Back to Repositories

Testing OGG Packet Processing Implementation in SmartTube

This test suite validates the OggPacket class functionality in ExoPlayer’s OGG media extraction component. It ensures proper handling of OGG packet reading, page parsing, and stream processing with comprehensive coverage of different packet scenarios and edge cases.

Test Coverage Overview

The test suite provides extensive coverage of OGG packet parsing and handling:

  • Packet reading across multiple pages and empty pages
  • Zero-size packet termination handling
  • Continued packet processing across 2-4 pages
  • Discarding of partial packets at stream start
  • Zero-sized packet handling at stream end
  • Real file parsing validation

Implementation Analysis

The testing approach uses JUnit and AndroidJUnit4 frameworks with a systematic verification of OggPacket behaviors. It employs mock data generation and custom test utilities like FakeExtractorInput and OggTestData for controlled testing environments.

The implementation follows a thorough pattern of setting up test data, executing packet operations, and verifying packet contents and header metadata.

Technical Details

  • Testing Framework: JUnit with AndroidJUnit4 runner
  • Mock Utilities: FakeExtractorInput, OggTestData, TestUtil
  • Test Data: Combination of synthetic and real OGG file samples
  • Key Classes: OggPacket, ParsableByteArray
  • Test Setup: Random data generation for packet content

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Comprehensive edge case coverage
  • Isolated test methods for specific scenarios
  • Proper test setup and cleanup
  • Robust input data validation
  • Clear test method naming
  • Effective use of assertion utilities

yuliskov/smarttube

exoplayer-amzn-2.10.6/library/core/src/test/java/com/google/android/exoplayer2/extractor/ogg/OggPacketTest.java

            
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.android.exoplayer2.extractor.ogg;

import static com.google.common.truth.Truth.assertThat;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
import com.google.android.exoplayer2.testutil.OggTestData;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

/** Unit test for {@link OggPacket}. */
@RunWith(AndroidJUnit4.class)
public final class OggPacketTest {

  private static final String TEST_FILE = "ogg/bear.opus";

  private Random random;
  private OggPacket oggPacket;

  @Before
  public void setUp() throws Exception {
    random = new Random(0);
    oggPacket = new OggPacket();
  }

  @Test
  public void testReadPacketsWithEmptyPage() throws Exception {
    byte[] firstPacket = TestUtil.buildTestData(8, random);
    byte[] secondPacket = TestUtil.buildTestData(272, random);
    byte[] thirdPacket = TestUtil.buildTestData(256, random);
    byte[] fourthPacket = TestUtil.buildTestData(271, random);

    FakeExtractorInput input =
        OggTestData.createInput(
            TestUtil.joinByteArrays(
                // First page with a single packet.
                OggTestData.buildOggHeader(0x02, 0, 1000, 0x01),
                TestUtil.createByteArray(0x08), // Laces
                firstPacket,
                // Second page with a single packet.
                OggTestData.buildOggHeader(0x00, 16, 1001, 0x02),
                TestUtil.createByteArray(0xFF, 0x11), // Laces
                secondPacket,
                // Third page with zero packets.
                OggTestData.buildOggHeader(0x00, 16, 1002, 0x00),
                // Fourth page with two packets.
                OggTestData.buildOggHeader(0x04, 128, 1003, 0x04),
                TestUtil.createByteArray(0xFF, 0x01, 0xFF, 0x10), // Laces
                thirdPacket,
                fourthPacket),
            true);

    assertReadPacket(input, firstPacket);
    assertThat((oggPacket.getPageHeader().type & 0x02) == 0x02).isTrue();
    assertThat((oggPacket.getPageHeader().type & 0x04) == 0x04).isFalse();
    assertThat(oggPacket.getPageHeader().type).isEqualTo(0x02);
    assertThat(oggPacket.getPageHeader().headerSize).isEqualTo(27 + 1);
    assertThat(oggPacket.getPageHeader().bodySize).isEqualTo(8);
    assertThat(oggPacket.getPageHeader().revision).isEqualTo(0x00);
    assertThat(oggPacket.getPageHeader().pageSegmentCount).isEqualTo(1);
    assertThat(oggPacket.getPageHeader().pageSequenceNumber).isEqualTo(1000);
    assertThat(oggPacket.getPageHeader().streamSerialNumber).isEqualTo(4096);
    assertThat(oggPacket.getPageHeader().granulePosition).isEqualTo(0);

    assertReadPacket(input, secondPacket);
    assertThat((oggPacket.getPageHeader().type & 0x02) == 0x02).isFalse();
    assertThat((oggPacket.getPageHeader().type & 0x04) == 0x04).isFalse();
    assertThat(oggPacket.getPageHeader().type).isEqualTo(0);
    assertThat(oggPacket.getPageHeader().headerSize).isEqualTo(27 + 2);
    assertThat(oggPacket.getPageHeader().bodySize).isEqualTo(255 + 17);
    assertThat(oggPacket.getPageHeader().pageSegmentCount).isEqualTo(2);
    assertThat(oggPacket.getPageHeader().pageSequenceNumber).isEqualTo(1001);
    assertThat(oggPacket.getPageHeader().granulePosition).isEqualTo(16);

    assertReadPacket(input, thirdPacket);
    assertThat((oggPacket.getPageHeader().type & 0x02) == 0x02).isFalse();
    assertThat((oggPacket.getPageHeader().type & 0x04) == 0x04).isTrue();
    assertThat(oggPacket.getPageHeader().type).isEqualTo(4);
    assertThat(oggPacket.getPageHeader().headerSize).isEqualTo(27 + 4);
    assertThat(oggPacket.getPageHeader().bodySize).isEqualTo(255 + 1 + 255 + 16);
    assertThat(oggPacket.getPageHeader().pageSegmentCount).isEqualTo(4);
    // Page 1002 is empty, so current page is 1003.
    assertThat(oggPacket.getPageHeader().pageSequenceNumber).isEqualTo(1003);
    assertThat(oggPacket.getPageHeader().granulePosition).isEqualTo(128);

    assertReadPacket(input, fourthPacket);

    assertReadEof(input);
  }

  @Test
  public void testReadPacketWithZeroSizeTerminator() throws Exception {
    byte[] firstPacket = TestUtil.buildTestData(255, random);
    byte[] secondPacket = TestUtil.buildTestData(8, random);

    FakeExtractorInput input =
        OggTestData.createInput(
            TestUtil.joinByteArrays(
                OggTestData.buildOggHeader(0x06, 0, 1000, 0x04),
                TestUtil.createByteArray(0xFF, 0x00, 0x00, 0x08), // Laces.
                firstPacket,
                secondPacket),
            true);

    assertReadPacket(input, firstPacket);
    assertReadPacket(input, secondPacket);
    assertReadEof(input);
  }

  @Test
  public void testReadContinuedPacketOverTwoPages() throws Exception {
    byte[] firstPacket = TestUtil.buildTestData(518);

    FakeExtractorInput input =
        OggTestData.createInput(
            TestUtil.joinByteArrays(
                // First page.
                OggTestData.buildOggHeader(0x02, 0, 1000, 0x02),
                TestUtil.createByteArray(0xFF, 0xFF), // Laces.
                Arrays.copyOf(firstPacket, 510),
                // Second page (continued packet).
                OggTestData.buildOggHeader(0x05, 10, 1001, 0x01),
                TestUtil.createByteArray(0x08), // Laces.
                Arrays.copyOfRange(firstPacket, 510, 510 + 8)),
            true);

    assertReadPacket(input, firstPacket);
    assertThat((oggPacket.getPageHeader().type & 0x04) == 0x04).isTrue();
    assertThat((oggPacket.getPageHeader().type & 0x02) == 0x02).isFalse();
    assertThat(oggPacket.getPageHeader().pageSequenceNumber).isEqualTo(1001);

    assertReadEof(input);
  }

  @Test
  public void testReadContinuedPacketOverFourPages() throws Exception {
    byte[] firstPacket = TestUtil.buildTestData(1028);

    FakeExtractorInput input =
        OggTestData.createInput(
            TestUtil.joinByteArrays(
                // First page.
                OggTestData.buildOggHeader(0x02, 0, 1000, 0x02),
                TestUtil.createByteArray(0xFF, 0xFF), // Laces.
                Arrays.copyOf(firstPacket, 510),
                // Second page (continued packet).
                OggTestData.buildOggHeader(0x01, 10, 1001, 0x01),
                TestUtil.createByteArray(0xFF), // Laces.
                Arrays.copyOfRange(firstPacket, 510, 510 + 255),
                // Third page (continued packet).
                OggTestData.buildOggHeader(0x01, 10, 1002, 0x01),
                TestUtil.createByteArray(0xFF), // Laces.
                Arrays.copyOfRange(firstPacket, 510 + 255, 510 + 255 + 255),
                // Fourth page (continued packet).
                OggTestData.buildOggHeader(0x05, 10, 1003, 0x01),
                TestUtil.createByteArray(0x08), // Laces.
                Arrays.copyOfRange(firstPacket, 510 + 255 + 255, 510 + 255 + 255 + 8)),
            true);

    assertReadPacket(input, firstPacket);
    assertThat((oggPacket.getPageHeader().type & 0x04) == 0x04).isTrue();
    assertThat((oggPacket.getPageHeader().type & 0x02) == 0x02).isFalse();
    assertThat(oggPacket.getPageHeader().pageSequenceNumber).isEqualTo(1003);

    assertReadEof(input);
  }

  @Test
  public void testReadDiscardContinuedPacketAtStart() throws Exception {
    byte[] pageBody = TestUtil.buildTestData(256 + 8);

    FakeExtractorInput input =
        OggTestData.createInput(
            TestUtil.joinByteArrays(
                // Page with a continued packet at start.
                OggTestData.buildOggHeader(0x01, 10, 1001, 0x03),
                TestUtil.createByteArray(255, 1, 8), // Laces.
                pageBody),
            true);

    // Expect the first partial packet to be discarded.
    assertReadPacket(input, Arrays.copyOfRange(pageBody, 256, 256 + 8));
    assertReadEof(input);
  }

  @Test
  public void testReadZeroSizedPacketsAtEndOfStream() throws Exception {
    byte[] firstPacket = TestUtil.buildTestData(8, random);
    byte[] secondPacket = TestUtil.buildTestData(8, random);
    byte[] thirdPacket = TestUtil.buildTestData(8, random);

    FakeExtractorInput input =
        OggTestData.createInput(
            TestUtil.joinByteArrays(
                OggTestData.buildOggHeader(0x02, 0, 1000, 0x01),
                TestUtil.createByteArray(0x08), // Laces.
                firstPacket,
                OggTestData.buildOggHeader(0x04, 0, 1001, 0x03),
                TestUtil.createByteArray(0x08, 0x00, 0x00), // Laces.
                secondPacket,
                OggTestData.buildOggHeader(0x04, 0, 1002, 0x03),
                TestUtil.createByteArray(0x08, 0x00, 0x00), // Laces.
                thirdPacket),
            true);

    assertReadPacket(input, firstPacket);
    assertReadPacket(input, secondPacket);
    assertReadPacket(input, thirdPacket);
    assertReadEof(input);
  }

  @Test
  public void testParseRealFile() throws IOException, InterruptedException {
    byte[] data = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TEST_FILE);
    FakeExtractorInput input = new FakeExtractorInput.Builder().setData(data).build();
    int packetCounter = 0;
    while (readPacket(input)) {
      packetCounter++;
    }
    assertThat(packetCounter).isEqualTo(277);
  }

  private void assertReadPacket(FakeExtractorInput extractorInput, byte[] expected)
      throws IOException, InterruptedException {
    assertThat(readPacket(extractorInput)).isTrue();
    ParsableByteArray payload = oggPacket.getPayload();
    assertThat(Arrays.copyOf(payload.data, payload.limit())).isEqualTo(expected);
  }

  private void assertReadEof(FakeExtractorInput extractorInput)
      throws IOException, InterruptedException {
    assertThat(readPacket(extractorInput)).isFalse();
  }

  private boolean readPacket(FakeExtractorInput input) throws InterruptedException, IOException {
    while (true) {
      try {
        return oggPacket.populate(input);
      } catch (FakeExtractorInput.SimulatedIOException e) {
        // Ignore.
      }
    }
  }
}