From a2fba687d4d2dbb3b2db8866b054ecb0e42871b2 Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Wed, 17 Aug 2011 22:07:43 +0800 Subject: Initial code for Gallery2. fix: 5176434 Change-Id: I041e282b9c7b34ceb1db8b033be2b853bb3a992c --- .../com/android/gallery3d/anim/AnimationTest.java | 80 ++ .../android/gallery3d/common/BlobCacheTest.java | 738 ++++++++++ .../com/android/gallery3d/common/UtilsTest.java | 244 ++++ .../com/android/gallery3d/data/GalleryAppMock.java | 50 + .../com/android/gallery3d/data/GalleryAppStub.java | 47 + .../com/android/gallery3d/data/LocalDataTest.java | 461 ++++++ .../com/android/gallery3d/data/MediaSetTest.java | 63 + tests/src/com/android/gallery3d/data/MockItem.java | 43 + tests/src/com/android/gallery3d/data/MockSet.java | 88 ++ .../src/com/android/gallery3d/data/MockSource.java | 48 + tests/src/com/android/gallery3d/data/PathTest.java | 82 ++ .../com/android/gallery3d/data/RealDataTest.java | 110 ++ .../src/com/android/gallery3d/ui/GLCanvasMock.java | 68 + .../src/com/android/gallery3d/ui/GLCanvasStub.java | 79 ++ .../src/com/android/gallery3d/ui/GLCanvasTest.java | 778 ++++++++++ tests/src/com/android/gallery3d/ui/GLMock.java | 195 +++ tests/src/com/android/gallery3d/ui/GLRootMock.java | 37 + tests/src/com/android/gallery3d/ui/GLRootStub.java | 30 + tests/src/com/android/gallery3d/ui/GLStub.java | 1490 ++++++++++++++++++++ tests/src/com/android/gallery3d/ui/GLViewMock.java | 85 ++ tests/src/com/android/gallery3d/ui/GLViewTest.java | 424 ++++++ .../src/com/android/gallery3d/ui/PointerInfo.java | 222 +++ .../src/com/android/gallery3d/ui/TextureTest.java | 208 +++ .../com/android/gallery3d/util/IntArrayTest.java | 60 + 24 files changed, 5730 insertions(+) create mode 100644 tests/src/com/android/gallery3d/anim/AnimationTest.java create mode 100644 tests/src/com/android/gallery3d/common/BlobCacheTest.java create mode 100644 tests/src/com/android/gallery3d/common/UtilsTest.java create mode 100644 tests/src/com/android/gallery3d/data/GalleryAppMock.java create mode 100644 tests/src/com/android/gallery3d/data/GalleryAppStub.java create mode 100644 tests/src/com/android/gallery3d/data/LocalDataTest.java create mode 100644 tests/src/com/android/gallery3d/data/MediaSetTest.java create mode 100644 tests/src/com/android/gallery3d/data/MockItem.java create mode 100644 tests/src/com/android/gallery3d/data/MockSet.java create mode 100644 tests/src/com/android/gallery3d/data/MockSource.java create mode 100644 tests/src/com/android/gallery3d/data/PathTest.java create mode 100644 tests/src/com/android/gallery3d/data/RealDataTest.java create mode 100644 tests/src/com/android/gallery3d/ui/GLCanvasMock.java create mode 100644 tests/src/com/android/gallery3d/ui/GLCanvasStub.java create mode 100644 tests/src/com/android/gallery3d/ui/GLCanvasTest.java create mode 100644 tests/src/com/android/gallery3d/ui/GLMock.java create mode 100644 tests/src/com/android/gallery3d/ui/GLRootMock.java create mode 100644 tests/src/com/android/gallery3d/ui/GLRootStub.java create mode 100644 tests/src/com/android/gallery3d/ui/GLStub.java create mode 100644 tests/src/com/android/gallery3d/ui/GLViewMock.java create mode 100644 tests/src/com/android/gallery3d/ui/GLViewTest.java create mode 100644 tests/src/com/android/gallery3d/ui/PointerInfo.java create mode 100644 tests/src/com/android/gallery3d/ui/TextureTest.java create mode 100644 tests/src/com/android/gallery3d/util/IntArrayTest.java (limited to 'tests/src/com/android') diff --git a/tests/src/com/android/gallery3d/anim/AnimationTest.java b/tests/src/com/android/gallery3d/anim/AnimationTest.java new file mode 100644 index 000000000..c7d5daec7 --- /dev/null +++ b/tests/src/com/android/gallery3d/anim/AnimationTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.anim; + +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; +import android.view.animation.Interpolator; + +import junit.framework.TestCase; + +@SmallTest +public class AnimationTest extends TestCase { + private static final String TAG = "AnimationTest"; + + public void testFloatAnimation() { + FloatAnimation a = new FloatAnimation(0f, 1f, 10); // value 0 to 1.0, duration 10 + a.start(); // start animation + assertTrue(a.isActive()); // should be active now + a.calculate(0); // set start time = 0 + assertTrue(a.get() == 0); // start value should be 0 + a.calculate(1); // calculate value for time 1 + assertFloatEq(a.get(), 0.1f); + a.calculate(5); // calculate value for time 5 + assertTrue(a.get() == 0.5);// + a.calculate(9); // calculate value for time 9 + assertFloatEq(a.get(), 0.9f); + a.calculate(10); // calculate value for time 10 + assertTrue(!a.isActive()); // should be inactive now + assertTrue(a.get() == 1.0);// + a.start(); // restart + assertTrue(a.isActive()); // should be active now + a.calculate(5); // set start time = 5 + assertTrue(a.get() == 0); // start value should be 0 + a.calculate(5+9); // calculate for time 5+9 + assertFloatEq(a.get(), 0.9f); + } + + private static class MyInterpolator implements Interpolator { + public float getInterpolation(float input) { + return 4f * (input - 0.5f); // maps [0,1] to [-2,2] + } + } + + public void testInterpolator() { + FloatAnimation a = new FloatAnimation(0f, 1f, 10); // value 0 to 1.0, duration 10 + a.setInterpolator(new MyInterpolator()); + a.start(); // start animation + a.calculate(0); // set start time = 0 + assertTrue(a.get() == -2); // start value should be -2 + a.calculate(1); // calculate value for time 1 + assertFloatEq(a.get(), -1.6f); + a.calculate(5); // calculate value for time 5 + assertTrue(a.get() == 0); // + a.calculate(9); // calculate value for time 9 + assertFloatEq(a.get(), 1.6f); + a.calculate(10); // calculate value for time 10 + assertTrue(a.get() == 2); // + } + + public static void assertFloatEq(float expected, float actual) { + if (Math.abs(actual - expected) > 1e-6) { + Log.v(TAG, "expected: " + expected + ", actual: " + actual); + fail(); + } + } +} diff --git a/tests/src/com/android/gallery3d/common/BlobCacheTest.java b/tests/src/com/android/gallery3d/common/BlobCacheTest.java new file mode 100644 index 000000000..2a911c45b --- /dev/null +++ b/tests/src/com/android/gallery3d/common/BlobCacheTest.java @@ -0,0 +1,738 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.common; + +import com.android.gallery3d.common.BlobCache; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Random; + +public class BlobCacheTest extends AndroidTestCase { + private static final String TAG = "BlobCacheTest"; + + @SmallTest + public void testReadIntLong() { + byte[] buf = new byte[9]; + assertEquals(0, BlobCache.readInt(buf, 0)); + assertEquals(0, BlobCache.readLong(buf, 0)); + buf[0] = 1; + assertEquals(1, BlobCache.readInt(buf, 0)); + assertEquals(1, BlobCache.readLong(buf, 0)); + buf[3] = 0x7f; + assertEquals(0x7f000001, BlobCache.readInt(buf, 0)); + assertEquals(0x7f000001, BlobCache.readLong(buf, 0)); + assertEquals(0x007f0000, BlobCache.readInt(buf, 1)); + assertEquals(0x007f0000, BlobCache.readLong(buf, 1)); + buf[3] = (byte) 0x80; + buf[7] = (byte) 0xA0; + buf[0] = 0; + assertEquals(0x80000000, BlobCache.readInt(buf, 0)); + assertEquals(0xA000000080000000L, BlobCache.readLong(buf, 0)); + for (int i = 0; i < 8; i++) { + buf[i] = (byte) (0x11 * (i+8)); + } + assertEquals(0xbbaa9988, BlobCache.readInt(buf, 0)); + assertEquals(0xffeeddccbbaa9988L, BlobCache.readLong(buf, 0)); + buf[8] = 0x33; + assertEquals(0x33ffeeddccbbaa99L, BlobCache.readLong(buf, 1)); + } + + @SmallTest + public void testWriteIntLong() { + byte[] buf = new byte[8]; + BlobCache.writeInt(buf, 0, 0x12345678); + assertEquals(0x78, buf[0]); + assertEquals(0x56, buf[1]); + assertEquals(0x34, buf[2]); + assertEquals(0x12, buf[3]); + assertEquals(0x00, buf[4]); + BlobCache.writeLong(buf, 0, 0xffeeddccbbaa9988L); + for (int i = 0; i < 8; i++) { + assertEquals((byte) (0x11 * (i+8)), buf[i]); + } + } + + @MediumTest + public void testChecksum() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true); + byte[] buf = new byte[0]; + assertEquals(0x1, bc.checkSum(buf)); + buf = new byte[1]; + assertEquals(0x10001, bc.checkSum(buf)); + buf[0] = 0x47; + assertEquals(0x480048, bc.checkSum(buf)); + buf = new byte[3]; + buf[0] = 0x10; + buf[1] = 0x30; + buf[2] = 0x01; + assertEquals(0x940042, bc.checkSum(buf)); + assertEquals(0x310031, bc.checkSum(buf, 1, 1)); + assertEquals(0x1, bc.checkSum(buf, 1, 0)); + assertEquals(0x630032, bc.checkSum(buf, 1, 2)); + buf = new byte[1024]; + for (int i = 0; i < buf.length; i++) { + buf[i] = (byte)(i*i); + } + assertEquals(0x3574a610, bc.checkSum(buf)); + bc.close(); + } + + private static final int HEADER_SIZE = 32; + private static final int DATA_HEADER_SIZE = 4; + private static final int BLOB_HEADER_SIZE = 20; + + private static final String TEST_FILE_NAME = "/sdcard/btest"; + private static final int MAX_ENTRIES = 100; + private static final int MAX_BYTES = 1000; + private static final int INDEX_SIZE = HEADER_SIZE + MAX_ENTRIES * 12 * 2; + private static final long KEY_0 = 0x1122334455667788L; + private static final long KEY_1 = 0x1122334455667789L; + private static final long KEY_2 = 0x112233445566778AL; + private static byte[] DATA_0 = new byte[10]; + private static byte[] DATA_1 = new byte[10]; + + @MediumTest + public void testBasic() throws IOException { + String name = TEST_FILE_NAME; + BlobCache bc; + File idxFile = new File(name + ".idx"); + File data0File = new File(name + ".0"); + File data1File = new File(name + ".1"); + + // Create a brand new cache. + bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, true); + bc.close(); + + // Make sure the initial state is correct. + assertTrue(idxFile.exists()); + assertTrue(data0File.exists()); + assertTrue(data1File.exists()); + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE, data0File.length()); + assertEquals(DATA_HEADER_SIZE, data1File.length()); + assertEquals(0, bc.getActiveCount()); + + // Re-open it. + bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, false); + assertNull(bc.lookup(KEY_0)); + + // insert one blob + genData(DATA_0, 1); + bc.insert(KEY_0, DATA_0); + assertSameData(DATA_0, bc.lookup(KEY_0)); + assertEquals(1, bc.getActiveCount()); + bc.close(); + + // Make sure the file size is right. + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + BLOB_HEADER_SIZE + DATA_0.length, + data0File.length()); + assertEquals(DATA_HEADER_SIZE, data1File.length()); + + // Re-open it and make sure we can get the old data + bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, false); + assertSameData(DATA_0, bc.lookup(KEY_0)); + + // insert with the same key (but using a different blob) + genData(DATA_0, 2); + bc.insert(KEY_0, DATA_0); + assertSameData(DATA_0, bc.lookup(KEY_0)); + assertEquals(1, bc.getActiveCount()); + bc.close(); + + // Make sure the file size is right. + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + 2 * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE, data1File.length()); + + // Re-open it and make sure we can get the old data + bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, false); + assertSameData(DATA_0, bc.lookup(KEY_0)); + + // insert another key and make sure we can get both key. + assertNull(bc.lookup(KEY_1)); + genData(DATA_1, 3); + bc.insert(KEY_1, DATA_1); + assertSameData(DATA_0, bc.lookup(KEY_0)); + assertSameData(DATA_1, bc.lookup(KEY_1)); + assertEquals(2, bc.getActiveCount()); + bc.close(); + + // Make sure the file size is right. + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + 3 * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE, data1File.length()); + + // Re-open it and make sure we can get the old data + bc = new BlobCache(name, 100, 1000, false); + assertSameData(DATA_0, bc.lookup(KEY_0)); + assertSameData(DATA_1, bc.lookup(KEY_1)); + assertEquals(2, bc.getActiveCount()); + bc.close(); + } + + @MediumTest + public void testNegativeKey() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true); + + // insert one blob + genData(DATA_0, 1); + bc.insert(-123, DATA_0); + assertSameData(DATA_0, bc.lookup(-123)); + bc.close(); + } + + @MediumTest + public void testEmptyBlob() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true); + + byte[] data = new byte[0]; + bc.insert(123, data); + assertSameData(data, bc.lookup(123)); + bc.close(); + } + + @MediumTest + public void testLookupRequest() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true); + + // insert one blob + genData(DATA_0, 1); + bc.insert(1, DATA_0); + assertSameData(DATA_0, bc.lookup(1)); + + // the same size buffer + byte[] buf = new byte[DATA_0.length]; + BlobCache.LookupRequest req = new BlobCache.LookupRequest(); + req.key = 1; + req.buffer = buf; + assertTrue(bc.lookup(req)); + assertEquals(1, req.key); + assertSame(buf, req.buffer); + assertEquals(DATA_0.length, req.length); + + // larger buffer + buf = new byte[DATA_0.length + 22]; + req = new BlobCache.LookupRequest(); + req.key = 1; + req.buffer = buf; + assertTrue(bc.lookup(req)); + assertEquals(1, req.key); + assertSame(buf, req.buffer); + assertEquals(DATA_0.length, req.length); + + // smaller buffer + buf = new byte[DATA_0.length - 1]; + req = new BlobCache.LookupRequest(); + req.key = 1; + req.buffer = buf; + assertTrue(bc.lookup(req)); + assertEquals(1, req.key); + assertNotSame(buf, req.buffer); + assertEquals(DATA_0.length, req.length); + assertSameData(DATA_0, req.buffer, DATA_0.length); + + // null buffer + req = new BlobCache.LookupRequest(); + req.key = 1; + req.buffer = null; + assertTrue(bc.lookup(req)); + assertEquals(1, req.key); + assertNotNull(req.buffer); + assertEquals(DATA_0.length, req.length); + assertSameData(DATA_0, req.buffer, DATA_0.length); + + bc.close(); + } + + @MediumTest + public void testKeyCollision() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true); + + for (int i = 0; i < MAX_ENTRIES / 2; i++) { + genData(DATA_0, i); + long key = KEY_1 + i * MAX_ENTRIES; + bc.insert(key, DATA_0); + } + + for (int i = 0; i < MAX_ENTRIES / 2; i++) { + genData(DATA_0, i); + long key = KEY_1 + i * MAX_ENTRIES; + assertSameData(DATA_0, bc.lookup(key)); + } + bc.close(); + } + + @MediumTest + public void testRegionFlip() throws IOException { + String name = TEST_FILE_NAME; + BlobCache bc; + File idxFile = new File(name + ".idx"); + File data0File = new File(name + ".0"); + File data1File = new File(name + ".1"); + + // Create a brand new cache. + bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, true); + + // This is the number of blobs fits into a region. + int maxFit = (MAX_BYTES - DATA_HEADER_SIZE) / + (BLOB_HEADER_SIZE + DATA_0.length); + + for (int k = 0; k < maxFit; k++) { + genData(DATA_0, k); + bc.insert(k, DATA_0); + } + assertEquals(maxFit, bc.getActiveCount()); + + // Make sure the file size is right. + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE, data1File.length()); + + // Now insert another one and let it flip. + genData(DATA_0, 777); + bc.insert(KEY_1, DATA_0); + assertEquals(1, bc.getActiveCount()); + + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE + 1 * (BLOB_HEADER_SIZE + DATA_0.length), + data1File.length()); + + // Make sure we can find the new data + assertSameData(DATA_0, bc.lookup(KEY_1)); + + // Now find an old blob + int old = maxFit / 2; + genData(DATA_0, old); + assertSameData(DATA_0, bc.lookup(old)); + assertEquals(2, bc.getActiveCount()); + + // Observed data is copied. + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE + 2 * (BLOB_HEADER_SIZE + DATA_0.length), + data1File.length()); + + // Now copy everything over (except we should have no space for the last one) + assertTrue(old < maxFit - 1); + for (int k = 0; k < maxFit; k++) { + genData(DATA_0, k); + assertSameData(DATA_0, bc.lookup(k)); + } + assertEquals(maxFit, bc.getActiveCount()); + + // Now both file should be full. + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data1File.length()); + + // Now insert one to make it flip. + genData(DATA_0, 888); + bc.insert(KEY_2, DATA_0); + assertEquals(1, bc.getActiveCount()); + + // Check the size after the second flip. + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + 1 * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data1File.length()); + + // Now the last key should be gone. + assertNull(bc.lookup(maxFit - 1)); + + // But others should remain + for (int k = 0; k < maxFit - 1; k++) { + genData(DATA_0, k); + assertSameData(DATA_0, bc.lookup(k)); + } + + assertEquals(maxFit, bc.getActiveCount()); + genData(DATA_0, 777); + assertSameData(DATA_0, bc.lookup(KEY_1)); + genData(DATA_0, 888); + assertSameData(DATA_0, bc.lookup(KEY_2)); + assertEquals(maxFit, bc.getActiveCount()); + + // Now two files should be full. + assertEquals(INDEX_SIZE, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data1File.length()); + + bc.close(); + } + + @MediumTest + public void testEntryLimit() throws IOException { + String name = TEST_FILE_NAME; + BlobCache bc; + File idxFile = new File(name + ".idx"); + File data0File = new File(name + ".0"); + File data1File = new File(name + ".1"); + int maxEntries = 10; + int maxFit = maxEntries / 2; + int indexSize = HEADER_SIZE + maxEntries * 12 * 2; + + // Create a brand new cache with a small entry limit. + bc = new BlobCache(name, maxEntries, MAX_BYTES, true); + + // Fill to just before flipping + for (int i = 0; i < maxFit; i++) { + genData(DATA_0, i); + bc.insert(i, DATA_0); + } + assertEquals(maxFit, bc.getActiveCount()); + + // Check the file size. + assertEquals(indexSize, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE, data1File.length()); + + // Insert one and make it flip + genData(DATA_0, 777); + bc.insert(777, DATA_0); + assertEquals(1, bc.getActiveCount()); + + // Check the file size. + assertEquals(indexSize, idxFile.length()); + assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length), + data0File.length()); + assertEquals(DATA_HEADER_SIZE + 1 * (BLOB_HEADER_SIZE + DATA_0.length), + data1File.length()); + bc.close(); + } + + @LargeTest + public void testDataIntegrity() throws IOException { + String name = TEST_FILE_NAME; + File idxFile = new File(name + ".idx"); + File data0File = new File(name + ".0"); + File data1File = new File(name + ".1"); + RandomAccessFile f; + + Log.v(TAG, "It should be readable if the content is not changed."); + prepareNewCache(); + f = new RandomAccessFile(data0File, "rw"); + f.seek(1); + byte b = f.readByte(); + f.seek(1); + f.write(b); + f.close(); + assertReadable(); + + Log.v(TAG, "Change the data file magic field"); + prepareNewCache(); + f = new RandomAccessFile(data0File, "rw"); + f.seek(1); + f.write(0xFF); + f.close(); + assertUnreadable(); + + prepareNewCache(); + f = new RandomAccessFile(data1File, "rw"); + f.write(0xFF); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the blob key"); + prepareNewCache(); + f = new RandomAccessFile(data0File, "rw"); + f.seek(4); + f.write(0x00); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the blob checksum"); + prepareNewCache(); + f = new RandomAccessFile(data0File, "rw"); + f.seek(4 + 8); + f.write(0x00); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the blob offset"); + prepareNewCache(); + f = new RandomAccessFile(data0File, "rw"); + f.seek(4 + 12); + f.write(0x20); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the blob length: some other value"); + prepareNewCache(); + f = new RandomAccessFile(data0File, "rw"); + f.seek(4 + 16); + f.write(0x20); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the blob length: -1"); + prepareNewCache(); + f = new RandomAccessFile(data0File, "rw"); + f.seek(4 + 16); + f.writeInt(0xFFFFFFFF); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the blob length: big value"); + prepareNewCache(); + f = new RandomAccessFile(data0File, "rw"); + f.seek(4 + 16); + f.writeInt(0xFFFFFF00); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the blob content"); + prepareNewCache(); + f = new RandomAccessFile(data0File, "rw"); + f.seek(4 + 20); + f.write(0x01); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the index magic"); + prepareNewCache(); + f = new RandomAccessFile(idxFile, "rw"); + f.seek(1); + f.write(0x00); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the active region"); + prepareNewCache(); + f = new RandomAccessFile(idxFile, "rw"); + f.seek(12); + f.write(0x01); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the reserved data"); + prepareNewCache(); + f = new RandomAccessFile(idxFile, "rw"); + f.seek(24); + f.write(0x01); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the checksum"); + prepareNewCache(); + f = new RandomAccessFile(idxFile, "rw"); + f.seek(29); + f.write(0x00); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the key"); + prepareNewCache(); + f = new RandomAccessFile(idxFile, "rw"); + f.seek(32 + 12 * (KEY_1 % MAX_ENTRIES)); + f.write(0x00); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the offset"); + prepareNewCache(); + f = new RandomAccessFile(idxFile, "rw"); + f.seek(32 + 12 * (KEY_1 % MAX_ENTRIES) + 8); + f.write(0x05); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Change the offset"); + prepareNewCache(); + f = new RandomAccessFile(idxFile, "rw"); + f.seek(32 + 12 * (KEY_1 % MAX_ENTRIES) + 8 + 3); + f.write(0xFF); + f.close(); + assertUnreadable(); + + Log.v(TAG, "Garbage index"); + prepareNewCache(); + f = new RandomAccessFile(idxFile, "rw"); + int n = (int) idxFile.length(); + f.seek(32); + byte[] garbage = new byte[1024]; + for (int i = 0; i < garbage.length; i++) { + garbage[i] = (byte) 0x80; + } + int i = 32; + while (i < n) { + int todo = Math.min(garbage.length, n - i); + f.write(garbage, 0, todo); + i += todo; + } + f.close(); + assertUnreadable(); + } + + // Create a brand new cache and put one entry into it. + private void prepareNewCache() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true); + genData(DATA_0, 777); + bc.insert(KEY_1, DATA_0); + bc.close(); + } + + private void assertReadable() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, false); + genData(DATA_0, 777); + assertSameData(DATA_0, bc.lookup(KEY_1)); + bc.close(); + } + + private void assertUnreadable() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, false); + genData(DATA_0, 777); + assertNull(bc.lookup(KEY_1)); + bc.close(); + } + + @LargeTest + public void testRandomSize() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true); + + // Random size test + Random rand = new Random(0); + for (int i = 0; i < 100; i++) { + byte[] data = new byte[rand.nextInt(MAX_BYTES*12/10)]; + try { + bc.insert(rand.nextLong(), data); + if (data.length > MAX_BYTES - 4 - 20) fail(); + } catch (RuntimeException ex) { + if (data.length <= MAX_BYTES - 4 - 20) fail(); + } + } + + bc.close(); + } + + @LargeTest + public void testBandwidth() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, 1000, 10000000, true); + + // Write + int count = 0; + byte[] data = new byte[20000]; + long t0 = System.nanoTime(); + for (int i = 0; i < 1000; i++) { + bc.insert(i, data); + count += data.length; + } + bc.syncAll(); + float delta = (System.nanoTime() - t0) * 1e-3f; + Log.v(TAG, "write bandwidth = " + (count / delta) + " M/s"); + + // Copy over + BlobCache.LookupRequest req = new BlobCache.LookupRequest(); + count = 0; + t0 = System.nanoTime(); + for (int i = 0; i < 1000; i++) { + req.key = i; + req.buffer = data; + if (bc.lookup(req)) { + count += req.length; + } + } + bc.syncAll(); + delta = (System.nanoTime() - t0) * 1e-3f; + Log.v(TAG, "copy over bandwidth = " + (count / delta) + " M/s"); + + // Read + count = 0; + t0 = System.nanoTime(); + for (int i = 0; i < 1000; i++) { + req.key = i; + req.buffer = data; + if (bc.lookup(req)) { + count += req.length; + } + } + bc.syncAll(); + delta = (System.nanoTime() - t0) * 1e-3f; + Log.v(TAG, "read bandwidth = " + (count / delta) + " M/s"); + + bc.close(); + } + + @LargeTest + public void testSmallSize() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, 40, true); + + // Small size test + Random rand = new Random(0); + for (int i = 0; i < 100; i++) { + byte[] data = new byte[rand.nextInt(3)]; + bc.insert(rand.nextLong(), data); + } + + bc.close(); + } + + @LargeTest + public void testManyEntries() throws IOException { + BlobCache bc = new BlobCache(TEST_FILE_NAME, 1, MAX_BYTES, true); + + // Many entries test + Random rand = new Random(0); + for (int i = 0; i < 100; i++) { + byte[] data = new byte[rand.nextInt(10)]; + } + + bc.close(); + } + + private void genData(byte[] data, int seed) { + for(int i = 0; i < data.length; i++) { + data[i] = (byte) (seed * i); + } + } + + private void assertSameData(byte[] data1, byte[] data2) { + if (data1 == null && data2 == null) return; + if (data1 == null || data2 == null) fail(); + if (data1.length != data2.length) fail(); + for (int i = 0; i < data1.length; i++) { + if (data1[i] != data2[i]) fail(); + } + } + + private void assertSameData(byte[] data1, byte[] data2, int n) { + if (data1 == null || data2 == null) fail(); + for (int i = 0; i < n; i++) { + if (data1[i] != data2[i]) fail(); + } + } +} diff --git a/tests/src/com/android/gallery3d/common/UtilsTest.java b/tests/src/com/android/gallery3d/common/UtilsTest.java new file mode 100644 index 000000000..b3552444b --- /dev/null +++ b/tests/src/com/android/gallery3d/common/UtilsTest.java @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.common; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +public class UtilsTest extends AndroidTestCase { + private static final String TAG = "UtilsTest"; + + private static final int [] testData = new int [] { + /* outWidth, outHeight, minSideLength, maxNumOfPixels, sample size */ + 1, 1, BitmapUtils.UNCONSTRAINED, BitmapUtils.UNCONSTRAINED, 1, + 1, 1, 1, 1, 1, + 100, 100, 100, 10000, 1, + 100, 100, 100, 2500, 2, + 99, 66, 33, 10000, 2, + 66, 99, 33, 10000, 2, + 99, 66, 34, 10000, 1, + 99, 66, 22, 10000, 4, + 99, 66, 16, 10000, 4, + + 10000, 10000, 20000, 1000000, 16, + + 100, 100, 100, 10000, 1, // 1 + 100, 100, 50, 10000, 2, // 2 + 100, 100, 30, 10000, 4, // 3->4 + 100, 100, 22, 10000, 4, // 4 + 100, 100, 20, 10000, 8, // 5->8 + 100, 100, 11, 10000, 16, // 9->16 + 100, 100, 5, 10000, 24, // 20->24 + 100, 100, 2, 10000, 56, // 50->56 + + 100, 100, 100, 10000 - 1, 2, // a bit less than 1 + 100, 100, 100, 10000 / (2 * 2) - 1, 4, // a bit less than 2 + 100, 100, 100, 10000 / (3 * 3) - 1, 4, // a bit less than 3 + 100, 100, 100, 10000 / (4 * 4) - 1, 8, // a bit less than 4 + 100, 100, 100, 10000 / (8 * 8) - 1, 16, // a bit less than 8 + 100, 100, 100, 10000 / (16 * 16) - 1, 24, // a bit less than 16 + 100, 100, 100, 10000 / (24 * 24) - 1, 32, // a bit less than 24 + 100, 100, 100, 10000 / (32 * 32) - 1, 40, // a bit less than 32 + + 640, 480, 480, BitmapUtils.UNCONSTRAINED, 1, // 1 + 640, 480, 240, BitmapUtils.UNCONSTRAINED, 2, // 2 + 640, 480, 160, BitmapUtils.UNCONSTRAINED, 4, // 3->4 + 640, 480, 120, BitmapUtils.UNCONSTRAINED, 4, // 4 + 640, 480, 96, BitmapUtils.UNCONSTRAINED, 8, // 5->8 + 640, 480, 80, BitmapUtils.UNCONSTRAINED, 8, // 6->8 + 640, 480, 60, BitmapUtils.UNCONSTRAINED, 8, // 8 + 640, 480, 48, BitmapUtils.UNCONSTRAINED, 16, // 10->16 + 640, 480, 40, BitmapUtils.UNCONSTRAINED, 16, // 12->16 + 640, 480, 30, BitmapUtils.UNCONSTRAINED, 16, // 16 + 640, 480, 24, BitmapUtils.UNCONSTRAINED, 24, // 20->24 + 640, 480, 20, BitmapUtils.UNCONSTRAINED, 24, // 24 + 640, 480, 16, BitmapUtils.UNCONSTRAINED, 32, // 30->32 + 640, 480, 12, BitmapUtils.UNCONSTRAINED, 40, // 40 + 640, 480, 10, BitmapUtils.UNCONSTRAINED, 48, // 48 + 640, 480, 8, BitmapUtils.UNCONSTRAINED, 64, // 60->64 + 640, 480, 6, BitmapUtils.UNCONSTRAINED, 80, // 80 + 640, 480, 4, BitmapUtils.UNCONSTRAINED, 120, // 120 + 640, 480, 3, BitmapUtils.UNCONSTRAINED, 160, // 160 + 640, 480, 2, BitmapUtils.UNCONSTRAINED, 240, // 240 + 640, 480, 1, BitmapUtils.UNCONSTRAINED, 480, // 480 + + 640, 480, BitmapUtils.UNCONSTRAINED, BitmapUtils.UNCONSTRAINED, 1, + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480, 1, // 1 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 - 1, 2, // a bit less than 1 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 4, 2, // 2 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 4 - 1, 4, // a bit less than 2 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 9, 4, // 3 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 9 - 1, 4, // a bit less than 3 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 16, 4, // 4 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 16 - 1, 8, // a bit less than 4 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 64, 8, // 8 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 64 - 1, 16, // a bit less than 8 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 256, 16, // 16 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 256 - 1, 24, // a bit less than 16 + 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / (24 * 24) - 1, 32, // a bit less than 24 + }; + + @SmallTest + public void testComputeSampleSize() { + + for (int i = 0; i < testData.length; i += 5) { + int w = testData[i]; + int h = testData[i + 1]; + int minSide = testData[i + 2]; + int maxPixels = testData[i + 3]; + int sampleSize = testData[i + 4]; + int result = BitmapUtils.computeSampleSize(w, h, minSide, maxPixels); + if (result != sampleSize) { + Log.v(TAG, w + "x" + h + ", minSide = " + minSide + ", maxPixels = " + + maxPixels + ", sampleSize = " + sampleSize + ", result = " + + result); + } + assertTrue(sampleSize == result); + } + } + + public void testAssert() { + // This should not throw an exception. + Utils.assertTrue(true); + + // This should throw an exception. + try { + Utils.assertTrue(false); + fail(); + } catch (AssertionError ex) { + // expected. + } + } + + public void testCheckNotNull() { + // These should not throw an expection. + Utils.checkNotNull(new Object()); + Utils.checkNotNull(0); + Utils.checkNotNull(""); + + // This should throw an expection. + try { + Utils.checkNotNull(null); + fail(); + } catch (NullPointerException ex) { + // expected. + } + } + + public void testEquals() { + Object a = new Object(); + Object b = new Object(); + + assertTrue(Utils.equals(null, null)); + assertTrue(Utils.equals(a, a)); + assertFalse(Utils.equals(null, a)); + assertFalse(Utils.equals(a, null)); + assertFalse(Utils.equals(a, b)); + } + + public void testIsPowerOf2() { + for (int i = 0; i < 31; i++) { + int v = (1 << i); + assertTrue(Utils.isPowerOf2(v)); + } + + int[] f = new int[] {3, 5, 6, 7, 9, 10, 65535, Integer.MAX_VALUE - 1, + Integer.MAX_VALUE }; + for (int v : f) { + assertFalse(Utils.isPowerOf2(v)); + } + + int[] e = new int[] {0, -1, -2, -4, -65536, Integer.MIN_VALUE + 1, + Integer.MIN_VALUE }; + for (int v : e) { + try { + Utils.isPowerOf2(v); + fail(); + } catch (IllegalArgumentException ex) { + // expected. + } + } + } + + public void testNextPowerOf2() { + int[] q = new int[] {1, 2, 3, 4, 5, 6, 10, 65535, (1 << 30) - 1, (1 << 30)}; + int[] a = new int[] {1, 2, 4, 4, 8, 8, 16, 65536, (1 << 30) , (1 << 30)}; + + for (int i = 0; i < q.length; i++) { + assertEquals(a[i], Utils.nextPowerOf2(q[i])); + } + + int[] e = new int[] {0, -1, -2, -4, -65536, (1 << 30) + 1, Integer.MAX_VALUE}; + + for (int v : e) { + try { + Utils.nextPowerOf2(v); + fail(); + } catch (IllegalArgumentException ex) { + // expected. + } + } + } + + public void testDistance() { + assertFloatEq(0f, Utils.distance(0, 0, 0, 0)); + assertFloatEq(1f, Utils.distance(0, 1, 0, 0)); + assertFloatEq(1f, Utils.distance(0, 0, 0, 1)); + assertFloatEq(2f, Utils.distance(1, 2, 3, 2)); + assertFloatEq(5f, Utils.distance(1, 2, 1 + 3, 2 + 4)); + assertFloatEq(5f, Utils.distance(1, 2, 1 + 3, 2 + 4)); + assertFloatEq(Float.MAX_VALUE, Utils.distance(Float.MAX_VALUE, 0, 0, 0)); + } + + public void testClamp() { + assertEquals(1000, Utils.clamp(300, 1000, 2000)); + assertEquals(1300, Utils.clamp(1300, 1000, 2000)); + assertEquals(2000, Utils.clamp(2300, 1000, 2000)); + + assertEquals(0.125f, Utils.clamp(0.1f, 0.125f, 0.5f)); + assertEquals(0.25f, Utils.clamp(0.25f, 0.125f, 0.5f)); + assertEquals(0.5f, Utils.clamp(0.9f, 0.125f, 0.5f)); + } + + public void testIsOpaque() { + assertTrue(Utils.isOpaque(0xFF000000)); + assertTrue(Utils.isOpaque(0xFFFFFFFF)); + assertTrue(Utils.isOpaque(0xFF123456)); + + assertFalse(Utils.isOpaque(0xFEFFFFFF)); + assertFalse(Utils.isOpaque(0x8FFFFFFF)); + assertFalse(Utils.isOpaque(0x00FF0000)); + assertFalse(Utils.isOpaque(0x5500FF00)); + assertFalse(Utils.isOpaque(0xAA0000FF)); + } + + public static void testSwap() { + Integer[] a = {1, 2, 3}; + Utils.swap(a, 0, 2); + assertEquals(a[0].intValue(), 3); + assertEquals(a[1].intValue(), 2); + assertEquals(a[2].intValue(), 1); + } + + public static void assertFloatEq(float expected, float actual) { + if (Math.abs(actual - expected) > 1e-6) { + Log.v(TAG, "expected: " + expected + ", actual: " + actual); + fail(); + } + } +} diff --git a/tests/src/com/android/gallery3d/data/GalleryAppMock.java b/tests/src/com/android/gallery3d/data/GalleryAppMock.java new file mode 100644 index 000000000..bbc569238 --- /dev/null +++ b/tests/src/com/android/gallery3d/data/GalleryAppMock.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.data; + +import android.content.ContentResolver; +import android.content.Context; +import android.os.Looper; + +import com.android.gallery3d.ui.GLRoot; +import com.android.gallery3d.ui.GLRootStub; + +class GalleryAppMock extends GalleryAppStub { + GLRoot mGLRoot = new GLRootStub(); + DataManager mDataManager = new DataManager(this); + ContentResolver mResolver; + Context mContext; + Looper mMainLooper; + + GalleryAppMock(Context context, + ContentResolver resolver, Looper mainLooper) { + mContext = context; + mResolver = resolver; + mMainLooper = mainLooper; + } + + @Override + public GLRoot getGLRoot() { return mGLRoot; } + @Override + public DataManager getDataManager() { return mDataManager; } + @Override + public Context getAndroidContext() { return mContext; } + @Override + public ContentResolver getContentResolver() { return mResolver; } + @Override + public Looper getMainLooper() { return mMainLooper; } +} diff --git a/tests/src/com/android/gallery3d/data/GalleryAppStub.java b/tests/src/com/android/gallery3d/data/GalleryAppStub.java new file mode 100644 index 000000000..36075f435 --- /dev/null +++ b/tests/src/com/android/gallery3d/data/GalleryAppStub.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.data; + +import com.android.gallery3d.app.GalleryApp; +import com.android.gallery3d.app.StateManager; +import com.android.gallery3d.ui.GLRoot; +import com.android.gallery3d.ui.PositionRepository; +import com.android.gallery3d.util.ThreadPool; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.os.Looper; + +class GalleryAppStub implements GalleryApp { + public ImageCacheService getImageCacheService() { return null; } + public StateManager getStateManager() { return null; } + public DataManager getDataManager() { return null; } + public DownloadUtils getDownloadService() { return null; } + public DecodeUtils getDecodeService() { return null; } + + public GLRoot getGLRoot() { return null; } + public PositionRepository getPositionRepository() { return null; } + + public Context getAndroidContext() { return null; } + + public Looper getMainLooper() { return null; } + public Resources getResources() { return null; } + public ContentResolver getContentResolver() { return null; } + public ThreadPool getThreadPool() { return null; } + public DownloadCache getDownloadCache() { return null; } +} diff --git a/tests/src/com/android/gallery3d/data/LocalDataTest.java b/tests/src/com/android/gallery3d/data/LocalDataTest.java new file mode 100644 index 000000000..8f6a46b8e --- /dev/null +++ b/tests/src/com/android/gallery3d/data/LocalDataTest.java @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.data; + +import android.content.ContentProvider; +import android.content.ContentResolver; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteQueryBuilder; +import android.net.Uri; +import android.os.Looper; +import android.test.AndroidTestCase; +import android.test.mock.MockContentProvider; +import android.test.mock.MockContentResolver; +import android.test.suitebuilder.annotation.MediumTest; +import android.util.Log; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class LocalDataTest extends AndroidTestCase { + @SuppressWarnings("unused") + private static final String TAG = "LocalDataTest"; + private static final long DEFAULT_TIMEOUT = 1000; // one second + + @MediumTest + public void testLocalAlbum() throws Exception { + new TestZeroImage().run(); + new TestOneImage().run(); + new TestMoreImages().run(); + new TestZeroVideo().run(); + new TestOneVideo().run(); + new TestMoreVideos().run(); + new TestDeleteOneImage().run(); + new TestDeleteOneAlbum().run(); + } + + abstract class TestLocalAlbumBase { + private boolean mIsImage; + protected GalleryAppStub mApp; + protected LocalAlbumSet mAlbumSet; + + TestLocalAlbumBase(boolean isImage) { + mIsImage = isImage; + } + + public void run() throws Exception { + SQLiteDatabase db = SQLiteDatabase.create(null); + prepareData(db); + mApp = newGalleryContext(db, Looper.getMainLooper()); + Path.clearAll(); + Path path = Path.fromString( + mIsImage ? "/local/image" : "/local/video"); + mAlbumSet = new LocalAlbumSet(path, mApp); + mAlbumSet.reload(); + verifyResult(); + } + + abstract void prepareData(SQLiteDatabase db); + abstract void verifyResult() throws Exception; + } + + abstract class TestLocalImageAlbum extends TestLocalAlbumBase { + TestLocalImageAlbum() { + super(true); + } + } + + abstract class TestLocalVideoAlbum extends TestLocalAlbumBase { + TestLocalVideoAlbum() { + super(false); + } + } + + class TestZeroImage extends TestLocalImageAlbum { + @Override + public void prepareData(SQLiteDatabase db) { + createImageTable(db); + } + + @Override + public void verifyResult() { + assertEquals(0, mAlbumSet.getMediaItemCount()); + assertEquals(0, mAlbumSet.getSubMediaSetCount()); + assertEquals(0, mAlbumSet.getTotalMediaItemCount()); + } + } + + class TestOneImage extends TestLocalImageAlbum { + @Override + public void prepareData(SQLiteDatabase db) { + createImageTable(db); + insertImageData(db); + } + + @Override + public void verifyResult() { + assertEquals(0, mAlbumSet.getMediaItemCount()); + assertEquals(1, mAlbumSet.getSubMediaSetCount()); + assertEquals(1, mAlbumSet.getTotalMediaItemCount()); + MediaSet sub = mAlbumSet.getSubMediaSet(0); + assertEquals(1, sub.getMediaItemCount()); + assertEquals(0, sub.getSubMediaSetCount()); + LocalMediaItem item = (LocalMediaItem) sub.getMediaItem(0, 1).get(0); + assertEquals(1, item.id); + assertEquals("IMG_0072", item.caption); + assertEquals("image/jpeg", item.mimeType); + assertEquals(12.0, item.latitude); + assertEquals(34.0, item.longitude); + assertEquals(0xD000, item.dateTakenInMs); + assertEquals(1280395646L, item.dateAddedInSec); + assertEquals(1275934796L, item.dateModifiedInSec); + assertEquals("/mnt/sdcard/DCIM/100CANON/IMG_0072.JPG", item.filePath); + } + } + + class TestMoreImages extends TestLocalImageAlbum { + @Override + public void prepareData(SQLiteDatabase db) { + // Albums are sorted by names, and items are sorted by + // dateTimeTaken (descending) + createImageTable(db); + // bucket 0xB000 + insertImageData(db, 1000, 0xB000, "second"); // id 1 + insertImageData(db, 2000, 0xB000, "second"); // id 2 + // bucket 0xB001 + insertImageData(db, 3000, 0xB001, "first"); // id 3 + } + + @Override + public void verifyResult() { + assertEquals(0, mAlbumSet.getMediaItemCount()); + assertEquals(2, mAlbumSet.getSubMediaSetCount()); + assertEquals(3, mAlbumSet.getTotalMediaItemCount()); + + MediaSet first = mAlbumSet.getSubMediaSet(0); + assertEquals(1, first.getMediaItemCount()); + LocalMediaItem item = (LocalMediaItem) first.getMediaItem(0, 1).get(0); + assertEquals(3, item.id); + assertEquals(3000L, item.dateTakenInMs); + + MediaSet second = mAlbumSet.getSubMediaSet(1); + assertEquals(2, second.getMediaItemCount()); + item = (LocalMediaItem) second.getMediaItem(0, 1).get(0); + assertEquals(2, item.id); + assertEquals(2000L, item.dateTakenInMs); + item = (LocalMediaItem) second.getMediaItem(1, 1).get(0); + assertEquals(1, item.id); + assertEquals(1000L, item.dateTakenInMs); + } + } + + class OnContentDirtyLatch implements ContentListener { + private CountDownLatch mLatch = new CountDownLatch(1); + + public void onContentDirty() { + mLatch.countDown(); + } + + public boolean isOnContentDirtyBeCalled(long timeout) + throws InterruptedException { + return mLatch.await(timeout, TimeUnit.MILLISECONDS); + } + } + + class TestDeleteOneAlbum extends TestLocalImageAlbum { + @Override + public void prepareData(SQLiteDatabase db) { + // Albums are sorted by names, and items are sorted by + // dateTimeTaken (descending) + createImageTable(db); + // bucket 0xB000 + insertImageData(db, 1000, 0xB000, "second"); // id 1 + insertImageData(db, 2000, 0xB000, "second"); // id 2 + // bucket 0xB001 + insertImageData(db, 3000, 0xB001, "first"); // id 3 + } + + @Override + public void verifyResult() throws Exception { + MediaSet sub = mAlbumSet.getSubMediaSet(1); // "second" + assertEquals(2, mAlbumSet.getSubMediaSetCount()); + OnContentDirtyLatch latch = new OnContentDirtyLatch(); + sub.addContentListener(latch); + assertTrue((sub.getSupportedOperations() & MediaSet.SUPPORT_DELETE) != 0); + sub.delete(); + mAlbumSet.fakeChange(); + latch.isOnContentDirtyBeCalled(DEFAULT_TIMEOUT); + mAlbumSet.reload(); + assertEquals(1, mAlbumSet.getSubMediaSetCount()); + } + } + + class TestDeleteOneImage extends TestLocalImageAlbum { + + @Override + public void prepareData(SQLiteDatabase db) { + createImageTable(db); + insertImageData(db); + } + + @Override + public void verifyResult() { + MediaSet sub = mAlbumSet.getSubMediaSet(0); + LocalMediaItem item = (LocalMediaItem) sub.getMediaItem(0, 1).get(0); + assertEquals(1, sub.getMediaItemCount()); + assertTrue((sub.getSupportedOperations() & MediaSet.SUPPORT_DELETE) != 0); + sub.delete(); + sub.reload(); + assertEquals(0, sub.getMediaItemCount()); + } + } + + static void createImageTable(SQLiteDatabase db) { + // This is copied from MediaProvider + db.execSQL("CREATE TABLE IF NOT EXISTS images (" + + "_id INTEGER PRIMARY KEY," + + "_data TEXT," + + "_size INTEGER," + + "_display_name TEXT," + + "mime_type TEXT," + + "title TEXT," + + "date_added INTEGER," + + "date_modified INTEGER," + + "description TEXT," + + "picasa_id TEXT," + + "isprivate INTEGER," + + "latitude DOUBLE," + + "longitude DOUBLE," + + "datetaken INTEGER," + + "orientation INTEGER," + + "mini_thumb_magic INTEGER," + + "bucket_id TEXT," + + "bucket_display_name TEXT" + + ");"); + } + + static void insertImageData(SQLiteDatabase db) { + insertImageData(db, 0xD000, 0xB000, "name"); + } + + static void insertImageData(SQLiteDatabase db, long dateTaken, + int bucketId, String bucketName) { + db.execSQL("INSERT INTO images (title, mime_type, latitude, longitude, " + + "datetaken, date_added, date_modified, bucket_id, " + + "bucket_display_name, _data, orientation) " + + "VALUES ('IMG_0072', 'image/jpeg', 12, 34, " + + dateTaken + ", 1280395646, 1275934796, '" + bucketId + "', " + + "'" + bucketName + "', " + + "'/mnt/sdcard/DCIM/100CANON/IMG_0072.JPG', 0)"); + } + + class TestZeroVideo extends TestLocalVideoAlbum { + @Override + public void prepareData(SQLiteDatabase db) { + createVideoTable(db); + } + + @Override + public void verifyResult() { + assertEquals(0, mAlbumSet.getMediaItemCount()); + assertEquals(0, mAlbumSet.getSubMediaSetCount()); + assertEquals(0, mAlbumSet.getTotalMediaItemCount()); + } + } + + class TestOneVideo extends TestLocalVideoAlbum { + @Override + public void prepareData(SQLiteDatabase db) { + createVideoTable(db); + insertVideoData(db); + } + + @Override + public void verifyResult() { + assertEquals(0, mAlbumSet.getMediaItemCount()); + assertEquals(1, mAlbumSet.getSubMediaSetCount()); + assertEquals(1, mAlbumSet.getTotalMediaItemCount()); + MediaSet sub = mAlbumSet.getSubMediaSet(0); + assertEquals(1, sub.getMediaItemCount()); + assertEquals(0, sub.getSubMediaSetCount()); + LocalMediaItem item = (LocalMediaItem) sub.getMediaItem(0, 1).get(0); + assertEquals(1, item.id); + assertEquals("VID_20100811_051413", item.caption); + assertEquals("video/mp4", item.mimeType); + assertEquals(11.0, item.latitude); + assertEquals(22.0, item.longitude); + assertEquals(0xD000, item.dateTakenInMs); + assertEquals(1281503663L, item.dateAddedInSec); + assertEquals(1281503662L, item.dateModifiedInSec); + assertEquals("/mnt/sdcard/DCIM/Camera/VID_20100811_051413.3gp", + item.filePath); + } + } + + class TestMoreVideos extends TestLocalVideoAlbum { + @Override + public void prepareData(SQLiteDatabase db) { + // Albums are sorted by names, and items are sorted by + // dateTimeTaken (descending) + createVideoTable(db); + // bucket 0xB002 + insertVideoData(db, 1000, 0xB000, "second"); // id 1 + insertVideoData(db, 2000, 0xB000, "second"); // id 2 + // bucket 0xB001 + insertVideoData(db, 3000, 0xB001, "first"); // id 3 + } + + @Override + public void verifyResult() { + assertEquals(0, mAlbumSet.getMediaItemCount()); + assertEquals(2, mAlbumSet.getSubMediaSetCount()); + assertEquals(3, mAlbumSet.getTotalMediaItemCount()); + + MediaSet first = mAlbumSet.getSubMediaSet(0); + assertEquals(1, first.getMediaItemCount()); + LocalMediaItem item = (LocalMediaItem) first.getMediaItem(0, 1).get(0); + assertEquals(3, item.id); + assertEquals(3000L, item.dateTakenInMs); + + MediaSet second = mAlbumSet.getSubMediaSet(1); + assertEquals(2, second.getMediaItemCount()); + item = (LocalMediaItem) second.getMediaItem(0, 1).get(0); + assertEquals(2, item.id); + assertEquals(2000L, item.dateTakenInMs); + item = (LocalMediaItem) second.getMediaItem(1, 1).get(0); + assertEquals(1, item.id); + assertEquals(1000L, item.dateTakenInMs); + } + } + + static void createVideoTable(SQLiteDatabase db) { + db.execSQL("CREATE TABLE IF NOT EXISTS video (" + + "_id INTEGER PRIMARY KEY," + + "_data TEXT NOT NULL," + + "_display_name TEXT," + + "_size INTEGER," + + "mime_type TEXT," + + "date_added INTEGER," + + "date_modified INTEGER," + + "title TEXT," + + "duration INTEGER," + + "artist TEXT," + + "album TEXT," + + "resolution TEXT," + + "description TEXT," + + "isprivate INTEGER," + // for YouTube videos + "tags TEXT," + // for YouTube videos + "category TEXT," + // for YouTube videos + "language TEXT," + // for YouTube videos + "mini_thumb_data TEXT," + + "latitude DOUBLE," + + "longitude DOUBLE," + + "datetaken INTEGER," + + "mini_thumb_magic INTEGER" + + ");"); + db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;"); + db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT"); + } + + static void insertVideoData(SQLiteDatabase db) { + insertVideoData(db, 0xD000, 0xB000, "name"); + } + + static void insertVideoData(SQLiteDatabase db, long dateTaken, + int bucketId, String bucketName) { + db.execSQL("INSERT INTO video (title, mime_type, latitude, longitude, " + + "datetaken, date_added, date_modified, bucket_id, " + + "bucket_display_name, _data, duration) " + + "VALUES ('VID_20100811_051413', 'video/mp4', 11, 22, " + + dateTaken + ", 1281503663, 1281503662, '" + bucketId + "', " + + "'" + bucketName + "', " + + "'/mnt/sdcard/DCIM/Camera/VID_20100811_051413.3gp', 2964)"); + } + + static GalleryAppStub newGalleryContext(SQLiteDatabase db, Looper mainLooper) { + MockContentResolver cr = new MockContentResolver(); + ContentProvider cp = new DbContentProvider(db, cr); + cr.addProvider("media", cp); + return new GalleryAppMock(null, cr, mainLooper); + } +} + +class DbContentProvider extends MockContentProvider { + private static final String TAG = "DbContentProvider"; + private SQLiteDatabase mDatabase; + private ContentResolver mContentResolver; + + DbContentProvider(SQLiteDatabase db, ContentResolver cr) { + mDatabase = db; + mContentResolver = cr; + } + + @Override + public Cursor query(Uri uri, String[] projection, + String selection, String[] selectionArgs, String sortOrder) { + // This is a simplified version extracted from MediaProvider. + + String tableName = getTableName(uri); + if (tableName == null) return null; + + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); + qb.setTables(tableName); + + String groupBy = null; + String limit = uri.getQueryParameter("limit"); + + if (uri.getQueryParameter("distinct") != null) { + qb.setDistinct(true); + } + + Log.v(TAG, "query = " + qb.buildQuery(projection, selection, + selectionArgs, groupBy, null, sortOrder, limit)); + + if (selectionArgs != null) { + for (String s : selectionArgs) { + Log.v(TAG, " selectionArgs = " + s); + } + } + + Cursor c = qb.query(mDatabase, projection, selection, + selectionArgs, groupBy, null, sortOrder, limit); + + return c; + } + + @Override + public int delete(Uri uri, String whereClause, String[] whereArgs) { + Log.v(TAG, "delete " + uri + "," + whereClause + "," + whereArgs[0]); + String tableName = getTableName(uri); + if (tableName == null) return 0; + int count = mDatabase.delete(tableName, whereClause, whereArgs); + mContentResolver.notifyChange(uri, null); + return count; + } + + private String getTableName(Uri uri) { + String uriString = uri.toString(); + if (uriString.startsWith("content://media/external/images/media")) { + return "images"; + } else if (uriString.startsWith("content://media/external/video/media")) { + return "video"; + } else { + return null; + } + } +} diff --git a/tests/src/com/android/gallery3d/data/MediaSetTest.java b/tests/src/com/android/gallery3d/data/MediaSetTest.java new file mode 100644 index 000000000..33dfe96de --- /dev/null +++ b/tests/src/com/android/gallery3d/data/MediaSetTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.data; + +import com.android.gallery3d.app.GalleryApp; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class MediaSetTest extends AndroidTestCase { + @SuppressWarnings("unused") + private static final String TAG = "MediaSetTest"; + + @SmallTest + public void testComboAlbumSet() { + GalleryApp app = new GalleryAppMock(null, null, null); + Path.clearAll(); + DataManager dataManager = app.getDataManager(); + + dataManager.addSource(new ComboSource(app)); + dataManager.addSource(new MockSource(app)); + + MockSet set00 = new MockSet(Path.fromString("/mock/00"), dataManager, 0, 2000); + MockSet set01 = new MockSet(Path.fromString("/mock/01"), dataManager, 1, 3000); + MockSet set10 = new MockSet(Path.fromString("/mock/10"), dataManager, 2, 4000); + MockSet set11 = new MockSet(Path.fromString("/mock/11"), dataManager, 3, 5000); + MockSet set12 = new MockSet(Path.fromString("/mock/12"), dataManager, 4, 6000); + + MockSet set0 = new MockSet(Path.fromString("/mock/0"), dataManager, 7, 7000); + set0.addMediaSet(set00); + set0.addMediaSet(set01); + + MockSet set1 = new MockSet(Path.fromString("/mock/1"), dataManager, 8, 8000); + set1.addMediaSet(set10); + set1.addMediaSet(set11); + set1.addMediaSet(set12); + + MediaSet combo = dataManager.getMediaSet("/combo/{/mock/0,/mock/1}"); + assertEquals(5, combo.getSubMediaSetCount()); + assertEquals(0, combo.getMediaItemCount()); + assertEquals("/mock/00", combo.getSubMediaSet(0).getPath().toString()); + assertEquals("/mock/01", combo.getSubMediaSet(1).getPath().toString()); + assertEquals("/mock/10", combo.getSubMediaSet(2).getPath().toString()); + assertEquals("/mock/11", combo.getSubMediaSet(3).getPath().toString()); + assertEquals("/mock/12", combo.getSubMediaSet(4).getPath().toString()); + + assertEquals(10, combo.getTotalMediaItemCount()); + } +} diff --git a/tests/src/com/android/gallery3d/data/MockItem.java b/tests/src/com/android/gallery3d/data/MockItem.java new file mode 100644 index 000000000..bd6dcd9cb --- /dev/null +++ b/tests/src/com/android/gallery3d/data/MockItem.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.data; + +import com.android.gallery3d.util.ThreadPool.Job; + +import android.graphics.Bitmap; +import android.graphics.BitmapRegionDecoder; + +public class MockItem extends MediaItem { + public MockItem(Path path) { + super(path, nextVersionNumber()); + } + + @Override + public Job requestImage(int type) { + return null; + } + + @Override + public Job requestLargeImage() { + return null; + } + + @Override + public String getMimeType() { + return null; + } +} diff --git a/tests/src/com/android/gallery3d/data/MockSet.java b/tests/src/com/android/gallery3d/data/MockSet.java new file mode 100644 index 000000000..fa83c796f --- /dev/null +++ b/tests/src/com/android/gallery3d/data/MockSet.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.data; + +import java.util.ArrayList; + +public class MockSet extends MediaSet { + ArrayList mItems = new ArrayList(); + ArrayList mSets = new ArrayList(); + Path mItemPath; + + public MockSet(Path path, DataManager dataManager) { + super(path, nextVersionNumber()); + mItemPath = Path.fromString("/mock/item"); + } + + public MockSet(Path path, DataManager dataManager, + int items, int item_id_start) { + this(path, dataManager); + for (int i = 0; i < items; i++) { + Path childPath = mItemPath.getChild(item_id_start + i); + mItems.add(new MockItem(childPath)); + } + } + + public void addMediaSet(MediaSet sub) { + mSets.add(sub); + } + + @Override + public int getMediaItemCount() { + return mItems.size(); + } + + @Override + public ArrayList getMediaItem(int start, int count) { + ArrayList result = new ArrayList(); + int end = Math.min(start + count, mItems.size()); + + for (int i = start; i < end; i++) { + result.add(mItems.get(i)); + } + return result; + } + + @Override + public int getSubMediaSetCount() { + return mSets.size(); + } + + @Override + public MediaSet getSubMediaSet(int index) { + return mSets.get(index); + } + + @Override + public int getTotalMediaItemCount() { + int result = mItems.size(); + for (MediaSet s : mSets) { + result += s.getTotalMediaItemCount(); + } + return result; + } + + @Override + public String getName() { + return "Set " + mPath; + } + + @Override + public long reload() { + return 0; + } +} diff --git a/tests/src/com/android/gallery3d/data/MockSource.java b/tests/src/com/android/gallery3d/data/MockSource.java new file mode 100644 index 000000000..27ed4d0de --- /dev/null +++ b/tests/src/com/android/gallery3d/data/MockSource.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.data; + +import com.android.gallery3d.app.GalleryApp; + +class MockSource extends MediaSource { + GalleryApp mApplication; + PathMatcher mMatcher; + + private static final int MOCK_SET = 0; + private static final int MOCK_ITEM = 1; + + public MockSource(GalleryApp context) { + super("mock"); + mApplication = context; + mMatcher = new PathMatcher(); + mMatcher.add("/mock/*", MOCK_SET); + mMatcher.add("/mock/item/*", MOCK_ITEM); + } + + @Override + public MediaObject createMediaObject(Path path) { + MediaObject obj; + switch (mMatcher.match(path)) { + case MOCK_SET: + return new MockSet(path, mApplication.getDataManager()); + case MOCK_ITEM: + return new MockItem(path); + default: + throw new RuntimeException("bad path: " + path); + } + } +} diff --git a/tests/src/com/android/gallery3d/data/PathTest.java b/tests/src/com/android/gallery3d/data/PathTest.java new file mode 100644 index 000000000..b43d10963 --- /dev/null +++ b/tests/src/com/android/gallery3d/data/PathTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.data; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class PathTest extends AndroidTestCase { + @SuppressWarnings("unused") + private static final String TAG = "PathTest"; + + @SmallTest + public void testToString() { + Path p = Path.fromString("/hello/world"); + assertEquals("/hello/world", p.toString()); + + p = Path.fromString("/a"); + assertEquals("/a", p.toString()); + + p = Path.fromString(""); + assertEquals("", p.toString()); + } + + @SmallTest + public void testSplit() { + Path p = Path.fromString("/hello/world"); + String[] s = p.split(); + assertEquals(2, s.length); + assertEquals("hello", s[0]); + assertEquals("world", s[1]); + + p = Path.fromString(""); + assertEquals(0, p.split().length); + } + + @SmallTest + public void testPrefix() { + Path p = Path.fromString("/hello/world"); + assertEquals("hello", p.getPrefix()); + + p = Path.fromString(""); + assertEquals("", p.getPrefix()); + } + + @SmallTest + public void testGetChild() { + Path p = Path.fromString("/hello"); + Path q = Path.fromString("/hello/world"); + assertSame(q, p.getChild("world")); + Path r = q.getChild(17); + assertEquals("/hello/world/17", r.toString()); + } + + @SmallTest + public void testSplitSequence() { + String[] s = Path.splitSequence("{a,bb,ccc}"); + assertEquals(3, s.length); + assertEquals("a", s[0]); + assertEquals("bb", s[1]); + assertEquals("ccc", s[2]); + + s = Path.splitSequence("{a,{bb,ccc},d}"); + assertEquals(3, s.length); + assertEquals("a", s[0]); + assertEquals("{bb,ccc}", s[1]); + assertEquals("d", s[2]); + } +} diff --git a/tests/src/com/android/gallery3d/data/RealDataTest.java b/tests/src/com/android/gallery3d/data/RealDataTest.java new file mode 100644 index 000000000..526cfe357 --- /dev/null +++ b/tests/src/com/android/gallery3d/data/RealDataTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.data; + +import com.android.gallery3d.app.GalleryApp; +import com.android.gallery3d.picasasource.PicasaSource; + +import android.os.Looper; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; + +import java.util.ArrayList; +import java.util.HashSet; + +// This test reads real data directly and dump information out in the log. +public class RealDataTest extends AndroidTestCase { + private static final String TAG = "RealDataTest"; + + private HashSet mUsedId = new HashSet(); + private GalleryApp mApplication; + private DataManager mDataManager; + + @LargeTest + public void testRealData() { + mUsedId.clear(); + mApplication = new GalleryAppMock( + mContext, + mContext.getContentResolver(), + Looper.myLooper()); + mDataManager = mApplication.getDataManager(); + mDataManager.addSource(new LocalSource(mApplication)); + mDataManager.addSource(new PicasaSource(mApplication)); + new TestLocalImage().run(); + new TestLocalVideo().run(); + new TestPicasa().run(); + } + + class TestLocalImage { + public void run() { + MediaSet set = mDataManager.getMediaSet("/local/image"); + set.reload(); + Log.v(TAG, "LocalAlbumSet (Image)"); + dumpMediaSet(set, ""); + } + } + + class TestLocalVideo { + public void run() { + MediaSet set = mDataManager.getMediaSet("/local/video"); + set.reload(); + Log.v(TAG, "LocalAlbumSet (Video)"); + dumpMediaSet(set, ""); + } + } + + class TestPicasa implements Runnable { + public void run() { + MediaSet set = mDataManager.getMediaSet("/picasa"); + set.reload(); + Log.v(TAG, "PicasaAlbumSet"); + dumpMediaSet(set, ""); + } + } + + void dumpMediaSet(MediaSet set, String prefix) { + Log.v(TAG, "getName() = " + set.getName()); + Log.v(TAG, "getPath() = " + set.getPath()); + Log.v(TAG, "getMediaItemCount() = " + set.getMediaItemCount()); + Log.v(TAG, "getSubMediaSetCount() = " + set.getSubMediaSetCount()); + Log.v(TAG, "getTotalMediaItemCount() = " + set.getTotalMediaItemCount()); + assertNewId(set.getPath()); + for (int i = 0, n = set.getSubMediaSetCount(); i < n; i++) { + MediaSet sub = set.getSubMediaSet(i); + Log.v(TAG, prefix + "got set " + i); + dumpMediaSet(sub, prefix + " "); + } + for (int i = 0, n = set.getMediaItemCount(); i < n; i += 10) { + ArrayList list = set.getMediaItem(i, 10); + Log.v(TAG, prefix + "got item " + i + " (+" + list.size() + ")"); + for (MediaItem item : list) { + dumpMediaItem(item, prefix + ".."); + } + } + } + + void dumpMediaItem(MediaItem item, String prefix) { + assertNewId(item.getPath()); + Log.v(TAG, prefix + "getPath() = " + item.getPath()); + } + + void assertNewId(Path key) { + assertFalse(key + " has already appeared.", mUsedId.contains(key)); + mUsedId.add(key); + } +} diff --git a/tests/src/com/android/gallery3d/ui/GLCanvasMock.java b/tests/src/com/android/gallery3d/ui/GLCanvasMock.java new file mode 100644 index 000000000..f8100ddf6 --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/GLCanvasMock.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import javax.microedition.khronos.opengles.GL11; + +public class GLCanvasMock extends GLCanvasStub { + // fillRect + int mFillRectCalled; + float mFillRectWidth; + float mFillRectHeight; + int mFillRectColor; + // drawMixed + int mDrawMixedCalled; + float mDrawMixedRatio; + // drawTexture; + int mDrawTextureCalled; + + private GL11 mGL; + + public GLCanvasMock(GL11 gl) { + mGL = gl; + } + + public GLCanvasMock() { + mGL = new GLStub(); + } + + @Override + public GL11 getGLInstance() { + return mGL; + } + + @Override + public void fillRect(float x, float y, float width, float height, int color) { + mFillRectCalled++; + mFillRectWidth = width; + mFillRectHeight = height; + mFillRectColor = color; + } + + @Override + public void drawTexture( + BasicTexture texture, int x, int y, int width, int height) { + mDrawTextureCalled++; + } + + @Override + public void drawMixed(BasicTexture from, BasicTexture to, + float ratio, int x, int y, int w, int h) { + mDrawMixedCalled++; + mDrawMixedRatio = ratio; + } +} diff --git a/tests/src/com/android/gallery3d/ui/GLCanvasStub.java b/tests/src/com/android/gallery3d/ui/GLCanvasStub.java new file mode 100644 index 000000000..f1663f4bd --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/GLCanvasStub.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import android.graphics.RectF; + +import javax.microedition.khronos.opengles.GL11; + +public class GLCanvasStub implements GLCanvas { + public void setSize(int width, int height) {} + public void clearBuffer() {} + public void setCurrentAnimationTimeMillis(long time) {} + public long currentAnimationTimeMillis() { + throw new UnsupportedOperationException(); + } + public void setAlpha(float alpha) {} + public float getAlpha() { + throw new UnsupportedOperationException(); + } + public void multiplyAlpha(float alpha) {} + public void translate(float x, float y, float z) {} + public void scale(float sx, float sy, float sz) {} + public void rotate(float angle, float x, float y, float z) {} + public boolean clipRect(int left, int top, int right, int bottom) { + throw new UnsupportedOperationException(); + } + public int save() { + throw new UnsupportedOperationException(); + } + public int save(int saveFlags) { + throw new UnsupportedOperationException(); + } + public void setBlendEnabled(boolean enabled) {} + public void restore() {} + public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {} + public void drawRect(float x1, float y1, float x2, float y2, GLPaint paint) {} + public void fillRect(float x, float y, float width, float height, int color) {} + public void drawTexture( + BasicTexture texture, int x, int y, int width, int height) {} + public void drawMesh(BasicTexture tex, int x, int y, int xyBuffer, + int uvBuffer, int indexBuffer, int indexCount) {} + public void drawTexture(BasicTexture texture, + int x, int y, int width, int height, float alpha) {} + public void drawTexture(BasicTexture texture, RectF source, RectF target) {} + public void drawMixed(BasicTexture from, BasicTexture to, + float ratio, int x, int y, int w, int h) {} + public void drawMixed(BasicTexture from, int to, + float ratio, int x, int y, int w, int h) {} + public void drawMixed(BasicTexture from, BasicTexture to, + float ratio, int x, int y, int width, int height, float alpha) {} + public BasicTexture copyTexture(int x, int y, int width, int height) { + throw new UnsupportedOperationException(); + } + public GL11 getGLInstance() { + throw new UnsupportedOperationException(); + } + public boolean unloadTexture(BasicTexture texture) { + throw new UnsupportedOperationException(); + } + public void deleteBuffer(int bufferId) { + throw new UnsupportedOperationException(); + } + public void deleteRecycledResources() {} + public void multiplyMatrix(float[] mMatrix, int offset) {} +} diff --git a/tests/src/com/android/gallery3d/ui/GLCanvasTest.java b/tests/src/com/android/gallery3d/ui/GLCanvasTest.java new file mode 100644 index 000000000..528b04f67 --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/GLCanvasTest.java @@ -0,0 +1,778 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import junit.framework.TestCase; + +import java.util.Arrays; + +import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.opengles.GL11; + +@SmallTest +public class GLCanvasTest extends TestCase { + private static final String TAG = "GLCanvasTest"; + + private static GLPaint newColorPaint(int color) { + GLPaint paint = new GLPaint(); + paint.setColor(color); + return paint; + } + + @SmallTest + public void testSetSize() { + GL11 glStub = new GLStub(); + GLCanvas canvas = new GLCanvasImpl(glStub); + canvas.setSize(100, 200); + canvas.setSize(1000, 100); + try { + canvas.setSize(-1, 100); + fail(); + } catch (Throwable ex) { + // expected. + } + } + + @SmallTest + public void testClearBuffer() { + new ClearBufferTest().run(); + } + + private static class ClearBufferTest extends GLMock { + void run() { + GLCanvas canvas = new GLCanvasImpl(this); + assertEquals(0, mGLClearCalled); + canvas.clearBuffer(); + assertEquals(GL10.GL_COLOR_BUFFER_BIT, mGLClearMask); + assertEquals(1, mGLClearCalled); + } + } + + @SmallTest + public void testAnimationTime() { + GL11 glStub = new GLStub(); + GLCanvas canvas = new GLCanvasImpl(glStub); + + long[] testData = {0, 1, 2, 1000, 10000, Long.MAX_VALUE}; + + for (long v : testData) { + canvas.setCurrentAnimationTimeMillis(v); + assertEquals(v, canvas.currentAnimationTimeMillis()); + } + + try { + canvas.setCurrentAnimationTimeMillis(-1); + fail(); + } catch (Throwable ex) { + // expected. + } + } + + @SmallTest + public void testSetColor() { + new SetColorTest().run(); + } + + // This test assumes we use pre-multipled alpha blending and should + // set the blending function and color correctly. + private static class SetColorTest extends GLMock { + void run() { + int[] testColors = new int[] { + 0, 0xFFFFFFFF, 0xFF000000, 0x00FFFFFF, 0x80FF8001, + 0x7F010101, 0xFEFEFDFC, 0x017F8081, 0x027F8081, 0x2ADE4C4D + }; + + GLCanvas canvas = new GLCanvasImpl(this); + canvas.setSize(400, 300); + // Test one color to make sure blend function is set. + assertEquals(0, mGLColorCalled); + canvas.drawLine(0, 0, 1, 1, newColorPaint(0x7F804020)); + assertEquals(1, mGLColorCalled); + assertEquals(0x7F402010, mGLColor); + assertPremultipliedBlending(this); + + // Test other colors to make sure premultiplication is right + for (int c : testColors) { + float a = (c >>> 24) / 255f; + float r = ((c >> 16) & 0xff) / 255f; + float g = ((c >> 8) & 0xff) / 255f; + float b = (c & 0xff) / 255f; + int pre = makeColor4f(a * r, a * g, a * b, a); + + mGLColorCalled = 0; + canvas.drawLine(0, 0, 1, 1, newColorPaint(c)); + assertEquals(1, mGLColorCalled); + assertEquals(pre, mGLColor); + } + } + } + + @SmallTest + public void testSetGetMultiplyAlpha() { + GL11 glStub = new GLStub(); + GLCanvas canvas = new GLCanvasImpl(glStub); + + canvas.setAlpha(1f); + assertEquals(1f, canvas.getAlpha()); + + canvas.setAlpha(0f); + assertEquals(0f, canvas.getAlpha()); + + canvas.setAlpha(0.5f); + assertEquals(0.5f, canvas.getAlpha()); + + canvas.multiplyAlpha(0.5f); + assertEquals(0.25f, canvas.getAlpha()); + + canvas.multiplyAlpha(0f); + assertEquals(0f, canvas.getAlpha()); + + try { + canvas.setAlpha(-0.01f); + fail(); + } catch (Throwable ex) { + // expected. + } + + try { + canvas.setAlpha(1.01f); + fail(); + } catch (Throwable ex) { + // expected. + } + } + + @SmallTest + public void testAlpha() { + new AlphaTest().run(); + } + + private static class AlphaTest extends GLMock { + void run() { + GLCanvas canvas = new GLCanvasImpl(this); + canvas.setSize(400, 300); + + assertEquals(0, mGLColorCalled); + canvas.setAlpha(0.48f); + canvas.drawLine(0, 0, 1, 1, newColorPaint(0xFF804020)); + assertPremultipliedBlending(this); + assertEquals(1, mGLColorCalled); + assertEquals(0x7A3D1F0F, mGLColor); + } + } + + @SmallTest + public void testDrawLine() { + new DrawLineTest().run(); + } + + // This test assumes the drawLine() function use glDrawArrays() with + // GL_LINE_STRIP mode to draw the line and the input coordinates are used + // directly. + private static class DrawLineTest extends GLMock { + private int mDrawArrayCalled = 0; + private final int[] mResult = new int[4]; + + @Override + public void glDrawArrays(int mode, int first, int count) { + assertNotNull(mGLVertexPointer); + assertEquals(GL10.GL_LINE_STRIP, mode); + assertEquals(2, count); + mGLVertexPointer.bindByteBuffer(); + + double[] coord = new double[4]; + mGLVertexPointer.getArrayElement(first, coord); + mResult[0] = (int) coord[0]; + mResult[1] = (int) coord[1]; + mGLVertexPointer.getArrayElement(first + 1, coord); + mResult[2] = (int) coord[0]; + mResult[3] = (int) coord[1]; + mDrawArrayCalled++; + } + + void run() { + GLCanvas canvas = new GLCanvasImpl(this); + canvas.setSize(400, 300); + canvas.drawLine(2, 7, 1, 8, newColorPaint(0) /* color */); + assertTrue(mGLVertexArrayEnabled); + assertEquals(1, mDrawArrayCalled); + + Log.v(TAG, "result = " + Arrays.toString(mResult)); + int[] answer = new int[] {2, 7, 1, 8}; + for (int i = 0; i < answer.length; i++) { + assertEquals(answer[i], mResult[i]); + } + } + } + + @SmallTest + public void testFillRect() { + new FillRectTest().run(); + } + + // This test assumes the drawLine() function use glDrawArrays() with + // GL_TRIANGLE_STRIP mode to draw the line and the input coordinates + // are used directly. + private static class FillRectTest extends GLMock { + private int mDrawArrayCalled = 0; + private final int[] mResult = new int[8]; + + @Override + public void glDrawArrays(int mode, int first, int count) { + assertNotNull(mGLVertexPointer); + assertEquals(GL10.GL_TRIANGLE_STRIP, mode); + assertEquals(4, count); + mGLVertexPointer.bindByteBuffer(); + + double[] coord = new double[4]; + for (int i = 0; i < 4; i++) { + mGLVertexPointer.getArrayElement(first + i, coord); + mResult[i * 2 + 0] = (int) coord[0]; + mResult[i * 2 + 1] = (int) coord[1]; + } + + mDrawArrayCalled++; + } + + void run() { + GLCanvas canvas = new GLCanvasImpl(this); + canvas.setSize(400, 300); + canvas.fillRect(2, 7, 1, 8, 0 /* color */); + assertTrue(mGLVertexArrayEnabled); + assertEquals(1, mDrawArrayCalled); + Log.v(TAG, "result = " + Arrays.toString(mResult)); + + // These are the four vertics that should be used. + int[] answer = new int[] { + 2, 7, + 3, 7, + 3, 15, + 2, 15}; + int count[] = new int[4]; + + // Count the number of appearances for each vertex. + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + if (answer[i * 2] == mResult[j * 2] && + answer[i * 2 + 1] == mResult[j * 2 + 1]) { + count[i]++; + } + } + } + + // Each vertex should appear exactly once. + for (int i = 0; i < 4; i++) { + assertEquals(1, count[i]); + } + } + } + + @SmallTest + public void testTransform() { + new TransformTest().run(); + } + + // This test assumes glLoadMatrixf is used to load the model view matrix, + // and glOrthof is used to load the projection matrix. + // + // The projection matrix is set to an orthogonal projection which is the + // inverse of viewport transform. So the model view matrix maps input + // directly to screen coordinates (default no scaling, and the y-axis is + // reversed). + // + // The matrix here are all listed in column major order. + // + private static class TransformTest extends GLMock { + private final float[] mModelViewMatrixUsed = new float[16]; + private final float[] mProjectionMatrixUsed = new float[16]; + + @Override + public void glDrawArrays(int mode, int first, int count) { + copy(mModelViewMatrixUsed, mGLModelViewMatrix); + copy(mProjectionMatrixUsed, mGLProjectionMatrix); + } + + private void copy(float[] dest, float[] src) { + System.arraycopy(src, 0, dest, 0, 16); + } + + void run() { + GLCanvas canvas = new GLCanvasImpl(this); + canvas.setSize(40, 50); + int color = 0; + + // Initial matrix + canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); + assertMatrixEq(new float[] { + 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 0, 50, 0, 1 + }, mModelViewMatrixUsed); + + assertMatrixEq(new float[] { + 2f / 40, 0, 0, 0, + 0, 2f / 50, 0, 0, + 0, 0, -1, 0, + -1, -1, 0, 1 + }, mProjectionMatrixUsed); + + // Translation + canvas.translate(3, 4, 5); + canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); + assertMatrixEq(new float[] { + 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 3, 46, 5, 1 + }, mModelViewMatrixUsed); + canvas.save(); + + // Scaling + canvas.scale(0.7f, 0.6f, 0.5f); + canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); + assertMatrixEq(new float[] { + 0.7f, 0, 0, 0, + 0, -0.6f, 0, 0, + 0, 0, 0.5f, 0, + 3, 46, 5, 1 + }, mModelViewMatrixUsed); + + // Rotation + canvas.rotate(90, 0, 0, 1); + canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); + assertMatrixEq(new float[] { + 0, -0.6f, 0, 0, + -0.7f, 0, 0, 0, + 0, 0, 0.5f, 0, + 3, 46, 5, 1 + }, mModelViewMatrixUsed); + canvas.restore(); + + // After restoring to the point just after translation, + // do rotation again. + canvas.rotate(180, 1, 0, 0); + canvas.drawLine(0, 0, 1, 1, newColorPaint(color)); + assertMatrixEq(new float[] { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, -1, 0, + 3, 46, 5, 1 + }, mModelViewMatrixUsed); + } + } + + @SmallTest + public void testClipRect() { + // The test is currently broken, waiting for the fix + // new ClipRectTest().run(); + } + + private static class ClipRectTest extends GLStub { + int mX, mY, mWidth, mHeight; + + @Override + public void glScissor(int x, int y, int width, int height) { + mX = x; + mY = 100 - y - height; // flip in Y direction + mWidth = width; + mHeight = height; + } + + private void assertClipRect(int x, int y, int width, int height) { + assertEquals(x, mX); + assertEquals(y, mY); + assertEquals(width, mWidth); + assertEquals(height, mHeight); + } + + private void assertEmptyClipRect() { + assertEquals(0, mWidth); + assertEquals(0, mHeight); + } + + void run() { + GLCanvas canvas = new GLCanvasImpl(this); + canvas.setSize(100, 100); + canvas.save(); + assertClipRect(0, 0, 100, 100); + + assertTrue(canvas.clipRect(10, 10, 70, 70)); + canvas.save(); + assertClipRect(10, 10, 60, 60); + + assertTrue(canvas.clipRect(30, 30, 90, 90)); + canvas.save(); + assertClipRect(30, 30, 40, 40); + + assertTrue(canvas.clipRect(40, 40, 60, 90)); + assertClipRect(40, 40, 20, 30); + + assertFalse(canvas.clipRect(30, 30, 70, 40)); + assertEmptyClipRect(); + assertFalse(canvas.clipRect(0, 0, 100, 100)); + assertEmptyClipRect(); + + canvas.restore(); + assertClipRect(30, 30, 40, 40); + + canvas.restore(); + assertClipRect(10, 10, 60, 60); + + canvas.restore(); + assertClipRect(0, 0, 100, 100); + + canvas.translate(10, 20, 30); + assertTrue(canvas.clipRect(10, 10, 70, 70)); + canvas.save(); + assertClipRect(20, 30, 60, 60); + } + } + + @SmallTest + public void testSaveRestore() { + new SaveRestoreTest().run(); + } + + private static class SaveRestoreTest extends GLStub { + int mX, mY, mWidth, mHeight; + + @Override + public void glScissor(int x, int y, int width, int height) { + mX = x; + mY = 100 - y - height; // flip in Y direction + mWidth = width; + mHeight = height; + } + + private void assertClipRect(int x, int y, int width, int height) { + assertEquals(x, mX); + assertEquals(y, mY); + assertEquals(width, mWidth); + assertEquals(height, mHeight); + } + + void run() { + GLCanvas canvas = new GLCanvasImpl(this); + canvas.setSize(100, 100); + + canvas.setAlpha(0.7f); + assertTrue(canvas.clipRect(10, 10, 70, 70)); + + canvas.save(canvas.SAVE_FLAG_CLIP); + canvas.setAlpha(0.6f); + assertTrue(canvas.clipRect(30, 30, 90, 90)); + + canvas.save(canvas.SAVE_FLAG_CLIP | canvas.SAVE_FLAG_ALPHA); + canvas.setAlpha(0.5f); + assertTrue(canvas.clipRect(40, 40, 60, 90)); + + assertEquals(0.5f, canvas.getAlpha()); + assertClipRect(40, 40, 20, 30); + + canvas.restore(); // now both clipping rect and alpha are restored. + assertEquals(0.6f, canvas.getAlpha()); + assertClipRect(30, 30, 40, 40); + + canvas.restore(); // now only clipping rect is restored. + + canvas.save(0); + canvas.save(0); + canvas.restore(); + canvas.restore(); + + assertEquals(0.6f, canvas.getAlpha()); + assertTrue(canvas.clipRect(10, 10, 60, 60)); + } + } + + @SmallTest + public void testDrawTexture() { + new DrawTextureTest().run(); + new DrawTextureMixedTest().run(); + } + + private static class MyTexture extends BasicTexture { + boolean mIsOpaque; + int mBindCalled; + + MyTexture(GLCanvas canvas, int id, boolean isOpaque) { + super(canvas, id, STATE_LOADED); + setSize(1, 1); + mIsOpaque = isOpaque; + } + + @Override + protected boolean onBind(GLCanvas canvas) { + mBindCalled++; + return true; + } + + public boolean isOpaque() { + return mIsOpaque; + } + } + + private static class DrawTextureTest extends GLMock { + int mDrawTexiOESCalled; + int mDrawArrayCalled; + int[] mResult = new int[4]; + + @Override + public void glDrawTexiOES(int x, int y, int z, + int width, int height) { + mDrawTexiOESCalled++; + } + + @Override + public void glDrawArrays(int mode, int first, int count) { + assertNotNull(mGLVertexPointer); + assertEquals(GL10.GL_TRIANGLE_STRIP, mode); + assertEquals(4, count); + mGLVertexPointer.bindByteBuffer(); + + double[] coord = new double[4]; + mGLVertexPointer.getArrayElement(first, coord); + mResult[0] = (int) coord[0]; + mResult[1] = (int) coord[1]; + mGLVertexPointer.getArrayElement(first + 1, coord); + mResult[2] = (int) coord[0]; + mResult[3] = (int) coord[1]; + mDrawArrayCalled++; + } + + void run() { + GLCanvas canvas = new GLCanvasImpl(this); + canvas.setSize(400, 300); + MyTexture texture = new MyTexture(canvas, 42, false); // non-opaque + MyTexture texture_o = new MyTexture(canvas, 47, true); // opaque + + // Draw a non-opaque texture + canvas.drawTexture(texture, 100, 200, 300, 400); + assertEquals(42, mGLBindTextureId); + assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE_ENV_MODE)); + assertPremultipliedBlending(this); + assertFalse(mGLStencilEnabled); + + // Draw an opaque texture + canvas.drawTexture(texture_o, 100, 200, 300, 400); + assertEquals(47, mGLBindTextureId); + assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE_ENV_MODE)); + assertFalse(mGLBlendEnabled); + + // Draw a non-opaque texture with alpha = 0.5 + canvas.setAlpha(0.5f); + canvas.drawTexture(texture, 100, 200, 300, 400); + assertEquals(42, mGLBindTextureId); + assertEquals(0x80808080, mGLColor); + assertEquals(GL_MODULATE, getTexEnvi(GL_TEXTURE_ENV_MODE)); + assertPremultipliedBlending(this); + assertFalse(mGLStencilEnabled); + + // Draw an non-opaque texture with overriden alpha = 1 + canvas.drawTexture(texture, 100, 200, 300, 400, 1f); + assertEquals(42, mGLBindTextureId); + assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE_ENV_MODE)); + assertPremultipliedBlending(this); + + // Draw an opaque texture with overriden alpha = 1 + canvas.drawTexture(texture_o, 100, 200, 300, 400, 1f); + assertEquals(47, mGLBindTextureId); + assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE_ENV_MODE)); + assertFalse(mGLBlendEnabled); + + // Draw an opaque texture with overridden alpha = 0.25 + canvas.drawTexture(texture_o, 100, 200, 300, 400, 0.25f); + assertEquals(47, mGLBindTextureId); + assertEquals(0x40404040, mGLColor); + assertEquals(GL_MODULATE, getTexEnvi(GL_TEXTURE_ENV_MODE)); + assertPremultipliedBlending(this); + + // Draw an opaque texture with overridden alpha = 0.125 + // but with some rotation so it will use DrawArray. + canvas.save(); + canvas.rotate(30, 0, 0, 1); + canvas.drawTexture(texture_o, 100, 200, 300, 400, 0.125f); + canvas.restore(); + assertEquals(47, mGLBindTextureId); + assertEquals(0x20202020, mGLColor); + assertEquals(GL_MODULATE, getTexEnvi(GL_TEXTURE_ENV_MODE)); + assertPremultipliedBlending(this); + + // We have drawn seven textures above. + assertEquals(1, mDrawArrayCalled); + assertEquals(6, mDrawTexiOESCalled); + + // translate and scale does not affect whether we + // can use glDrawTexiOES, but rotate may. + canvas.translate(10, 20, 30); + canvas.drawTexture(texture, 100, 200, 300, 400); + assertEquals(7, mDrawTexiOESCalled); + + canvas.scale(10, 20, 30); + canvas.drawTexture(texture, 100, 200, 300, 400); + assertEquals(8, mDrawTexiOESCalled); + + canvas.rotate(90, 1, 2, 3); + canvas.drawTexture(texture, 100, 200, 300, 400); + assertEquals(8, mDrawTexiOESCalled); + + canvas.rotate(-90, 1, 2, 3); + canvas.drawTexture(texture, 100, 200, 300, 400); + assertEquals(9, mDrawTexiOESCalled); + + canvas.rotate(180, 0, 0, 1); + canvas.drawTexture(texture, 100, 200, 300, 400); + assertEquals(9, mDrawTexiOESCalled); + + canvas.rotate(180, 0, 0, 1); + canvas.drawTexture(texture, 100, 200, 300, 400); + assertEquals(10, mDrawTexiOESCalled); + + assertEquals(3, mDrawArrayCalled); + + assertTrue(texture.isLoaded(canvas)); + texture.recycle(); + assertFalse(texture.isLoaded(canvas)); + canvas.deleteRecycledResources(); + + assertTrue(texture_o.isLoaded(canvas)); + texture_o.recycle(); + assertFalse(texture_o.isLoaded(canvas)); + } + } + + private static class DrawTextureMixedTest extends GLMock { + + boolean mTexture2DEnabled0, mTexture2DEnabled1; + int mBindTexture0; + int mBindTexture1; + + @Override + public void glEnable(int cap) { + if (cap == GL_TEXTURE_2D) { + texture2DEnable(true); + } + } + + @Override + public void glDisable(int cap) { + if (cap == GL_TEXTURE_2D) { + texture2DEnable(false); + } + } + + private void texture2DEnable(boolean enable) { + if (mGLActiveTexture == GL_TEXTURE0) { + mTexture2DEnabled0 = enable; + } else if (mGLActiveTexture == GL_TEXTURE1) { + mTexture2DEnabled1 = enable; + } else { + fail(); + } + } + + @Override + public void glTexEnvfv(int target, int pname, float[] params, int offset) { + if (target == GL_TEXTURE_ENV && pname == GL_TEXTURE_ENV_COLOR) { + assertEquals(0.5f, params[offset + 3]); + } + } + + @Override + public void glBindTexture(int target, int texture) { + if (target == GL_TEXTURE_2D) { + if (mGLActiveTexture == GL_TEXTURE0) { + mBindTexture0 = texture; + } else if (mGLActiveTexture == GL_TEXTURE1) { + mBindTexture1 = texture; + } else { + fail(); + } + } + } + + void run() { + GLCanvas canvas = new GLCanvasImpl(this); + canvas.setSize(400, 300); + MyTexture from = new MyTexture(canvas, 42, false); // non-opaque + MyTexture to = new MyTexture(canvas, 47, true); // opaque + + canvas.drawMixed(from, to, 0.5f, 100, 200, 300, 400); + assertEquals(42, mBindTexture0); + assertEquals(47, mBindTexture1); + assertTrue(mTexture2DEnabled0); + assertFalse(mTexture2DEnabled1); + + assertEquals(GL_COMBINE, getTexEnvi(GL_TEXTURE1, GL_TEXTURE_ENV_MODE)); + assertEquals(GL_INTERPOLATE, getTexEnvi(GL_TEXTURE1, GL_COMBINE_RGB)); + assertEquals(GL_INTERPOLATE, getTexEnvi(GL_TEXTURE1, GL_COMBINE_ALPHA)); + assertEquals(GL_CONSTANT, getTexEnvi(GL_TEXTURE1, GL_SRC2_RGB)); + assertEquals(GL_CONSTANT, getTexEnvi(GL_TEXTURE1, GL_SRC2_ALPHA)); + assertEquals(GL_SRC_ALPHA, getTexEnvi(GL_TEXTURE1, GL_OPERAND2_RGB)); + assertEquals(GL_SRC_ALPHA, getTexEnvi(GL_TEXTURE1, GL_OPERAND2_ALPHA)); + + assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE0, GL_TEXTURE_ENV_MODE)); + + assertFalse(mGLBlendEnabled); + + canvas.drawMixed(from, to, 0, 100, 200, 300, 400); + assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE0, GL_TEXTURE_ENV_MODE)); + assertEquals(42, mBindTexture0); + + canvas.drawMixed(from, to, 1, 100, 200, 300, 400); + assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE0, GL_TEXTURE_ENV_MODE)); + assertEquals(47, mBindTexture0); + } + } + + @SmallTest + public void testGetGLInstance() { + GL11 glStub = new GLStub(); + GLCanvas canvas = new GLCanvasImpl(glStub); + assertSame(glStub, canvas.getGLInstance()); + } + + private static void assertPremultipliedBlending(GLMock mock) { + assertTrue(mock.mGLBlendFuncCalled > 0); + assertTrue(mock.mGLBlendEnabled); + assertEquals(GL11.GL_ONE, mock.mGLBlendFuncSFactor); + assertEquals(GL11.GL_ONE_MINUS_SRC_ALPHA, mock.mGLBlendFuncDFactor); + } + + private static void assertMatrixEq(float[] expected, float[] actual) { + try { + for (int i = 0; i < 16; i++) { + assertFloatEq(expected[i], actual[i]); + } + } catch (Throwable t) { + Log.v(TAG, "expected = " + Arrays.toString(expected) + + ", actual = " + Arrays.toString(actual)); + fail(); + } + } + + public static void assertFloatEq(float expected, float actual) { + if (Math.abs(actual - expected) > 1e-6) { + Log.v(TAG, "expected: " + expected + ", actual: " + actual); + fail(); + } + } +} diff --git a/tests/src/com/android/gallery3d/ui/GLMock.java b/tests/src/com/android/gallery3d/ui/GLMock.java new file mode 100644 index 000000000..c1fe53c62 --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/GLMock.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import java.nio.Buffer; +import java.util.HashMap; +import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.opengles.GL11; + +public class GLMock extends GLStub { + @SuppressWarnings("unused") + private static final String TAG = "GLMock"; + + // glClear + int mGLClearCalled; + int mGLClearMask; + // glBlendFunc + int mGLBlendFuncCalled; + int mGLBlendFuncSFactor; + int mGLBlendFuncDFactor; + // glColor4[fx] + int mGLColorCalled; + int mGLColor; + // glEnable, glDisable + boolean mGLBlendEnabled; + boolean mGLStencilEnabled; + // glEnableClientState + boolean mGLVertexArrayEnabled; + // glVertexPointer + PointerInfo mGLVertexPointer; + // glMatrixMode + int mGLMatrixMode = GL10.GL_MODELVIEW; + // glLoadMatrixf + float[] mGLModelViewMatrix = new float[16]; + float[] mGLProjectionMatrix = new float[16]; + // glBindTexture + int mGLBindTextureId; + // glTexEnvf + HashMap mGLTexEnv0 = new HashMap(); + HashMap mGLTexEnv1 = new HashMap(); + // glActiveTexture + int mGLActiveTexture = GL11.GL_TEXTURE0; + + @Override + public void glClear(int mask) { + mGLClearCalled++; + mGLClearMask = mask; + } + + @Override + public void glBlendFunc(int sfactor, int dfactor) { + mGLBlendFuncSFactor = sfactor; + mGLBlendFuncDFactor = dfactor; + mGLBlendFuncCalled++; + } + + @Override + public void glColor4f(float red, float green, float blue, + float alpha) { + mGLColorCalled++; + mGLColor = makeColor4f(red, green, blue, alpha); + } + + @Override + public void glColor4x(int red, int green, int blue, int alpha) { + mGLColorCalled++; + mGLColor = makeColor4x(red, green, blue, alpha); + } + + @Override + public void glEnable(int cap) { + if (cap == GL11.GL_BLEND) { + mGLBlendEnabled = true; + } else if (cap == GL11.GL_STENCIL_TEST) { + mGLStencilEnabled = true; + } + } + + @Override + public void glDisable(int cap) { + if (cap == GL11.GL_BLEND) { + mGLBlendEnabled = false; + } else if (cap == GL11.GL_STENCIL_TEST) { + mGLStencilEnabled = false; + } + } + + @Override + public void glEnableClientState(int array) { + if (array == GL10.GL_VERTEX_ARRAY) { + mGLVertexArrayEnabled = true; + } + } + + @Override + public void glVertexPointer(int size, int type, int stride, Buffer pointer) { + mGLVertexPointer = new PointerInfo(size, type, stride, pointer); + } + + @Override + public void glMatrixMode(int mode) { + mGLMatrixMode = mode; + } + + @Override + public void glLoadMatrixf(float[] m, int offset) { + if (mGLMatrixMode == GL10.GL_MODELVIEW) { + System.arraycopy(m, offset, mGLModelViewMatrix, 0, 16); + } else if (mGLMatrixMode == GL10.GL_PROJECTION) { + System.arraycopy(m, offset, mGLProjectionMatrix, 0, 16); + } + } + + @Override + public void glOrthof( + float left, float right, float bottom, float top, + float zNear, float zFar) { + float tx = -(right + left) / (right - left); + float ty = -(top + bottom) / (top - bottom); + float tz = - (zFar + zNear) / (zFar - zNear); + float[] m = new float[] { + 2 / (right - left), 0, 0, 0, + 0, 2 / (top - bottom), 0, 0, + 0, 0, -2 / (zFar - zNear), 0, + tx, ty, tz, 1 + }; + glLoadMatrixf(m, 0); + } + + @Override + public void glBindTexture(int target, int texture) { + if (target == GL11.GL_TEXTURE_2D) { + mGLBindTextureId = texture; + } + } + + @Override + public void glTexEnvf(int target, int pname, float param) { + if (target == GL11.GL_TEXTURE_ENV) { + if (mGLActiveTexture == GL11.GL_TEXTURE0) { + mGLTexEnv0.put(pname, param); + } else if (mGLActiveTexture == GL11.GL_TEXTURE1) { + mGLTexEnv1.put(pname, param); + } else { + throw new AssertionError(); + } + } + } + + public int getTexEnvi(int pname) { + return getTexEnvi(mGLActiveTexture, pname); + } + + public int getTexEnvi(int activeTexture, int pname) { + if (activeTexture == GL11.GL_TEXTURE0) { + return (int) mGLTexEnv0.get(pname).floatValue(); + } else if (activeTexture == GL11.GL_TEXTURE1) { + return (int) mGLTexEnv1.get(pname).floatValue(); + } else { + throw new AssertionError(); + } + } + + @Override + public void glActiveTexture(int texture) { + mGLActiveTexture = texture; + } + + public static int makeColor4f(float red, float green, float blue, + float alpha) { + return (Math.round(alpha * 255) << 24) | + (Math.round(red * 255) << 16) | + (Math.round(green * 255) << 8) | + Math.round(blue * 255); + } + + public static int makeColor4x(int red, int green, int blue, int alpha) { + final float X = 65536f; + return makeColor4f(red / X, green / X, blue / X, alpha / X); + } +} diff --git a/tests/src/com/android/gallery3d/ui/GLRootMock.java b/tests/src/com/android/gallery3d/ui/GLRootMock.java new file mode 100644 index 000000000..c83e94342 --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/GLRootMock.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import com.android.gallery3d.anim.CanvasAnimation; + +public class GLRootMock implements GLRoot { + int mRequestRenderCalled; + int mRequestLayoutContentPaneCalled; + + public void addOnGLIdleListener(OnGLIdleListener listener) {} + public void registerLaunchedAnimation(CanvasAnimation animation) {} + public void requestRender() { + mRequestRenderCalled++; + } + public void requestLayoutContentPane() { + mRequestLayoutContentPaneCalled++; + } + public boolean hasStencil() { return true; } + public void lockRenderThread() {} + public void unlockRenderThread() {} + public void setContentPane(GLView content) {} +} diff --git a/tests/src/com/android/gallery3d/ui/GLRootStub.java b/tests/src/com/android/gallery3d/ui/GLRootStub.java new file mode 100644 index 000000000..d6bc678d4 --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/GLRootStub.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import com.android.gallery3d.anim.CanvasAnimation; + +public class GLRootStub implements GLRoot { + public void addOnGLIdleListener(OnGLIdleListener listener) {} + public void registerLaunchedAnimation(CanvasAnimation animation) {} + public void requestRender() {} + public void requestLayoutContentPane() {} + public boolean hasStencil() { return true; } + public void lockRenderThread() {} + public void unlockRenderThread() {} + public void setContentPane(GLView content) {} +} diff --git a/tests/src/com/android/gallery3d/ui/GLStub.java b/tests/src/com/android/gallery3d/ui/GLStub.java new file mode 100644 index 000000000..2af73f905 --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/GLStub.java @@ -0,0 +1,1490 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import javax.microedition.khronos.opengles.GL; +import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.opengles.GL10Ext; +import javax.microedition.khronos.opengles.GL11; +import javax.microedition.khronos.opengles.GL11Ext; + +public class GLStub implements GL, GL10, GL10Ext, GL11, GL11Ext { + @SuppressWarnings("unused") + private static final String TAG = "GLStub"; + + public void glActiveTexture( + int texture + ){} + + public void glAlphaFunc( + int func, + float ref + ){} + + public void glAlphaFuncx( + int func, + int ref + ){} + + public void glBindTexture( + int target, + int texture + ){} + + public void glBlendFunc( + int sfactor, + int dfactor + ){} + + public void glClear( + int mask + ){} + + public void glClearColor( + float red, + float green, + float blue, + float alpha + ){} + + public void glClearColorx( + int red, + int green, + int blue, + int alpha + ){} + + public void glClearDepthf( + float depth + ){} + + public void glClearDepthx( + int depth + ){} + + public void glClearStencil( + int s + ){} + + public void glClientActiveTexture( + int texture + ){} + + public void glColor4f( + float red, + float green, + float blue, + float alpha + ){} + + public void glColor4x( + int red, + int green, + int blue, + int alpha + ){} + + public void glColorMask( + boolean red, + boolean green, + boolean blue, + boolean alpha + ){} + + public void glColorPointer( + int size, + int type, + int stride, + java.nio.Buffer pointer + ){} + + public void glCompressedTexImage2D( + int target, + int level, + int internalformat, + int width, + int height, + int border, + int imageSize, + java.nio.Buffer data + ){} + + public void glCompressedTexSubImage2D( + int target, + int level, + int xoffset, + int yoffset, + int width, + int height, + int format, + int imageSize, + java.nio.Buffer data + ){} + + public void glCopyTexImage2D( + int target, + int level, + int internalformat, + int x, + int y, + int width, + int height, + int border + ){} + + public void glCopyTexSubImage2D( + int target, + int level, + int xoffset, + int yoffset, + int x, + int y, + int width, + int height + ){} + + public void glCullFace( + int mode + ){} + + public void glDeleteTextures( + int n, + int[] textures, + int offset + ){} + + public void glDeleteTextures( + int n, + java.nio.IntBuffer textures + ){} + + public void glDepthFunc( + int func + ){} + + public void glDepthMask( + boolean flag + ){} + + public void glDepthRangef( + float zNear, + float zFar + ){} + + public void glDepthRangex( + int zNear, + int zFar + ){} + + public void glDisable( + int cap + ){} + + public void glDisableClientState( + int array + ){} + + public void glDrawArrays( + int mode, + int first, + int count + ){} + + public void glDrawElements( + int mode, + int count, + int type, + java.nio.Buffer indices + ){} + + public void glEnable( + int cap + ){} + + public void glEnableClientState( + int array + ){} + + public void glFinish( + ){} + + public void glFlush( + ){} + + public void glFogf( + int pname, + float param + ){} + + public void glFogfv( + int pname, + float[] params, + int offset + ){} + + public void glFogfv( + int pname, + java.nio.FloatBuffer params + ){} + + public void glFogx( + int pname, + int param + ){} + + public void glFogxv( + int pname, + int[] params, + int offset + ){} + + public void glFogxv( + int pname, + java.nio.IntBuffer params + ){} + + public void glFrontFace( + int mode + ){} + + public void glFrustumf( + float left, + float right, + float bottom, + float top, + float zNear, + float zFar + ){} + + public void glFrustumx( + int left, + int right, + int bottom, + int top, + int zNear, + int zFar + ){} + + public void glGenTextures( + int n, + int[] textures, + int offset + ){} + + public void glGenTextures( + int n, + java.nio.IntBuffer textures + ){} + + public int glGetError( + ){ throw new UnsupportedOperationException(); } + + public void glGetIntegerv( + int pname, + int[] params, + int offset + ){} + + public void glGetIntegerv( + int pname, + java.nio.IntBuffer params + ){} + + public String glGetString( + int name + ){ throw new UnsupportedOperationException(); } + + public void glHint( + int target, + int mode + ){} + + public void glLightModelf( + int pname, + float param + ){} + + public void glLightModelfv( + int pname, + float[] params, + int offset + ){} + + public void glLightModelfv( + int pname, + java.nio.FloatBuffer params + ){} + + public void glLightModelx( + int pname, + int param + ){} + + public void glLightModelxv( + int pname, + int[] params, + int offset + ){} + + public void glLightModelxv( + int pname, + java.nio.IntBuffer params + ){} + + public void glLightf( + int light, + int pname, + float param + ){} + + public void glLightfv( + int light, + int pname, + float[] params, + int offset + ){} + + public void glLightfv( + int light, + int pname, + java.nio.FloatBuffer params + ){} + + public void glLightx( + int light, + int pname, + int param + ){} + + public void glLightxv( + int light, + int pname, + int[] params, + int offset + ){} + + public void glLightxv( + int light, + int pname, + java.nio.IntBuffer params + ){} + + public void glLineWidth( + float width + ){} + + public void glLineWidthx( + int width + ){} + + public void glLoadIdentity( + ){} + + public void glLoadMatrixf( + float[] m, + int offset + ){} + + public void glLoadMatrixf( + java.nio.FloatBuffer m + ){} + + public void glLoadMatrixx( + int[] m, + int offset + ){} + + public void glLoadMatrixx( + java.nio.IntBuffer m + ){} + + public void glLogicOp( + int opcode + ){} + + public void glMaterialf( + int face, + int pname, + float param + ){} + + public void glMaterialfv( + int face, + int pname, + float[] params, + int offset + ){} + + public void glMaterialfv( + int face, + int pname, + java.nio.FloatBuffer params + ){} + + public void glMaterialx( + int face, + int pname, + int param + ){} + + public void glMaterialxv( + int face, + int pname, + int[] params, + int offset + ){} + + public void glMaterialxv( + int face, + int pname, + java.nio.IntBuffer params + ){} + + public void glMatrixMode( + int mode + ){} + + public void glMultMatrixf( + float[] m, + int offset + ){} + + public void glMultMatrixf( + java.nio.FloatBuffer m + ){} + + public void glMultMatrixx( + int[] m, + int offset + ){} + + public void glMultMatrixx( + java.nio.IntBuffer m + ){} + + public void glMultiTexCoord4f( + int target, + float s, + float t, + float r, + float q + ){} + + public void glMultiTexCoord4x( + int target, + int s, + int t, + int r, + int q + ){} + + public void glNormal3f( + float nx, + float ny, + float nz + ){} + + public void glNormal3x( + int nx, + int ny, + int nz + ){} + + public void glNormalPointer( + int type, + int stride, + java.nio.Buffer pointer + ){} + + public void glOrthof( + float left, + float right, + float bottom, + float top, + float zNear, + float zFar + ){} + + public void glOrthox( + int left, + int right, + int bottom, + int top, + int zNear, + int zFar + ){} + + public void glPixelStorei( + int pname, + int param + ){} + + public void glPointSize( + float size + ){} + + public void glPointSizex( + int size + ){} + + public void glPolygonOffset( + float factor, + float units + ){} + + public void glPolygonOffsetx( + int factor, + int units + ){} + + public void glPopMatrix( + ){} + + public void glPushMatrix( + ){} + + public void glReadPixels( + int x, + int y, + int width, + int height, + int format, + int type, + java.nio.Buffer pixels + ){} + + public void glRotatef( + float angle, + float x, + float y, + float z + ){} + + public void glRotatex( + int angle, + int x, + int y, + int z + ){} + + public void glSampleCoverage( + float value, + boolean invert + ){} + + public void glSampleCoveragex( + int value, + boolean invert + ){} + + public void glScalef( + float x, + float y, + float z + ){} + + public void glScalex( + int x, + int y, + int z + ){} + + public void glScissor( + int x, + int y, + int width, + int height + ){} + + public void glShadeModel( + int mode + ){} + + public void glStencilFunc( + int func, + int ref, + int mask + ){} + + public void glStencilMask( + int mask + ){} + + public void glStencilOp( + int fail, + int zfail, + int zpass + ){} + + public void glTexCoordPointer( + int size, + int type, + int stride, + java.nio.Buffer pointer + ){} + + public void glTexEnvf( + int target, + int pname, + float param + ){} + + public void glTexEnvfv( + int target, + int pname, + float[] params, + int offset + ){} + + public void glTexEnvfv( + int target, + int pname, + java.nio.FloatBuffer params + ){} + + public void glTexEnvx( + int target, + int pname, + int param + ){} + + public void glTexEnvxv( + int target, + int pname, + int[] params, + int offset + ){} + + public void glTexEnvxv( + int target, + int pname, + java.nio.IntBuffer params + ){} + + public void glTexImage2D( + int target, + int level, + int internalformat, + int width, + int height, + int border, + int format, + int type, + java.nio.Buffer pixels + ){} + + public void glTexParameterf( + int target, + int pname, + float param + ){} + + public void glTexParameterx( + int target, + int pname, + int param + ){} + + public void glTexSubImage2D( + int target, + int level, + int xoffset, + int yoffset, + int width, + int height, + int format, + int type, + java.nio.Buffer pixels + ){} + + public void glTranslatef( + float x, + float y, + float z + ){} + + public void glTranslatex( + int x, + int y, + int z + ){} + + public void glVertexPointer( + int size, + int type, + int stride, + java.nio.Buffer pointer + ){} + + public void glViewport( + int x, + int y, + int width, + int height + ){} + + public int glQueryMatrixxOES( + int[] mantissa, + int mantissaOffset, + int[] exponent, + int exponentOffset + ){ throw new UnsupportedOperationException(); } + + public int glQueryMatrixxOES( + java.nio.IntBuffer mantissa, + java.nio.IntBuffer exponent + ){ throw new UnsupportedOperationException(); } + + public void glGetPointerv(int pname, java.nio.Buffer[] params){} + public void glBindBuffer( + int target, + int buffer + ){} + + public void glBufferData( + int target, + int size, + java.nio.Buffer data, + int usage + ){} + + public void glBufferSubData( + int target, + int offset, + int size, + java.nio.Buffer data + ){} + + public void glClipPlanef( + int plane, + float[] equation, + int offset + ){} + + public void glClipPlanef( + int plane, + java.nio.FloatBuffer equation + ){} + + public void glClipPlanex( + int plane, + int[] equation, + int offset + ){} + + public void glClipPlanex( + int plane, + java.nio.IntBuffer equation + ){} + + public void glColor4ub( + byte red, + byte green, + byte blue, + byte alpha + ){} + + public void glColorPointer( + int size, + int type, + int stride, + int offset + ){} + + public void glDeleteBuffers( + int n, + int[] buffers, + int offset + ){} + + public void glDeleteBuffers( + int n, + java.nio.IntBuffer buffers + ){} + + public void glDrawElements( + int mode, + int count, + int type, + int offset + ){} + + public void glGenBuffers( + int n, + int[] buffers, + int offset + ){} + + public void glGenBuffers( + int n, + java.nio.IntBuffer buffers + ){} + + public void glGetBooleanv( + int pname, + boolean[] params, + int offset + ){} + + public void glGetBooleanv( + int pname, + java.nio.IntBuffer params + ){} + + public void glGetBufferParameteriv( + int target, + int pname, + int[] params, + int offset + ){} + + public void glGetBufferParameteriv( + int target, + int pname, + java.nio.IntBuffer params + ){} + + public void glGetClipPlanef( + int pname, + float[] eqn, + int offset + ){} + + public void glGetClipPlanef( + int pname, + java.nio.FloatBuffer eqn + ){} + + public void glGetClipPlanex( + int pname, + int[] eqn, + int offset + ){} + + public void glGetClipPlanex( + int pname, + java.nio.IntBuffer eqn + ){} + + public void glGetFixedv( + int pname, + int[] params, + int offset + ){} + + public void glGetFixedv( + int pname, + java.nio.IntBuffer params + ){} + + public void glGetFloatv( + int pname, + float[] params, + int offset + ){} + + public void glGetFloatv( + int pname, + java.nio.FloatBuffer params + ){} + + public void glGetLightfv( + int light, + int pname, + float[] params, + int offset + ){} + + public void glGetLightfv( + int light, + int pname, + java.nio.FloatBuffer params + ){} + + public void glGetLightxv( + int light, + int pname, + int[] params, + int offset + ){} + + public void glGetLightxv( + int light, + int pname, + java.nio.IntBuffer params + ){} + + public void glGetMaterialfv( + int face, + int pname, + float[] params, + int offset + ){} + + public void glGetMaterialfv( + int face, + int pname, + java.nio.FloatBuffer params + ){} + + public void glGetMaterialxv( + int face, + int pname, + int[] params, + int offset + ){} + + public void glGetMaterialxv( + int face, + int pname, + java.nio.IntBuffer params + ){} + + public void glGetTexEnviv( + int env, + int pname, + int[] params, + int offset + ){} + + public void glGetTexEnviv( + int env, + int pname, + java.nio.IntBuffer params + ){} + + public void glGetTexEnvxv( + int env, + int pname, + int[] params, + int offset + ){} + + public void glGetTexEnvxv( + int env, + int pname, + java.nio.IntBuffer params + ){} + + public void glGetTexParameterfv( + int target, + int pname, + float[] params, + int offset + ){} + + public void glGetTexParameterfv( + int target, + int pname, + java.nio.FloatBuffer params + ){} + + public void glGetTexParameteriv( + int target, + int pname, + int[] params, + int offset + ){} + + public void glGetTexParameteriv( + int target, + int pname, + java.nio.IntBuffer params + ){} + + public void glGetTexParameterxv( + int target, + int pname, + int[] params, + int offset + ){} + + public void glGetTexParameterxv( + int target, + int pname, + java.nio.IntBuffer params + ){} + + public boolean glIsBuffer( + int buffer + ){ throw new UnsupportedOperationException(); } + + public boolean glIsEnabled( + int cap + ){ throw new UnsupportedOperationException(); } + + public boolean glIsTexture( + int texture + ){ throw new UnsupportedOperationException(); } + + public void glNormalPointer( + int type, + int stride, + int offset + ){} + + public void glPointParameterf( + int pname, + float param + ){} + + public void glPointParameterfv( + int pname, + float[] params, + int offset + ){} + + public void glPointParameterfv( + int pname, + java.nio.FloatBuffer params + ){} + + public void glPointParameterx( + int pname, + int param + ){} + + public void glPointParameterxv( + int pname, + int[] params, + int offset + ){} + + public void glPointParameterxv( + int pname, + java.nio.IntBuffer params + ){} + + public void glPointSizePointerOES( + int type, + int stride, + java.nio.Buffer pointer + ){} + + public void glTexCoordPointer( + int size, + int type, + int stride, + int offset + ){} + + public void glTexEnvi( + int target, + int pname, + int param + ){} + + public void glTexEnviv( + int target, + int pname, + int[] params, + int offset + ){} + + public void glTexEnviv( + int target, + int pname, + java.nio.IntBuffer params + ){} + + public void glTexParameterfv( + int target, + int pname, + float[] params, + int offset + ){} + + public void glTexParameterfv( + int target, + int pname, + java.nio.FloatBuffer params + ){} + + public void glTexParameteri( + int target, + int pname, + int param + ){} + + public void glTexParameteriv( + int target, + int pname, + int[] params, + int offset + ){} + + public void glTexParameteriv( + int target, + int pname, + java.nio.IntBuffer params + ){} + + public void glTexParameterxv( + int target, + int pname, + int[] params, + int offset + ){} + + public void glTexParameterxv( + int target, + int pname, + java.nio.IntBuffer params + ){} + + public void glVertexPointer( + int size, + int type, + int stride, + int offset + ){} + + public void glCurrentPaletteMatrixOES( + int matrixpaletteindex + ){} + + public void glDrawTexfOES( + float x, + float y, + float z, + float width, + float height + ){} + + public void glDrawTexfvOES( + float[] coords, + int offset + ){} + + public void glDrawTexfvOES( + java.nio.FloatBuffer coords + ){} + + public void glDrawTexiOES( + int x, + int y, + int z, + int width, + int height + ){} + + public void glDrawTexivOES( + int[] coords, + int offset + ){} + + public void glDrawTexivOES( + java.nio.IntBuffer coords + ){} + + public void glDrawTexsOES( + short x, + short y, + short z, + short width, + short height + ){} + + public void glDrawTexsvOES( + short[] coords, + int offset + ){} + + public void glDrawTexsvOES( + java.nio.ShortBuffer coords + ){} + + public void glDrawTexxOES( + int x, + int y, + int z, + int width, + int height + ){} + + public void glDrawTexxvOES( + int[] coords, + int offset + ){} + + public void glDrawTexxvOES( + java.nio.IntBuffer coords + ){} + + public void glLoadPaletteFromModelViewMatrixOES( + ){} + + public void glMatrixIndexPointerOES( + int size, + int type, + int stride, + java.nio.Buffer pointer + ){} + + public void glMatrixIndexPointerOES( + int size, + int type, + int stride, + int offset + ){} + + public void glWeightPointerOES( + int size, + int type, + int stride, + java.nio.Buffer pointer + ){} + + public void glWeightPointerOES( + int size, + int type, + int stride, + int offset + ){} + + public void glBindFramebufferOES( + int target, + int framebuffer + ){} + + public void glBindRenderbufferOES( + int target, + int renderbuffer + ){} + + public void glBlendEquation( + int mode + ){} + + public void glBlendEquationSeparate( + int modeRGB, + int modeAlpha + ){} + + public void glBlendFuncSeparate( + int srcRGB, + int dstRGB, + int srcAlpha, + int dstAlpha + ){} + + public int glCheckFramebufferStatusOES( + int target + ){ throw new UnsupportedOperationException(); } + + public void glDeleteFramebuffersOES( + int n, + int[] framebuffers, + int offset + ){} + + public void glDeleteFramebuffersOES( + int n, + java.nio.IntBuffer framebuffers + ){} + + public void glDeleteRenderbuffersOES( + int n, + int[] renderbuffers, + int offset + ){} + + public void glDeleteRenderbuffersOES( + int n, + java.nio.IntBuffer renderbuffers + ){} + + public void glFramebufferRenderbufferOES( + int target, + int attachment, + int renderbuffertarget, + int renderbuffer + ){} + + public void glFramebufferTexture2DOES( + int target, + int attachment, + int textarget, + int texture, + int level + ){} + + public void glGenerateMipmapOES( + int target + ){} + + public void glGenFramebuffersOES( + int n, + int[] framebuffers, + int offset + ){} + + public void glGenFramebuffersOES( + int n, + java.nio.IntBuffer framebuffers + ){} + + public void glGenRenderbuffersOES( + int n, + int[] renderbuffers, + int offset + ){} + + public void glGenRenderbuffersOES( + int n, + java.nio.IntBuffer renderbuffers + ){} + + public void glGetFramebufferAttachmentParameterivOES( + int target, + int attachment, + int pname, + int[] params, + int offset + ){} + + public void glGetFramebufferAttachmentParameterivOES( + int target, + int attachment, + int pname, + java.nio.IntBuffer params + ){} + + public void glGetRenderbufferParameterivOES( + int target, + int pname, + int[] params, + int offset + ){} + + public void glGetRenderbufferParameterivOES( + int target, + int pname, + java.nio.IntBuffer params + ){} + + public void glGetTexGenfv( + int coord, + int pname, + float[] params, + int offset + ){} + + public void glGetTexGenfv( + int coord, + int pname, + java.nio.FloatBuffer params + ){} + + public void glGetTexGeniv( + int coord, + int pname, + int[] params, + int offset + ){} + + public void glGetTexGeniv( + int coord, + int pname, + java.nio.IntBuffer params + ){} + + public void glGetTexGenxv( + int coord, + int pname, + int[] params, + int offset + ){} + + public void glGetTexGenxv( + int coord, + int pname, + java.nio.IntBuffer params + ){} + + public boolean glIsFramebufferOES( + int framebuffer + ){ throw new UnsupportedOperationException(); } + + public boolean glIsRenderbufferOES( + int renderbuffer + ){ throw new UnsupportedOperationException(); } + + public void glRenderbufferStorageOES( + int target, + int internalformat, + int width, + int height + ){} + + public void glTexGenf( + int coord, + int pname, + float param + ){} + + public void glTexGenfv( + int coord, + int pname, + float[] params, + int offset + ){} + + public void glTexGenfv( + int coord, + int pname, + java.nio.FloatBuffer params + ){} + + public void glTexGeni( + int coord, + int pname, + int param + ){} + + public void glTexGeniv( + int coord, + int pname, + int[] params, + int offset + ){} + + public void glTexGeniv( + int coord, + int pname, + java.nio.IntBuffer params + ){} + + public void glTexGenx( + int coord, + int pname, + int param + ){} + + public void glTexGenxv( + int coord, + int pname, + int[] params, + int offset + ){} + + public void glTexGenxv( + int coord, + int pname, + java.nio.IntBuffer params + ){} +} diff --git a/tests/src/com/android/gallery3d/ui/GLViewMock.java b/tests/src/com/android/gallery3d/ui/GLViewMock.java new file mode 100644 index 000000000..7b941daad --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/GLViewMock.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +class GLViewMock extends GLView { + // onAttachToRoot + int mOnAttachCalled; + GLRoot mRoot; + // onDetachFromRoot + int mOnDetachCalled; + // onVisibilityChanged + int mOnVisibilityChangedCalled; + // onLayout + int mOnLayoutCalled; + boolean mOnLayoutChangeSize; + // renderBackground + int mRenderBackgroundCalled; + // onMeasure + int mOnMeasureCalled; + int mOnMeasureWidthSpec; + int mOnMeasureHeightSpec; + + @Override + public void onAttachToRoot(GLRoot root) { + mRoot = root; + mOnAttachCalled++; + super.onAttachToRoot(root); + } + + @Override + public void onDetachFromRoot() { + mRoot = null; + mOnDetachCalled++; + super.onDetachFromRoot(); + } + + @Override + protected void onVisibilityChanged(int visibility) { + mOnVisibilityChangedCalled++; + } + + @Override + protected void onLayout(boolean changeSize, int left, int top, + int right, int bottom) { + mOnLayoutCalled++; + mOnLayoutChangeSize = changeSize; + // call children's layout. + for (int i = 0, n = getComponentCount(); i < n; ++i) { + GLView item = getComponent(i); + item.layout(left, top, right, bottom); + } + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + mOnMeasureCalled++; + mOnMeasureWidthSpec = widthSpec; + mOnMeasureHeightSpec = heightSpec; + // call children's measure. + for (int i = 0, n = getComponentCount(); i < n; ++i) { + GLView item = getComponent(i); + item.measure(widthSpec, heightSpec); + } + setMeasuredSize(widthSpec, heightSpec); + } + + @Override + protected void renderBackground(GLCanvas view) { + mRenderBackgroundCalled++; + } +} diff --git a/tests/src/com/android/gallery3d/ui/GLViewTest.java b/tests/src/com/android/gallery3d/ui/GLViewTest.java new file mode 100644 index 000000000..a9377bfee --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/GLViewTest.java @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import android.graphics.Rect; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.MotionEvent; + +import junit.framework.TestCase; + +@SmallTest +public class GLViewTest extends TestCase { + @SuppressWarnings("unused") + private static final String TAG = "GLViewTest"; + + @SmallTest + public void testVisibility() { + GLViewMock a = new GLViewMock(); + assertEquals(GLView.VISIBLE, a.getVisibility()); + assertEquals(0, a.mOnVisibilityChangedCalled); + a.setVisibility(GLView.INVISIBLE); + assertEquals(GLView.INVISIBLE, a.getVisibility()); + assertEquals(1, a.mOnVisibilityChangedCalled); + a.setVisibility(GLView.VISIBLE); + assertEquals(GLView.VISIBLE, a.getVisibility()); + assertEquals(2, a.mOnVisibilityChangedCalled); + } + + @SmallTest + public void testComponents() { + GLView view = new GLView(); + assertEquals(0, view.getComponentCount()); + try { + view.getComponent(0); + fail(); + } catch (IndexOutOfBoundsException ex) { + // expected + } + + GLView x = new GLView(); + GLView y = new GLView(); + view.addComponent(x); + view.addComponent(y); + assertEquals(2, view.getComponentCount()); + assertSame(x, view.getComponent(0)); + assertSame(y, view.getComponent(1)); + view.removeComponent(x); + assertSame(y, view.getComponent(0)); + try { + view.getComponent(1); + fail(); + } catch (IndexOutOfBoundsException ex) { + // expected + } + try { + view.addComponent(y); + fail(); + } catch (IllegalStateException ex) { + // expected + } + view.addComponent(x); + view.removeAllComponents(); + assertEquals(0, view.getComponentCount()); + } + + @SmallTest + public void testBounds() { + GLView view = new GLView(); + + assertEquals(0, view.getWidth()); + assertEquals(0, view.getHeight()); + + Rect b = view.bounds(); + assertEquals(0, b.left); + assertEquals(0, b.top); + assertEquals(0, b.right); + assertEquals(0, b.bottom); + + view.layout(10, 20, 30, 100); + assertEquals(20, view.getWidth()); + assertEquals(80, view.getHeight()); + + b = view.bounds(); + assertEquals(10, b.left); + assertEquals(20, b.top); + assertEquals(30, b.right); + assertEquals(100, b.bottom); + } + + @SmallTest + public void testPaddings() { + GLView view = new GLView(); + + Rect p = view.getPaddings(); + assertEquals(0, p.left); + assertEquals(0, p.top); + assertEquals(0, p.right); + assertEquals(0, p.bottom); + + view.setPaddings(10, 20, 30, 100); + p = view.getPaddings(); + assertEquals(10, p.left); + assertEquals(20, p.top); + assertEquals(30, p.right); + assertEquals(100, p.bottom); + + p = new Rect(11, 22, 33, 104); + view.setPaddings(p); + p = view.getPaddings(); + assertEquals(11, p.left); + assertEquals(22, p.top); + assertEquals(33, p.right); + assertEquals(104, p.bottom); + } + + @SmallTest + public void testParent() { + GLView a = new GLView(); + GLView b = new GLView(); + assertNull(b.mParent); + a.addComponent(b); + assertSame(a, b.mParent); + a.removeComponent(b); + assertNull(b.mParent); + } + + @SmallTest + public void testRoot() { + GLViewMock a = new GLViewMock(); + GLViewMock b = new GLViewMock(); + GLRoot r = new GLRootStub(); + GLRoot r2 = new GLRootStub(); + a.addComponent(b); + + // Attach to root r + assertEquals(0, a.mOnAttachCalled); + assertEquals(0, b.mOnAttachCalled); + a.attachToRoot(r); + assertEquals(1, a.mOnAttachCalled); + assertEquals(1, b.mOnAttachCalled); + assertSame(r, a.getGLRoot()); + assertSame(r, b.getGLRoot()); + + // Detach from r + assertEquals(0, a.mOnDetachCalled); + assertEquals(0, b.mOnDetachCalled); + a.detachFromRoot(); + assertEquals(1, a.mOnDetachCalled); + assertEquals(1, b.mOnDetachCalled); + + // Attach to another root r2 + assertEquals(1, a.mOnAttachCalled); + assertEquals(1, b.mOnAttachCalled); + a.attachToRoot(r2); + assertEquals(2, a.mOnAttachCalled); + assertEquals(2, b.mOnAttachCalled); + assertSame(r2, a.getGLRoot()); + assertSame(r2, b.getGLRoot()); + + // Detach from r2 + assertEquals(1, a.mOnDetachCalled); + assertEquals(1, b.mOnDetachCalled); + a.detachFromRoot(); + assertEquals(2, a.mOnDetachCalled); + assertEquals(2, b.mOnDetachCalled); + } + + @SmallTest + public void testRoot2() { + GLView a = new GLViewMock(); + GLViewMock b = new GLViewMock(); + GLRoot r = new GLRootStub(); + + a.attachToRoot(r); + + assertEquals(0, b.mOnAttachCalled); + a.addComponent(b); + assertEquals(1, b.mOnAttachCalled); + + assertEquals(0, b.mOnDetachCalled); + a.removeComponent(b); + assertEquals(1, b.mOnDetachCalled); + } + + @SmallTest + public void testInvalidate() { + GLView a = new GLView(); + GLRootMock r = new GLRootMock(); + a.attachToRoot(r); + assertEquals(0, r.mRequestRenderCalled); + a.invalidate(); + assertEquals(1, r.mRequestRenderCalled); + } + + @SmallTest + public void testRequestLayout() { + GLView a = new GLView(); + GLView b = new GLView(); + GLRootMock r = new GLRootMock(); + a.attachToRoot(r); + a.addComponent(b); + assertEquals(0, r.mRequestLayoutContentPaneCalled); + b.requestLayout(); + assertEquals(1, r.mRequestLayoutContentPaneCalled); + } + + @SmallTest + public void testLayout() { + GLViewMock a = new GLViewMock(); + GLViewMock b = new GLViewMock(); + GLViewMock c = new GLViewMock(); + GLRootMock r = new GLRootMock(); + + a.attachToRoot(r); + a.addComponent(b); + a.addComponent(c); + + assertEquals(0, a.mOnLayoutCalled); + a.layout(10, 20, 60, 100); + assertEquals(1, a.mOnLayoutCalled); + assertEquals(1, b.mOnLayoutCalled); + assertEquals(1, c.mOnLayoutCalled); + assertTrue(a.mOnLayoutChangeSize); + assertTrue(b.mOnLayoutChangeSize); + assertTrue(c.mOnLayoutChangeSize); + + // same size should not trigger onLayout + a.layout(10, 20, 60, 100); + assertEquals(1, a.mOnLayoutCalled); + + // unless someone requested it, but only those on the path + // to the requester. + assertEquals(0, r.mRequestLayoutContentPaneCalled); + b.requestLayout(); + a.layout(10, 20, 60, 100); + assertEquals(1, r.mRequestLayoutContentPaneCalled); + assertEquals(2, a.mOnLayoutCalled); + assertEquals(2, b.mOnLayoutCalled); + assertEquals(1, c.mOnLayoutCalled); + } + + @SmallTest + public void testRender() { + GLViewMock a = new GLViewMock(); + GLViewMock b = new GLViewMock(); + + a.addComponent(b); + GLCanvasStub canvas = new GLCanvasStub(); + assertEquals(0, a.mRenderBackgroundCalled); + assertEquals(0, b.mRenderBackgroundCalled); + a.render(canvas); + assertEquals(1, a.mRenderBackgroundCalled); + assertEquals(1, b.mRenderBackgroundCalled); + } + + @SmallTest + public void testMeasure() { + GLViewMock a = new GLViewMock(); + GLViewMock b = new GLViewMock(); + GLViewMock c = new GLViewMock(); + GLRootMock r = new GLRootMock(); + + a.addComponent(b); + a.addComponent(c); + a.attachToRoot(r); + + assertEquals(0, a.mOnMeasureCalled); + a.measure(100, 200); + assertEquals(1, a.mOnMeasureCalled); + assertEquals(1, b.mOnMeasureCalled); + assertEquals(100, a.mOnMeasureWidthSpec); + assertEquals(200, a.mOnMeasureHeightSpec); + assertEquals(100, b.mOnMeasureWidthSpec); + assertEquals(200, b.mOnMeasureHeightSpec); + assertEquals(100, a.getMeasuredWidth()); + assertEquals(200, b.getMeasuredHeight()); + + // same spec should not trigger onMeasure + a.measure(100, 200); + assertEquals(1, a.mOnMeasureCalled); + + // unless someone requested it, but only those on the path + // to the requester. + b.requestLayout(); + a.measure(100, 200); + assertEquals(2, a.mOnMeasureCalled); + assertEquals(2, b.mOnMeasureCalled); + assertEquals(1, c.mOnMeasureCalled); + } + + class MyGLView extends GLView { + private int mWidth; + int mOnTouchCalled; + int mOnTouchX; + int mOnTouchY; + int mOnTouchAction; + + public MyGLView(int width) { + mWidth = width; + } + + @Override + protected void onLayout(boolean changeSize, int left, int top, + int right, int bottom) { + // layout children from left to right + // call children's layout. + int x = 0; + for (int i = 0, n = getComponentCount(); i < n; ++i) { + GLView item = getComponent(i); + item.measure(0, 0); + int w = item.getMeasuredWidth(); + int h = item.getMeasuredHeight(); + item.layout(x, 0, x + w, h); + x += w; + } + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + setMeasuredSize(mWidth, 100); + } + + @Override + protected boolean onTouch(MotionEvent event) { + mOnTouchCalled++; + mOnTouchX = (int) event.getX(); + mOnTouchY = (int) event.getY(); + mOnTouchAction = event.getAction(); + return true; + } + } + + private MotionEvent NewMotionEvent(int action, int x, int y) { + return MotionEvent.obtain(0, 0, action, x, y, 0); + } + + @SmallTest + public void testTouchEvent() { + // We construct a tree with four nodes. Only the x coordinate is used: + // A = [0..............................300) + // B = [0......100) + // C = [100......200) + // D = [100..150) + + MyGLView a = new MyGLView(300); + MyGLView b = new MyGLView(100); + MyGLView c = new MyGLView(100); + MyGLView d = new MyGLView(50); + GLRoot r = new GLRootStub(); + + a.addComponent(b); + a.addComponent(c); + c.addComponent(d); + a.attachToRoot(r); + a.layout(0, 0, 300, 100); + + int DOWN = MotionEvent.ACTION_DOWN; + int UP = MotionEvent.ACTION_UP; + int MOVE = MotionEvent.ACTION_MOVE; + int CANCEL = MotionEvent.ACTION_CANCEL; + + // simple case + assertEquals(0, a.mOnTouchCalled); + a.dispatchTouchEvent(NewMotionEvent(DOWN, 250, 0)); + assertEquals(DOWN, a.mOnTouchAction); + a.dispatchTouchEvent(NewMotionEvent(UP, 250, 0)); + assertEquals(UP, a.mOnTouchAction); + assertEquals(2, a.mOnTouchCalled); + + // pass to a child, check the location is offseted. + assertEquals(0, c.mOnTouchCalled); + a.dispatchTouchEvent(NewMotionEvent(DOWN, 175, 0)); + a.dispatchTouchEvent(NewMotionEvent(UP, 175, 0)); + assertEquals(75, c.mOnTouchX); + assertEquals(0, c.mOnTouchY); + assertEquals(2, c.mOnTouchCalled); + assertEquals(2, a.mOnTouchCalled); + + // motion target cancel event + assertEquals(0, d.mOnTouchCalled); + a.dispatchTouchEvent(NewMotionEvent(DOWN, 125, 0)); + assertEquals(1, d.mOnTouchCalled); + a.dispatchTouchEvent(NewMotionEvent(MOVE, 250, 0)); + assertEquals(2, d.mOnTouchCalled); + a.dispatchTouchEvent(NewMotionEvent(MOVE, 50, 0)); + assertEquals(3, d.mOnTouchCalled); + a.dispatchTouchEvent(NewMotionEvent(DOWN, 175, 0)); + assertEquals(4, d.mOnTouchCalled); + assertEquals(CANCEL, d.mOnTouchAction); + assertEquals(3, c.mOnTouchCalled); + assertEquals(DOWN, c.mOnTouchAction); + a.dispatchTouchEvent(NewMotionEvent(UP, 175, 0)); + + // motion target is removed + assertEquals(4, d.mOnTouchCalled); + a.dispatchTouchEvent(NewMotionEvent(DOWN, 125, 0)); + assertEquals(5, d.mOnTouchCalled); + a.removeComponent(c); + assertEquals(6, d.mOnTouchCalled); + assertEquals(CANCEL, d.mOnTouchAction); + + // invisible component should not get events + assertEquals(2, a.mOnTouchCalled); + assertEquals(0, b.mOnTouchCalled); + b.setVisibility(GLView.INVISIBLE); + a.dispatchTouchEvent(NewMotionEvent(DOWN, 50, 0)); + assertEquals(3, a.mOnTouchCalled); + assertEquals(0, b.mOnTouchCalled); + } +} diff --git a/tests/src/com/android/gallery3d/ui/PointerInfo.java b/tests/src/com/android/gallery3d/ui/PointerInfo.java new file mode 100644 index 000000000..6c78556e1 --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/PointerInfo.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.DoubleBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.nio.ShortBuffer; + +import javax.microedition.khronos.opengles.GL10; + +public class PointerInfo { + + /** + * The number of coordinates per vertex. 1..4 + */ + public int mSize; + + /** + * The type of each coordinate. + */ + public int mType; + + /** + * The byte offset between consecutive vertices. 0 means mSize * + * sizeof(mType) + */ + public int mStride; + public Buffer mPointer; + public ByteBuffer mTempByteBuffer; + + public PointerInfo(int size, int type, int stride, Buffer pointer) { + mSize = size; + mType = type; + mStride = stride; + mPointer = pointer; + } + + private int getStride() { + return mStride > 0 ? mStride : sizeof(mType) * mSize; + } + + public void bindByteBuffer() { + mTempByteBuffer = mPointer == null ? null : toByteBuffer(-1, mPointer); + } + + public void unbindByteBuffer() { + mTempByteBuffer = null; + } + + private static int sizeof(int type) { + switch (type) { + case GL10.GL_UNSIGNED_BYTE: + return 1; + case GL10.GL_BYTE: + return 1; + case GL10.GL_SHORT: + return 2; + case GL10.GL_FIXED: + return 4; + case GL10.GL_FLOAT: + return 4; + default: + return 0; + } + } + + private static ByteBuffer toByteBuffer(int byteCount, Buffer input) { + ByteBuffer result = null; + boolean convertWholeBuffer = (byteCount < 0); + if (input instanceof ByteBuffer) { + ByteBuffer input2 = (ByteBuffer) input; + int position = input2.position(); + if (convertWholeBuffer) { + byteCount = input2.limit() - position; + } + result = ByteBuffer.allocate(byteCount).order(input2.order()); + for (int i = 0; i < byteCount; i++) { + result.put(input2.get()); + } + input2.position(position); + } else if (input instanceof CharBuffer) { + CharBuffer input2 = (CharBuffer) input; + int position = input2.position(); + if (convertWholeBuffer) { + byteCount = (input2.limit() - position) * 2; + } + result = ByteBuffer.allocate(byteCount).order(input2.order()); + CharBuffer result2 = result.asCharBuffer(); + for (int i = 0; i < byteCount / 2; i++) { + result2.put(input2.get()); + } + input2.position(position); + } else if (input instanceof ShortBuffer) { + ShortBuffer input2 = (ShortBuffer) input; + int position = input2.position(); + if (convertWholeBuffer) { + byteCount = (input2.limit() - position)* 2; + } + result = ByteBuffer.allocate(byteCount).order(input2.order()); + ShortBuffer result2 = result.asShortBuffer(); + for (int i = 0; i < byteCount / 2; i++) { + result2.put(input2.get()); + } + input2.position(position); + } else if (input instanceof IntBuffer) { + IntBuffer input2 = (IntBuffer) input; + int position = input2.position(); + if (convertWholeBuffer) { + byteCount = (input2.limit() - position) * 4; + } + result = ByteBuffer.allocate(byteCount).order(input2.order()); + IntBuffer result2 = result.asIntBuffer(); + for (int i = 0; i < byteCount / 4; i++) { + result2.put(input2.get()); + } + input2.position(position); + } else if (input instanceof FloatBuffer) { + FloatBuffer input2 = (FloatBuffer) input; + int position = input2.position(); + if (convertWholeBuffer) { + byteCount = (input2.limit() - position) * 4; + } + result = ByteBuffer.allocate(byteCount).order(input2.order()); + FloatBuffer result2 = result.asFloatBuffer(); + for (int i = 0; i < byteCount / 4; i++) { + result2.put(input2.get()); + } + input2.position(position); + } else if (input instanceof DoubleBuffer) { + DoubleBuffer input2 = (DoubleBuffer) input; + int position = input2.position(); + if (convertWholeBuffer) { + byteCount = (input2.limit() - position) * 8; + } + result = ByteBuffer.allocate(byteCount).order(input2.order()); + DoubleBuffer result2 = result.asDoubleBuffer(); + for (int i = 0; i < byteCount / 8; i++) { + result2.put(input2.get()); + } + input2.position(position); + } else if (input instanceof LongBuffer) { + LongBuffer input2 = (LongBuffer) input; + int position = input2.position(); + if (convertWholeBuffer) { + byteCount = (input2.limit() - position) * 8; + } + result = ByteBuffer.allocate(byteCount).order(input2.order()); + LongBuffer result2 = result.asLongBuffer(); + for (int i = 0; i < byteCount / 8; i++) { + result2.put(input2.get()); + } + input2.position(position); + } else { + throw new RuntimeException("Unimplemented Buffer subclass."); + } + result.rewind(); + // The OpenGL API will interpret the result in hardware byte order, + // so we better do that as well: + result.order(ByteOrder.nativeOrder()); + return result; + } + + public void getArrayElement(int index, double[] result) { + if (mTempByteBuffer == null) { + throw new IllegalArgumentException("undefined pointer"); + } + if (mStride < 0) { + throw new IllegalArgumentException("invalid stride"); + } + + int stride = getStride(); + ByteBuffer byteBuffer = mTempByteBuffer; + int size = mSize; + int type = mType; + int sizeofType = sizeof(type); + int byteOffset = stride * index; + + for (int i = 0; i < size; i++) { + switch (type) { + case GL10.GL_BYTE: + case GL10.GL_UNSIGNED_BYTE: + result[i] = byteBuffer.get(byteOffset); + break; + case GL10.GL_SHORT: + ShortBuffer shortBuffer = byteBuffer.asShortBuffer(); + result[i] = shortBuffer.get(byteOffset / 2); + break; + case GL10.GL_FIXED: + IntBuffer intBuffer = byteBuffer.asIntBuffer(); + result[i] = intBuffer.get(byteOffset / 4); + break; + case GL10.GL_FLOAT: + FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); + result[i] = floatBuffer.get(byteOffset / 4); + break; + default: + throw new UnsupportedOperationException("unknown type"); + } + byteOffset += sizeofType; + } + } +} diff --git a/tests/src/com/android/gallery3d/ui/TextureTest.java b/tests/src/com/android/gallery3d/ui/TextureTest.java new file mode 100644 index 000000000..fb26060bc --- /dev/null +++ b/tests/src/com/android/gallery3d/ui/TextureTest.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.ui; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.test.suitebuilder.annotation.SmallTest; + +import javax.microedition.khronos.opengles.GL11; + +import junit.framework.TestCase; + +@SmallTest +public class TextureTest extends TestCase { + @SuppressWarnings("unused") + private static final String TAG = "TextureTest"; + + class MyBasicTexture extends BasicTexture { + int mOnBindCalled; + int mOpaqueCalled; + + MyBasicTexture(GLCanvas canvas, int id) { + super(canvas, id, BasicTexture.STATE_UNLOADED); + } + + @Override + protected boolean onBind(GLCanvas canvas) { + mOnBindCalled++; + return true; + } + + public boolean isOpaque() { + mOpaqueCalled++; + return true; + } + + void upload() { + mState = STATE_LOADED; + } + } + + @SmallTest + public void testBasicTexture() { + GL11 glStub = new GLStub(); + GLCanvas canvas = new GLCanvasImpl(glStub); + MyBasicTexture texture = new MyBasicTexture(canvas, 47); + + assertEquals(47, texture.getId()); + texture.setSize(1, 1); + assertEquals(1, texture.getWidth()); + assertEquals(1, texture.getHeight()); + assertEquals(1, texture.getTextureWidth()); + assertEquals(1, texture.getTextureHeight()); + texture.setSize(3, 5); + assertEquals(3, texture.getWidth()); + assertEquals(5, texture.getHeight()); + assertEquals(4, texture.getTextureWidth()); + assertEquals(8, texture.getTextureHeight()); + + assertFalse(texture.isLoaded(canvas)); + texture.upload(); + assertTrue(texture.isLoaded(canvas)); + + // For a different GL, it's not loaded. + GLCanvas canvas2 = new GLCanvasImpl(new GLStub()); + assertFalse(texture.isLoaded(canvas2)); + + assertEquals(0, texture.mOnBindCalled); + assertEquals(0, texture.mOpaqueCalled); + texture.draw(canvas, 100, 200, 1, 1); + assertEquals(1, texture.mOnBindCalled); + assertEquals(1, texture.mOpaqueCalled); + texture.draw(canvas, 0, 0); + assertEquals(2, texture.mOnBindCalled); + assertEquals(2, texture.mOpaqueCalled); + } + + @SmallTest + public void testRawTexture() { + GL11 glStub = new GLStub(); + GLCanvas canvas = new GLCanvasImpl(glStub); + RawTexture texture = RawTexture.newInstance(canvas); + texture.onBind(canvas); + + GLCanvas canvas2 = new GLCanvasImpl(new GLStub()); + try { + texture.onBind(canvas2); + fail(); + } catch (RuntimeException ex) { + // expected. + } + + assertTrue(texture.isOpaque()); + } + + @SmallTest + public void testColorTexture() { + GLCanvasMock canvas = new GLCanvasMock(); + ColorTexture texture = new ColorTexture(0x12345678); + + texture.setSize(42, 47); + assertEquals(texture.getWidth(), 42); + assertEquals(texture.getHeight(), 47); + assertEquals(0, canvas.mFillRectCalled); + texture.draw(canvas, 0, 0); + assertEquals(1, canvas.mFillRectCalled); + assertEquals(0x12345678, canvas.mFillRectColor); + assertEquals(42f, canvas.mFillRectWidth); + assertEquals(47f, canvas.mFillRectHeight); + assertFalse(texture.isOpaque()); + assertTrue(new ColorTexture(0xFF000000).isOpaque()); + } + + private class MyUploadedTexture extends UploadedTexture { + int mGetCalled; + int mFreeCalled; + Bitmap mBitmap; + @Override + protected Bitmap onGetBitmap() { + mGetCalled++; + Config config = Config.ARGB_8888; + mBitmap = Bitmap.createBitmap(47, 42, config); + return mBitmap; + } + @Override + protected void onFreeBitmap(Bitmap bitmap) { + mFreeCalled++; + assertSame(mBitmap, bitmap); + mBitmap.recycle(); + mBitmap = null; + } + } + + @SmallTest + public void testUploadedTexture() { + GL11 glStub = new GLStub(); + GLCanvas canvas = new GLCanvasImpl(glStub); + MyUploadedTexture texture = new MyUploadedTexture(); + + // draw it and the bitmap should be fetched. + assertEquals(0, texture.mFreeCalled); + assertEquals(0, texture.mGetCalled); + texture.draw(canvas, 0, 0); + assertEquals(1, texture.mGetCalled); + assertTrue(texture.isLoaded(canvas)); + assertTrue(texture.isContentValid(canvas)); + + // invalidate content and it should be freed. + texture.invalidateContent(); + assertFalse(texture.isContentValid(canvas)); + assertEquals(1, texture.mFreeCalled); + assertTrue(texture.isLoaded(canvas)); // But it's still loaded + + // draw it again and the bitmap should be fetched again. + texture.draw(canvas, 0, 0); + assertEquals(2, texture.mGetCalled); + assertTrue(texture.isLoaded(canvas)); + assertTrue(texture.isContentValid(canvas)); + + // recycle the texture and it should be freed again. + texture.recycle(); + assertEquals(2, texture.mFreeCalled); + // TODO: these two are broken and waiting for fix. + //assertFalse(texture.isLoaded(canvas)); + //assertFalse(texture.isContentValid(canvas)); + } + + class MyTextureForMixed extends BasicTexture { + MyTextureForMixed(GLCanvas canvas, int id) { + super(canvas, id, BasicTexture.STATE_UNLOADED); + } + + @Override + protected boolean onBind(GLCanvas canvas) { + return true; + } + + public boolean isOpaque() { + return true; + } + } + + @SmallTest + public void testBitmapTexture() { + Config config = Config.ARGB_8888; + Bitmap bitmap = Bitmap.createBitmap(47, 42, config); + assertFalse(bitmap.isRecycled()); + BitmapTexture texture = new BitmapTexture(bitmap); + texture.recycle(); + assertFalse(bitmap.isRecycled()); + bitmap.recycle(); + assertTrue(bitmap.isRecycled()); + } +} diff --git a/tests/src/com/android/gallery3d/util/IntArrayTest.java b/tests/src/com/android/gallery3d/util/IntArrayTest.java new file mode 100644 index 000000000..83e605006 --- /dev/null +++ b/tests/src/com/android/gallery3d/util/IntArrayTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 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.android.gallery3d.util; + +import com.android.gallery3d.util.IntArray; + +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import java.util.Arrays; +import junit.framework.TestCase; + +@SmallTest +public class IntArrayTest extends TestCase { + private static final String TAG = "IntArrayTest"; + + public void testIntArray() { + IntArray a = new IntArray(); + assertEquals(0, a.size()); + assertTrue(Arrays.equals(new int[] {}, a.toArray(null))); + + a.add(0); + assertEquals(1, a.size()); + assertTrue(Arrays.equals(new int[] {0}, a.toArray(null))); + + a.add(1); + assertEquals(2, a.size()); + assertTrue(Arrays.equals(new int[] {0, 1}, a.toArray(null))); + + int[] buf = new int[2]; + int[] result = a.toArray(buf); + assertSame(buf, result); + + IntArray b = new IntArray(); + for (int i = 0; i < 100; i++) { + b.add(i * i); + } + + assertEquals(100, b.size()); + result = b.toArray(buf); + assertEquals(100, result.length); + for (int i = 0; i < 100; i++) { + assertEquals(i * i, result[i]); + } + } +} -- cgit v1.2.3