1/*
2 * Copyright (C) 2016 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.android.server.wifi.hotspot2.anqp;
18
19import static org.junit.Assert.assertEquals;
20
21import android.test.suitebuilder.annotation.SmallTest;
22
23import org.junit.Test;
24
25import java.io.ByteArrayOutputStream;
26import java.io.IOException;
27import java.net.ProtocolException;
28import java.nio.BufferUnderflowException;
29import java.nio.ByteBuffer;
30import java.nio.charset.StandardCharsets;
31import java.util.Locale;
32
33/**
34 * Unit tests for {@link com.android.server.wifi.hotspot2.anqp.I18Name}.
35 */
36@SmallTest
37public class I18NameTest {
38    private static final String TEST_LANGUAGE = "en";
39    private static final Locale TEST_LOCALE = Locale.forLanguageTag(TEST_LANGUAGE);
40    private static final String TEST_TEXT = "Hello World";
41
42    /**
43     * Helper function for returning byte array containing test data.
44     *
45     * @param language The language code string
46     * @param text The text string
47     * @return byte[]
48     * @throws IOException
49     */
50    private byte[] getTestData(String language, String text) throws IOException {
51        ByteArrayOutputStream stream = new ByteArrayOutputStream();
52        stream.write(language.getBytes(StandardCharsets.US_ASCII));
53        stream.write(new byte[]{(byte) 0x0});  // Padding for language code.
54        stream.write(text.getBytes(StandardCharsets.UTF_8));
55        return stream.toByteArray();
56    }
57
58    /**
59     * Helper function for generating default test data. The test data include the language code
60     * and text field.
61     *
62     * @return byte[] of data
63     * @throws IOException
64     */
65    private byte[] getDefaultTestData() throws IOException {
66        return getTestData(TEST_LANGUAGE, TEST_TEXT);
67    }
68
69    /**
70     * Helper function for returning a buffer containing a I18Name test data.
71     *
72     * @Param data The byte array of I18Name data
73     * @param length The length value to set in the I18Name header
74     * @return {@link ByteBuffer}
75     * @throws IOException
76     */
77    private ByteBuffer getTestBuffer(byte[] data, int length) throws IOException {
78        // Allocate extra byte for storing the length field.
79        ByteBuffer buffer = ByteBuffer.allocate(data.length + 1);
80        buffer.put((byte) length);
81        buffer.put(data);
82        buffer.position(0);
83        return buffer;
84    }
85
86    /**
87     * Verify that BufferUnderflowException will be thrown when parsing from an empty buffer.
88     *
89     * @throws Exception
90     */
91    @Test(expected = BufferUnderflowException.class)
92    public void parseEmptyBuffer() throws Exception {
93        I18Name.parse(ByteBuffer.allocate(0));
94    }
95
96    /**
97     * Verify that BufferUnderflowException will be thrown when the length field is set to more
98     * than the actual buffer size.
99     *
100     * @throws Exception
101     */
102    @Test(expected = BufferUnderflowException.class)
103    public void parseTruncatedBuffer() throws Exception {
104        byte[] data = getDefaultTestData();
105        ByteBuffer buffer = getTestBuffer(data, data.length);
106        buffer.limit(buffer.remaining() - 1);
107        I18Name.parse(buffer);
108    }
109
110    /**
111     * Verify that ProtocolException will be thrown when the length field is set to less than
112     * the minimum.
113     *
114     * @throws Exception
115     */
116    @Test(expected = ProtocolException.class)
117    public void parseBufferWithLengthLessThanMinimum() throws Exception {
118        byte[] data = getDefaultTestData();
119        I18Name.parse(getTestBuffer(data, I18Name.MINIMUM_LENGTH - 1));
120    }
121
122    /**
123     * Verify that the expected I18Name will be returned when parsing a buffer contained the
124     * predefined test data.
125     *
126     * @throws Exception
127     */
128    @Test
129    public void parseBufferWithDefaultTestData() throws Exception {
130        byte[] data = getDefaultTestData();
131        I18Name actualName = I18Name.parse(getTestBuffer(data, data.length));
132        I18Name expectedName = new I18Name(TEST_LANGUAGE, TEST_LOCALE, TEST_TEXT);
133        assertEquals(expectedName, actualName);
134    }
135
136    /**
137     * Verify that the expected I18Name will be returned when parsing a buffer contained
138     * a non-English (French) language.
139     *
140     * @throws Exception
141     */
142    @Test
143    public void parseBufferWithFrenchData() throws Exception {
144        // Test data for French.
145        String language = "fr";
146        String text = "Hello World";
147        byte[] data = getTestData(language, text);
148        I18Name actualName = I18Name.parse(getTestBuffer(data, data.length));
149        I18Name expectedName = new I18Name(language, Locale.forLanguageTag(language), text);
150        assertEquals(expectedName, actualName);
151    }
152
153    /**
154     * Verify that an I18Name with an empty text will be returned when parsing a buffer contained
155     * an empty text field.
156     *
157     * @throws Exception
158     */
159    @Test
160    public void parseBufferWithEmptyText() throws Exception {
161        byte[] data = getTestData(TEST_LANGUAGE, "");
162        I18Name actualName = I18Name.parse(getTestBuffer(data, data.length));
163        I18Name expectedName = new I18Name(TEST_LANGUAGE, TEST_LOCALE, "");
164        assertEquals(expectedName, actualName);
165    }
166}
167