1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.example.android.camera2.cameratoo;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertTrue;
21import static org.mockito.Mockito.mock;
22import static org.mockito.Mockito.when;
23
24import android.media.Image;
25import android.os.Environment;
26import android.util.Size;
27
28import java.io.File;
29import java.io.FileInputStream;
30import java.io.FileNotFoundException;
31import java.io.FilenameFilter;
32import java.io.IOException;
33import java.nio.ByteBuffer;
34import java.util.Arrays;
35import java.util.Comparator;
36import java.util.HashSet;
37import java.util.Set;
38
39import com.example.android.camera2.cameratoo.CameraTooActivity;
40import org.junit.Test;
41
42public class CameraTooTest {
43    private <T> void assertComparatorEq(T lhs, T rhs, Comparator<T> rel) {
44        assertEquals(String.format("%s should be equal to %s", lhs, rhs), rel.compare(lhs, rhs), 0);
45        assertEquals(String.format("%s should be equal to %s (reverse check)", lhs, rhs),
46                rel.compare(rhs, lhs), 0);
47    }
48
49    private <T> void assertComparatorLt(T lhs, T rhs, Comparator<T> rel) {
50        assertTrue(String.format("%s should be less than %s", lhs, rhs), rel.compare(lhs, rhs) < 0);
51        assertTrue(String.format("%s should be less than %s (reverse check)", lhs, rhs),
52                rel.compare(rhs, lhs) > 0);
53    }
54
55    @Test
56    public void compareSizesByArea() {
57        Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
58        Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
59        Size largeSquare = new Size(5, 5);
60        Comparator<Size> rel = new CameraTooActivity.CompareSizesByArea();
61
62        assertComparatorEq(empty, fatAndFlat, rel);
63        assertComparatorEq(empty, tallAndThin, rel);
64        assertComparatorEq(fatAndFlat, empty, rel);
65        assertComparatorEq(fatAndFlat, tallAndThin, rel);
66        assertComparatorEq(tallAndThin, empty, rel);
67        assertComparatorEq(tallAndThin, fatAndFlat, rel);
68
69        assertComparatorEq(smallSquare, horizRect, rel);
70        assertComparatorEq(smallSquare, vertRect, rel);
71        assertComparatorEq(horizRect, smallSquare, rel);
72        assertComparatorEq(horizRect, vertRect, rel);
73        assertComparatorEq(vertRect, smallSquare, rel);
74        assertComparatorEq(vertRect, horizRect, rel);
75
76        assertComparatorLt(empty, smallSquare, rel);
77        assertComparatorLt(empty, horizRect, rel);
78        assertComparatorLt(empty, vertRect, rel);
79
80        assertComparatorLt(fatAndFlat, smallSquare, rel);
81        assertComparatorLt(fatAndFlat, horizRect, rel);
82        assertComparatorLt(fatAndFlat, vertRect, rel);
83
84        assertComparatorLt(tallAndThin, smallSquare, rel);
85        assertComparatorLt(tallAndThin, horizRect, rel);
86        assertComparatorLt(tallAndThin, vertRect, rel);
87
88        assertComparatorLt(empty, largeSquare, rel);
89        assertComparatorLt(fatAndFlat, largeSquare, rel);
90        assertComparatorLt(tallAndThin, largeSquare, rel);
91        assertComparatorLt(smallSquare, largeSquare, rel);
92        assertComparatorLt(horizRect, largeSquare, rel);
93        assertComparatorLt(vertRect, largeSquare, rel);
94    }
95
96    private void assertOptimalSize(Size[] options, int minWidth, int minHeight, Size expected) {
97        Size verdict = CameraTooActivity.chooseBigEnoughSize(options, minWidth, minHeight);
98        assertEquals(String.format("Expected optimal size %s but got %s", expected, verdict),
99                verdict, expected);
100    }
101
102    @Test
103    public void chooseBigEnoughSize() {
104        Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
105        Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
106        Size largeSquare = new Size(5, 5);
107        Size[] siz =
108                { empty, fatAndFlat, tallAndThin, smallSquare, horizRect, vertRect, largeSquare };
109
110        assertOptimalSize(siz, 0, 0, empty);
111
112        assertOptimalSize(siz, 1, 0, fatAndFlat);
113        assertOptimalSize(siz, 0, 1, tallAndThin);
114
115        assertOptimalSize(siz, 4, 4, smallSquare);
116        assertOptimalSize(siz, 1, 1, smallSquare);
117        assertOptimalSize(siz, 2, 1, smallSquare);
118        assertOptimalSize(siz, 1, 2, smallSquare);
119        assertOptimalSize(siz, 3, 4, smallSquare);
120        assertOptimalSize(siz, 4, 3, smallSquare);
121
122        assertOptimalSize(siz, 8, 2, horizRect);
123        assertOptimalSize(siz, 5, 1, horizRect);
124        assertOptimalSize(siz, 5, 2, horizRect);
125
126        assertOptimalSize(siz, 2, 8, vertRect);
127        assertOptimalSize(siz, 1, 5, vertRect);
128        assertOptimalSize(siz, 2, 5, vertRect);
129
130        assertOptimalSize(siz, 5, 5, largeSquare);
131        assertOptimalSize(siz, 3, 5, largeSquare);
132        assertOptimalSize(siz, 5, 3, largeSquare);
133    }
134
135    private static final FilenameFilter OUTPUT_FILE_DECIDER = new FilenameFilter() {
136        @Override
137        public boolean accept(File dir, String filename) {
138            return filename.indexOf("cameratoo") == 0 &&
139                    filename.indexOf(".jpg") == filename.length() - ".jpg".length();
140        }};
141
142    private static <T> Set<T> newlyAddedElements(Set<T> before, Set<T> after) {
143        Set<T> result = new HashSet<T>(after);
144        result.removeAll(before);
145        return result;
146    }
147
148    @Test
149    public void capturedImageSaver() throws FileNotFoundException, IOException {
150        ByteBuffer buf = ByteBuffer.allocate(25);
151        for(int index = 0; index < buf.capacity(); ++index)
152            buf.put(index, (byte) index);
153
154        Image.Plane plane = mock(Image.Plane.class);
155        when(plane.getBuffer()).thenReturn(buf);
156        when(plane.getPixelStride()).thenReturn(1);
157        when(plane.getRowStride()).thenReturn(5);
158
159        Image.Plane[] onlyPlaneThatMatters = { plane };
160        Image image = mock(Image.class);
161        when(image.getPlanes()).thenReturn(onlyPlaneThatMatters);
162        when(image.getWidth()).thenReturn(5);
163        when(image.getHeight()).thenReturn(5);
164
165        File picturesFolder =
166                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
167        Set<File> preListing =
168                new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
169
170        CameraTooActivity.CapturedImageSaver saver =
171                new CameraTooActivity.CapturedImageSaver(image);
172        saver.run();
173
174        Set<File> postListing =
175                new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
176        Set<File> newFiles = newlyAddedElements(preListing, postListing);
177
178        assertEquals(newFiles.size(), 1);
179
180        File picture = newFiles.iterator().next();
181        FileInputStream istream = new FileInputStream(picture);
182
183        for(int count = 0; count < buf.capacity(); ++count) {
184            assertEquals(istream.read(), buf.get(count));
185        }
186        assertEquals(istream.read(), -1);
187        assertTrue(picture.delete());
188    }
189}
190