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 Stepan M. Mishura
20*/
21
22package org.apache.harmony.security.tests.asn1.der;
23
24import java.io.IOException;
25import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.List;
28
29import org.apache.harmony.security.asn1.ASN1Boolean;
30import org.apache.harmony.security.asn1.ASN1Exception;
31import org.apache.harmony.security.asn1.ASN1Integer;
32import org.apache.harmony.security.asn1.ASN1Sequence;
33import org.apache.harmony.security.asn1.ASN1SequenceOf;
34import org.apache.harmony.security.asn1.ASN1Type;
35import org.apache.harmony.security.asn1.BerInputStream;
36import org.apache.harmony.security.asn1.DerInputStream;
37import org.apache.harmony.security.asn1.DerOutputStream;
38
39import junit.framework.TestCase;
40
41
42/**
43 * ASN.1 DER test for Sequence type
44 *
45 * @see http://asn1.elibel.tm.fr/en/standards/index.htm
46 */
47
48public class SequenceTest extends TestCase {
49
50    private static ASN1SequenceOf sequenceOf = new ASN1SequenceOf(ASN1Boolean
51            .getInstance());
52
53    private static ArrayList defaultList;
54
55    private static ASN1Sequence sequence;
56
57    private static Object[][] testcases;
58
59    protected void setUp() throws Exception {
60        super.setUp();
61
62        //
63        // sequence ::= SEQUENCE {
64        //     boolean BOOLEAN, DEFAULT true
65        //     list SEQUENCE OF BOOLEAN, DEFAULT list(false)
66        // }
67        //
68
69        defaultList = new ArrayList();
70        defaultList.add(Boolean.FALSE);
71
72        sequence = new ASN1Sequence(new ASN1Type[] { ASN1Boolean.getInstance(),
73                sequenceOf }) {
74            {
75                setDefault(Boolean.TRUE, 0);
76                setDefault(defaultList, 1);
77            }
78
79            protected Object getDecodedObject(BerInputStream in)
80                    throws IOException {
81                Object[] values = (Object[]) in.content;
82                return new AppClass((Boolean) values[0], (List) values[1]);
83            }
84
85            protected void getValues(Object object, Object[] values) {
86                AppClass obj = (AppClass) object;
87
88                values[0] = obj.ok;
89                values[1] = obj.list;
90            }
91        };
92
93        //
94        // Test Cases
95        //
96
97        testcases = new Object[][] {
98                // format: object to encode / byte array
99
100                // sequence : all values are default
101                { new AppClass(Boolean.TRUE, defaultList),
102                        new byte[] { 0x30, 0x00 } },
103
104                // sequence : true, default
105                { new AppClass(Boolean.FALSE, defaultList),
106                        new byte[] { 0x30, 0x03, 0x01, 0x01, 0x00 } },
107
108                // sequence = default, empty sequence
109                { new AppClass(Boolean.TRUE, new ArrayList()),
110                        new byte[] { 0x30, 0x02, 0x30, 0x00 } },
111
112                // sequence = false, empty sequence
113                { new AppClass(Boolean.FALSE, new ArrayList()),
114                        new byte[] { 0x30, 0x05, 0x01, 0x01, 0x00, 0x30, 0x00 } },
115
116        //TODO add testcase for another ASN.1 type`
117
118        };
119    }
120
121    //
122    // Application class
123    //
124
125    public static class AppClass {
126
127        public Boolean ok;
128
129        public List list;
130
131        public AppClass(Boolean ok, List list) {
132            this.ok = ok;
133            this.list = list;
134        }
135
136        public boolean equals(Object o) {
137            if (o instanceof AppClass) {
138                AppClass obj = (AppClass) o;
139                return ok.equals(obj.ok) && list.equals(obj.list);
140            }
141            return false;
142        }
143    }
144
145    public void testDecode_Valid() throws IOException {
146
147        for (int i = 0; i < testcases.length; i++) {
148            try {
149                DerInputStream in = new DerInputStream((byte[]) testcases[i][1]);
150                assertEquals("Test case: " + i, testcases[i][0], sequence
151                        .decode(in));
152            } catch (ASN1Exception e) {
153                fail("Test case: " + i + "\n" + e.getMessage());
154            }
155        }
156    }
157
158    //FIXME need testcase for decoding invalid encodings
159
160    public void testEncode() throws IOException {
161
162        for (int i = 0; i < testcases.length; i++) {
163            DerOutputStream out = new DerOutputStream(sequence, testcases[i][0]);
164            assertTrue("Test case: " + i, Arrays.equals(
165                    (byte[]) testcases[i][1], out.encoded));
166        }
167    }
168
169    public void testVerify() throws IOException {
170
171        ASN1Sequence seqVerify = new ASN1Sequence(new ASN1Type[] {
172                ASN1Boolean.getInstance(), sequenceOf }) {
173            {
174                setDefault(Boolean.TRUE, 0);
175                setDefault(defaultList, 1);
176            }
177
178            protected Object getDecodedObject(BerInputStream in)
179                    throws IOException {
180                throw new IOException(
181                        "Method getDecodedObject MUST not be invoked");
182            }
183        };
184
185        for (int i = 0; i < testcases.length; i++) {
186            DerInputStream in = new DerInputStream((byte[]) testcases[i][1]);
187            in.setVerify();
188            seqVerify.decode(in);
189        }
190    }
191
192    /**
193     * Tests encoding default fields
194     */
195    public void testEncodeDefault() throws IOException {
196
197        //
198        // Boolean as default
199        //
200        ASN1Sequence s = new ASN1Sequence(new ASN1Type[] { ASN1Boolean
201                .getInstance() }) {
202            {
203                setDefault(Boolean.TRUE, 0);
204            }
205
206            protected void getValues(Object object, Object[] values) {
207                values = (Object[]) object;
208            }
209        };
210
211        byte[] expectedArray = new byte[] { 0x30, 0x00 };
212
213        byte[] encoded = s.encode(new Object[] { Boolean.TRUE });
214        assertTrue("Encoded boolean:", Arrays.equals(expectedArray, encoded));
215
216        //
217        // Integer as default
218        //
219        s = new ASN1Sequence(new ASN1Type[] { ASN1Integer.getInstance() }) {
220            {
221                setDefault(new byte[] { 0x01 }, 0);
222            }
223
224            protected void getValues(Object object, Object[] values) {
225                values = (Object[]) object;
226            }
227        };
228
229        encoded = s.encode(new Object[] { new byte[] { 0x01 } });
230        assertTrue("Encoded integer:", Arrays.equals(expectedArray, encoded));
231    }
232
233    /**
234     * Tests encoding optional fields
235     */
236    public void testEncodeOptional() throws IOException {
237
238        //
239        // Test not optional
240        //
241        ASN1Sequence s = new ASN1Sequence(new ASN1Type[] { ASN1Boolean
242                .getInstance() }) {
243
244            protected void getValues(Object object, Object[] values) {
245                values[0] = ((Object[]) object)[0];
246            }
247        };
248
249        try {
250            s.encode(new Object[] { null });
251            fail("No expected RuntimeException");
252        } catch (RuntimeException e) {
253        }
254
255        //
256        // Test optional
257        //
258        s = new ASN1Sequence(new ASN1Type[] { ASN1Boolean.getInstance() }) {
259            {
260                setOptional(0);
261            }
262
263            protected void getValues(Object object, Object[] values) {
264                values[0] = ((Object[]) object)[0];
265            }
266        };
267
268        byte[] expectedArray = new byte[] { 0x30, 0x00 };
269
270        byte[] encoded = s.encode(new Object[] { null });
271        assertTrue("Encoded boolean:", Arrays.equals(expectedArray, encoded));
272    }
273}
274