Back to Repositories

Testing EXIF Orientation Parsing in Glide Image Library

This test suite validates EXIF orientation handling in Glide’s image processing pipeline, focusing on proper rotation of JPEG images. It ensures correct parsing of EXIF metadata across different image orientations and buffer handling scenarios.

Test Coverage Overview

The test suite provides comprehensive coverage of EXIF orientation parsing for both portrait and landscape images.

Key areas tested include:
  • Specific JPEG rotation issue (Issue 387)
  • 8 different orientation values for landscape images
  • 8 different orientation values for portrait images
  • Buffer pool handling with various sizes

Implementation Analysis

The testing approach uses JUnit with Robolectric for Android environment simulation. It implements systematic verification of image orientation parsing using DefaultImageHeaderParser and handles resource management through TestResourceUtil.

Testing patterns include:
  • Parameterized testing for orientation values 1-8
  • Resource cleanup in try-finally blocks
  • Memory management validation with ArrayPool

Technical Details

Testing infrastructure includes:
  • Robolectric test runner with SDK configuration
  • LruArrayPool for byte array management
  • DefaultImageHeaderParser for EXIF parsing
  • TestResourceUtil for test resource loading
  • JUnit assertions and Truth assertion framework

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Proper resource management and cleanup
  • Systematic test organization with @Before setup
  • Comprehensive edge case coverage
  • Efficient test resource utilization
  • Clear separation of test utilities and actual test cases

bumptech/glide

library/test/src/test/java/com/bumptech/glide/resize/load/ExifTest.java

            
package com.bumptech.glide.resize.load;

import static com.bumptech.glide.RobolectricConstants.ROBOLECTRIC_SDK;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;

import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool;
import com.bumptech.glide.load.engine.bitmap_recycle.LruArrayPool;
import com.bumptech.glide.load.resource.bitmap.DefaultImageHeaderParser;
import com.bumptech.glide.testutil.TestResourceUtil;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(sdk = ROBOLECTRIC_SDK)
public class ExifTest {

  private ArrayPool byteArrayPool;

  private InputStream open(String imageName) {
    return TestResourceUtil.openResource(getClass(), imageName);
  }

  private void assertOrientation(String filePrefix, int expectedOrientation) {
    InputStream is = null;
    try {
      is = open(filePrefix + "_" + expectedOrientation + ".jpg");
      assertEquals(
          new DefaultImageHeaderParser().getOrientation(is, byteArrayPool), expectedOrientation);
    } catch (IOException e) {
      throw new RuntimeException(e);
    } finally {
      if (is != null) {
        try {
          is.close();
        } catch (IOException e) {
          // Do nothing.
        }
      }
    }
  }

  @Before
  public void setUp() {
    byteArrayPool = new LruArrayPool();
  }

  @Test
  public void testIssue387() throws IOException {
    InputStream is = TestResourceUtil.openResource(getClass(), "issue387_rotated_jpeg.jpg");
    assertThat(new DefaultImageHeaderParser().getOrientation(is, byteArrayPool)).isEqualTo(6);
  }

  @Test
  public void testLandscape() throws IOException {
    for (int i = 1; i <= 8; i++) {
      assertOrientation("Landscape", i);
    }
  }

  @Test
  public void testPortrait() throws IOException {
    for (int i = 1; i <= 8; i++) {
      assertOrientation("Portrait", i);
    }
  }

  @Test
  public void testHandlesInexactSizesInByteArrayPools() {
    for (int i = 1; i <= 8; i++) {
      byteArrayPool.put(new byte[ArrayPool.STANDARD_BUFFER_SIZE_BYTES]);
      assertOrientation("Portrait", i);
    }
    for (int i = 1; i <= 8; i++) {
      byteArrayPool.put(new byte[ArrayPool.STANDARD_BUFFER_SIZE_BYTES]);
      assertOrientation("Landscape", i);
    }
  }
}