1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18/**
19* @author Alexander Y. Kleymenov
20* @version $Revision$
21*/
22
23package org.apache.harmony.crypto.tests.javax.crypto;
24
25import dalvik.annotation.TestTargetClass;
26import dalvik.annotation.TestTargets;
27import dalvik.annotation.TestLevel;
28import dalvik.annotation.TestTargetNew;
29
30import java.io.ByteArrayInputStream;
31import java.security.InvalidKeyException;
32import java.security.Key;
33import java.security.NoSuchAlgorithmException;
34import java.security.SecureRandom;
35
36import javax.crypto.Cipher;
37import javax.crypto.KeyGenerator;
38import javax.crypto.NoSuchPaddingException;
39import javax.crypto.NullCipher;
40import javax.crypto.CipherInputStream;
41
42import junit.framework.TestCase;
43
44@TestTargetClass(CipherInputStream.class)
45/**
46 */
47
48public class CipherInputStream1Test extends TestCase {
49
50    private static class TestInputStream extends ByteArrayInputStream {
51        private boolean closed = false;
52
53        public TestInputStream(byte[] data) {
54            super(data);
55        }
56
57        public void close() {
58            closed = true;
59        }
60
61        public boolean wasClosed() {
62            return closed;
63        }
64    }
65
66    /**
67     * CipherInputStream(InputStream is) method testing. Tests that
68     * CipherInputStream uses NullCipher if Cipher is not specified
69     * in the constructor.
70     */
71    @TestTargetNew(
72        level = TestLevel.COMPLETE,
73        notes = "",
74        method = "CipherInputStream",
75        args = {java.io.InputStream.class}
76    )
77    public void testCipherInputStream() throws Exception {
78        byte[] data = new byte[] { -127, -100, -50, -10, -1, 0, 1, 10, 50, 127 };
79        TestInputStream tis = new TestInputStream(data);
80        CipherInputStream cis = new CipherInputStream(tis){};
81
82        for (int i = 0; i < data.length; i++) {
83            if ((byte) cis.read() != data[i]) {
84                fail("NullCipher should be used "
85                        + "if Cipher is not specified.");
86            }
87        }
88        if (cis.read() != -1) {
89            fail("NullCipher should be used if Cipher is not specified.");
90        }
91    }
92
93    /**
94     * read() method testing. Tests that method returns the correct value
95     * (related to the InputStream) and that it returns -1 at the end of stream.
96     */
97    @TestTargetNew(
98        level = TestLevel.COMPLETE,
99        notes = "Can not check IOException.",
100        method = "read",
101        args = {}
102    )
103    public void testRead1() throws Exception {
104        byte[] data = new byte[] { -127, -100, -50, -10, -1, 0, 1, 10, 50, 127 };
105        TestInputStream tis = new TestInputStream(data);
106        CipherInputStream cis = new CipherInputStream(tis, new NullCipher());
107        byte res;
108        for (int i = 0; i < data.length; i++) {
109            if ((res = (byte) cis.read()) != data[i]) {
110                fail("read() returned the incorrect value. " + "Expected: "
111                        + data[i] + ", Got: " + res + ".");
112            }
113        }
114        if (cis.read() != -1) {
115            fail("read() should return -1 at the end of the stream.");
116        }
117    }
118
119    /**
120     * read(byte[] b) method testing. Tests that method returns the correct
121     * value (related to the InputStream) and that it returns -1 at the end of
122     * stream.
123     */
124    @TestTargetNew(
125        level = TestLevel.COMPLETE,
126        notes = "Can not check IOException.",
127        method = "read",
128        args = {byte[].class}
129    )
130    public void testRead2() throws Exception {
131        byte[] data = new byte[] { -127, -100, -50, -10, -1, 0, 1, 10, 50, 127 };
132        TestInputStream tis = new TestInputStream(data);
133        CipherInputStream cis = new CipherInputStream(tis, new NullCipher());
134
135        int expected = data.length;
136        byte[] result = new byte[expected];
137
138        int ind = 0; // index into the data array (to check the got data)
139        int got = cis.read(result); // the number of got bytes
140        while (true) {
141            for (int j = 0; j < got - ind; j++) {
142                if (result[j] != data[ind + j]) {
143                    fail("read(byte[] b) returned incorrect data.");
144                }
145            }
146            if (got == expected) {
147                break;
148            } else if (got > expected) {
149                fail("The data returned by read(byte[] b) "
150                        + "is larger than expected.");
151            } else {
152                ind = got;
153                got += cis.read(result);
154            }
155        }
156        if (cis.read(result) != -1) {
157            fail("read(byte[] b) should return -1 "
158                    + "at the end of the stream.");
159        }
160    }
161
162    /**
163     * read(byte[] b, int off, int len) method testing. Tests that method
164     * returns the correct value (related to the InputStream), that it discards
165     * bytes in the case of null buffer, and that it returns -1 at the end of
166     * stream.
167     */
168    @TestTargetNew(
169        level = TestLevel.COMPLETE,
170        notes = "Can not check IOException.",
171        method = "read",
172        args = {byte[].class, int.class, int.class}
173    )
174    public void testRead3() throws Exception {
175        byte[] data = new byte[] { -127, -100, -50, -10, -1, 0, 1, 10, 50, 127 };
176        TestInputStream tis = new TestInputStream(data);
177        CipherInputStream cis = new CipherInputStream(tis, new NullCipher());
178
179        int expected = data.length;
180        byte[] result = new byte[expected];
181
182        int skip = 2;
183        int ind = skip; // index into the data array (to check the got data)
184        // should read and discard bytes;
185        cis.read(null, 0, skip);
186        int got = skip + cis.read(result, 0, 1); // the number of got bytes
187        while (true) {
188            for (int j = 0; j < got - ind; j++) {
189                assertEquals("read(byte[] b, int off, int len) "
190                        + "returned incorrect data.", result[j], data[ind + j]);
191            }
192            if (got == expected) {
193                break;
194            } else if (got > expected) {
195                fail("The data returned by "
196                        + "read(byte[] b, int off, int len) "
197                        + "is larger than expected.");
198            } else {
199                ind = got;
200                got += cis.read(result, 0, 3);
201            }
202        }
203        if (cis.read(result, 0, 1) != -1) {
204            fail("read() should return -1 at the end of the stream.");
205        }
206    }
207
208    /**
209     * skip(long n) method testing. Tests that the method correctly skips the
210     * bytes.
211     */
212    @TestTargetNew(
213        level = TestLevel.COMPLETE,
214        notes = "Can not check IOException.",
215        method = "skip",
216        args = {long.class}
217    )
218    public void testSkip() throws Exception {
219        byte[] data = new byte[] { -127, -100, -50, -10, -1, 0, 1, 10, 50, 127 };
220        TestInputStream tis = new TestInputStream(data);
221        CipherInputStream cis = new CipherInputStream(tis, new NullCipher());
222        int expected = data.length;
223        byte[] result = new byte[expected];
224
225        int skipped = (int) cis.skip(2);
226        int ind = skipped;
227        int got = skipped + cis.read(result, 0, 1); // the number of got bytes
228        while (true) {
229            for (int j = 0; j < got - ind; j++) {
230                if (result[j] != data[ind + j]) {
231                    fail("read(byte[] b, int off, int len) "
232                            + "returned incorrect data: Expected "
233                            + data[ind + j] + ", got: " + result[j]);
234                }
235            }
236            if (got == expected) {
237                break;
238            } else if (got > expected) {
239                fail("The data returned by "
240                        + "read(byte[] b, int off, int len) "
241                        + "is larger than expected.");
242            } else {
243                ind = got;
244                got += cis.read(result, 0, 1);
245            }
246        }
247        if ((got = cis.read(result, 0, 1)) != -1) {
248            fail("read() should return -1 at the end of the stream. "
249                    + "Output is: " + got + ".");
250        }
251    }
252
253    /**
254     * available() method testing. Tests that the method always return 0.
255     */
256    @TestTargetNew(
257        level = TestLevel.COMPLETE,
258        notes = "Can not check IOException.",
259        method = "available",
260        args = {}
261    )
262    public void testAvailable() throws Exception {
263        byte[] data = new byte[] { -127, -100, -50, -10, -1, 0, 1, 10, 50, 127 };
264        TestInputStream tis = new TestInputStream(data);
265        CipherInputStream cis = new CipherInputStream(tis, new NullCipher());
266        assertEquals("The returned by available() method value "
267                + "should be 0.", cis.available(), 0);
268    }
269
270    /**
271     * close() method testing. Tests that the method calls the close()
272     * method of the underlying input stream.
273     */
274    @TestTargetNew(
275        level = TestLevel.COMPLETE,
276        notes = "Can not check IOException.",
277        method = "close",
278        args = {}
279    )
280    public void testClose() throws Exception {
281        byte[] data = new byte[] { -127, -100, -50, -10, -1, 0, 1, 10, 50, 127 };
282        TestInputStream tis = new TestInputStream(data);
283        CipherInputStream cis = new CipherInputStream(tis, new NullCipher());
284        cis.close();
285        assertTrue("The close() method should call the close() method "
286                + "of its underlying input stream.", tis.wasClosed());
287    }
288
289    /**
290     * markSupported() method testing. Tests that mark is not supported.
291     */
292    @TestTargetNew(
293        level = TestLevel.COMPLETE,
294        notes = "",
295        method = "markSupported",
296        args = {}
297    )
298    public void testMarkSupported() {
299        byte[] data = new byte[] {-127, -100, -50, -10, -1, 0, 1, 10, 50, 127};
300        TestInputStream tis = new TestInputStream(data);
301        CipherInputStream cis = new CipherInputStream(tis, new NullCipher());
302        assertFalse("The returned by markSupported() method value "
303                + "should be false.", cis.markSupported());
304    }
305
306    @TestTargetNew(
307        level = TestLevel.COMPLETE,
308        notes = "",
309        method = "CipherInputStream",
310        args = {java.io.InputStream.class, javax.crypto.Cipher.class}
311    )
312    public void test_ConstructorLjava_io_InputStreamLjavax_crypto_Cipher () throws
313    NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
314        ByteArrayInputStream bais = new ByteArrayInputStream(new byte[100]);
315
316        KeyGenerator kg = KeyGenerator.getInstance("DES");
317        kg.init(56, new SecureRandom());
318        Key key = kg.generateKey();
319
320        Cipher c = Cipher.getInstance("DES/CBC/NoPadding");
321        c.init(Cipher.ENCRYPT_MODE, key);
322
323        CipherInputStream cis = new CipherInputStream(bais, c);
324
325        assertNotNull(cis);
326    }
327
328}
329
330