function testCommonBehaviors(
      basicLines, basicRefs, updateLines, updateRefs, partialUpdateLines) {
    /**
     * Tests that an update will show the given references.
     *
     * @param {!Array<string>} firstLines The Representation contents for the
     *   first manifest.
     * @param {!Array<!shaka.media.SegmentReference>} firstReferences The media
     *   references for the first parse.
     * @param {!Array<string>} secondLines The Representation contents for the
     *   updated manifest.
     * @param {!Array<!shaka.media.SegmentReference>} secondReferences The
     *   media references for the updated manifest.
     */
    async function testBasicUpdate(
        firstLines, firstReferences, secondLines, secondReferences) {
      const firstManifest = makeSimpleLiveManifestText(firstLines, updateTime);
      const secondManifest =
          makeSimpleLiveManifestText(secondLines, updateTime);

      fakeNetEngine.setResponseText('dummy://foo', firstManifest);
      const manifest = await parser.start('dummy://foo', playerInterface);
      const stream = manifest.variants[0].video;
      await stream.createSegmentIndex();
      ManifestParser.verifySegmentIndex(stream, firstReferences);

      fakeNetEngine.setResponseText('dummy://foo', secondManifest);
      await updateManifest();
      ManifestParser.verifySegmentIndex(stream, secondReferences);
    }

    it('basic support', async () => {
      await testBasicUpdate(basicLines, basicRefs, updateLines, updateRefs);
    });

    it('new manifests don\'t need to include old references', async () => {
      await testBasicUpdate(
          basicLines, basicRefs, partialUpdateLines, updateRefs);
    });

    it('evicts old references for single-period live stream', async () => {
      const template = [
        '<MPD type="dynamic" minimumUpdatePeriod="PT%(updateTime)dS"',
        '    timeShiftBufferDepth="PT30S"',
        '    suggestedPresentationDelay="PT5S"',
        '    availabilityStartTime="1970-01-01T00:00:00Z">',
        '  <Period id="1">',
        '    <AdaptationSet mimeType="video/mp4">',
        '      <Representation id="3" bandwidth="500">',
        '        <BaseURL>http://example.com</BaseURL>',
        '%(contents)s',
        '      </Representation>',
        '    </AdaptationSet>',
        '  </Period>',
        '</MPD>',
      ].join('\n');
      const text = sprintf(
          template, {updateTime: updateTime, contents: basicLines.join('\n')});

      fakeNetEngine.setResponseText('dummy://foo', text);
      const baseTime = new Date(2015, 11, 30);
      Date.now = () => baseTime.getTime();
      const manifest = await parser.start('dummy://foo', playerInterface);

      expect(manifest).toBeTruthy();
      const stream = manifest.variants[0].video;
      expect(stream).toBeTruthy();

      await stream.createSegmentIndex();
      expect(stream.segmentIndex).toBeTruthy();
      const firstPosition = stream.segmentIndex.find(0);
      ManifestParser.verifySegmentIndex(stream, basicRefs);

      // The 30 second availability window is initially full in all cases
      // (SegmentTemplate+Timeline, etc.)  The first segment is always 10
      // seconds long in all of these cases.  So 11 seconds after the
      // manifest was parsed, the first segment should have fallen out of
      // the availability window.
      Date.now = () => baseTime.getTime() + (11 * 1000);
      await updateManifest();
      // The first reference should have been evicted.
      expect(stream.segmentIndex.find(0)).toBe(firstPosition + 1);
      ManifestParser.verifySegmentIndex(stream, basicRefs.slice(1));
    });

    it('evicts old references for multi-period live stream', async () => {
      const template = [
        '<MPD type="dynamic" minimumUpdatePeriod="PT%(updateTime)dS"',
        '    timeShiftBufferDepth="PT60S"',
        '    suggestedPresentationDelay="PT5S"',
        '    availabilityStartTime="1970-01-01T00:00:00Z">',
        '  <Period id="1">',
        '    <AdaptationSet mimeType="video/mp4">',
        '      <Representation id="3" bandwidth="500">',
        '        <BaseURL>http://example.com</BaseURL>',
        '%(contents)s',
        '      </Representation>',
        '    </AdaptationSet>',
        '  </Period>',
        '  <Period id="2" start="PT%(pStart)dS">',
        '    <AdaptationSet mimeType="video/mp4">',
        '      <Representation id="4" bandwidth="500">',
        '        <BaseURL>http://example.com</BaseURL>',
        '%(contents)s',
        '      </Representation>',
        '    </AdaptationSet>',
        '  </Period>',
        '</MPD>',
      ].join('\n');
      // Set the period start to the sum of the durations of the references
      // in the previous period.
      const durations = basicRefs.map((r) => {
        return r.endTime - r.startTime;
      });
      const pStart = durations.reduce((p, d) => p + d, 0);
      const args = {
        updateTime: updateTime,
        pStart: pStart,
        contents: basicLines.join('\n'),
      };
      const text = sprintf(template, args);

      fakeNetEngine.setResponseText('dummy://foo', text);
      Date.now = () => 0;
      const manifest = await parser.start('dummy://foo', playerInterface);

      /** @const {!Array<!shaka.media.SegmentReference>} */
      const period1Refs = cloneRefs(basicRefs);
      /** @const {!Array<!shaka.media.SegmentReference>} */
      const period2Refs = cloneRefs(basicRefs);
      for (const ref of period2Refs) {
        ref.timestampOffset = pStart;
        ref.startTime += pStart;
        ref.endTime += pStart;
        ref.trueEndTime += pStart;
      }
      /** @const {!Array<!shaka.media.SegmentReference>} */
      const allRefs = period1Refs.concat(period2Refs);

      const stream1 = manifest.variants[0].video;
      await stream1.createSegmentIndex();
      ManifestParser.verifySegmentIndex(stream1, allRefs);

      // The 60 second availability window is initially full in all cases
      // (SegmentTemplate+Timeline, etc.)  The first segment is always 10
      // seconds long in all of these cases.  So 11 seconds after the
      // manifest was parsed, the first segment should have fallen out of
      // the availability window.
      Date.now = () => 11 * 1000;
      await updateManifest();
      // The first reference should have been evicted.
      ManifestParser.verifySegmentIndex(stream1, allRefs.slice(1));

      // Same as above, but 1 period length later
      Date.now = () => (11 + pStart) * 1000;
      await updateManifest();
      ManifestParser.verifySegmentIndex(stream1, period2Refs.slice(1));
    });

    it('sets infinite duration for single-period live streams', async () => {
      const template = [
        '<MPD type="dynamic" minimumUpdatePeriod="PT%(updateTime)dS"',
        '    timeShiftBufferDepth="PT1S"',
        '    suggestedPresentationDelay="PT5S"',
        '    availabilityStartTime="1970-01-01T00:00:00Z">',
        '  <Period id="1">',
        '    <AdaptationSet mimeType="video/mp4">',
        '      <Representation id="3" bandwidth="500">',
        '        <BaseURL>http://example.com</BaseURL>',
        '%(contents)s',
        '      </Representation>',
        '    </AdaptationSet>',
        '  </Period>',
        '</MPD>',
      ].join('\n');
      const text = sprintf(
          template, {updateTime: updateTime, contents: basicLines.join('\n')});

      fakeNetEngine.setResponseText('dummy://foo', text);
      Date.now = () => 0;
      const manifest = await parser.start('dummy://foo', playerInterface);

      const timeline = manifest.presentationTimeline;
      expect(timeline.getDuration()).toBe(Infinity);
    });

    it('sets infinite duration for multi-period live streams', async () => {
      const template = [
        '<MPD type="dynamic" minimumUpdatePeriod="PT%(updateTime)dS"',
        '    timeShiftBufferDepth="PT1S"',
        '    suggestedPresentationDelay="PT5S"',
        '    availabilityStartTime="1970-01-01T00:00:00Z">',
        '  <Period id="1">',
        '    <AdaptationSet mimeType="video/mp4">',
        '      <Representation id="3" bandwidth="500">',
        '        <BaseURL>http://example.com</BaseURL>',
        '%(contents)s',
        '      </Representation>',
        '    </AdaptationSet>',
        '  </Period>',
        '  <Period id="2" start="PT60S">',
        '    <AdaptationSet mimeType="video/mp4">',
        '      <Representation id="4" bandwidth="500">',
        '        <BaseURL>http://example.com</BaseURL>',
        '%(contents)s',
        '      </Representation>',
        '    </AdaptationSet>',
        '  </Period>',
        '</MPD>',
      ].join('\n');
      const text = sprintf(
          template, {updateTime: updateTime, contents: basicLines.join('\n')});

      fakeNetEngine.setResponseText('dummy://foo', text);
      Date.now = () => 0;
      const manifest = await parser.start('dummy://foo', playerInterface);

      const timeline = manifest.presentationTimeline;
      expect(timeline.getDuration()).toBe(Infinity);
    });
  }
Creates tests that test the behavior common between SegmentList and
SegmentTemplate.

@param {!Array<string>} basicLines
@param {!Array<!shaka.media.SegmentReference>} basicRefs
@param {!Array<string>} updateLines
@param {!Array<!shaka.media.SegmentReference>} updateRefs
@param {!Array<string>} partialUpdateLines