summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPeter Qiu <zqiu@google.com>2016-12-05 16:11:37 -0800
committerPeter Qiu <zqiu@google.com>2016-12-15 15:37:19 -0800
commit74339de52d7066f22771d914e698da503232c107 (patch)
treef38b4466b773e40a6ddfb6eec9c2bdc2084542e9 /tests
parentfa04a81daf829e6e5c099c9a249b8dd8dd112102 (diff)
hotspot2: ANQP elements cleanup Part 1
Cleanup and add unit tests for the following ANQP elements (and the underlying classes used by those elements): - HSFriendNameElement - IPAddressTypeAvailabilityElement - RoamingConsortiumElement - VenueNameElement The cleanup included using a static #parse function for parsing raw bytes into an element object, the new ByteBufferReader APIs for reading integer and string from ByteBuffer, and documented possible runtime exceptions. Additional changes include: - remove the unnecessary setting of byte order for the ByteBuffer, since we're not using the ByteBuffer's APIs for reading integer values (all reads are either byte or byte array). - remove the unused functions in ANQPFactory More ANQP elements cleanup will be done in the upcoming CLs. Bug: 33000864 Test: frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I6da918c83722d5c0ca7a2374ff5fa5f630cdea6d
Diffstat (limited to 'tests')
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/HSFriendlyNameElementTest.java170
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/I18NameTest.java199
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/IPAddressTypeAvailabilityElementTest.java85
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/RoamingConsortiumElementTest.java171
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/VenueNameElementTest.java207
5 files changed, 668 insertions, 164 deletions
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/HSFriendlyNameElementTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/HSFriendlyNameElementTest.java
new file mode 100644
index 000000000..e228e0391
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/HSFriendlyNameElementTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2016 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.server.wifi.hotspot2.anqp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.ProtocolException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.hotspot2.anqp.HSFriendlyNameElement}.
+ */
+@SmallTest
+public class HSFriendlyNameElementTest {
+ private static final String TEST_LANGUAGE = "en";
+ private static final Locale TEST_LOCALE = Locale.forLanguageTag(TEST_LANGUAGE);
+ private static final String TEST_OPERATOR_NAME1 = "Operator1";
+ private static final String TEST_OPERATOR_NAME2 = "Operator2";
+
+ /**
+ * Helper function for appending a Operator Name to an output stream.
+ *
+ * @param stream Stream to write to
+ * @param operator The name of the operator
+ * @throws IOException
+ */
+ private void appendOperatorName(ByteArrayOutputStream stream, String operator)
+ throws IOException {
+ byte[] nameBytes = operator.getBytes(StandardCharsets.UTF_8);
+ int length = I18Name.LANGUAGE_CODE_LENGTH + operator.length();
+ stream.write((byte) length);
+ stream.write(TEST_LANGUAGE.getBytes(StandardCharsets.US_ASCII));
+ stream.write(new byte[]{(byte) 0x0}); // Padding for language code.
+ stream.write(nameBytes);
+ }
+
+ /**
+ * Helper function for generating test data.
+ *
+ * @return byte[] of data
+ * @throws IOException
+ */
+ private byte[] getTestData(String[] names) throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ for (String name : names) {
+ appendOperatorName(stream, name);
+ }
+ return stream.toByteArray();
+ }
+
+ /**
+ * Verify that HSFriendlyNameElement with a empty operator name list will be returned when
+ * parsing an empty buffer.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithEmptyBuffer() throws Exception {
+ assertTrue(HSFriendlyNameElement.parse(ByteBuffer.allocate(0)).getNames().isEmpty());
+ }
+
+ /**
+ * Verify that BufferUnderflowException will be thrown when parsing a truncated buffer
+ * (missing a byte at the end).
+ *
+ * @throws Exception
+ */
+ @Test(expected = BufferUnderflowException.class)
+ public void parseBufferWithTruncatedByte() throws Exception {
+ byte[] testData = getTestData(new String[] {TEST_OPERATOR_NAME1});
+ // Truncate a byte at the end.
+ ByteBuffer buffer = ByteBuffer.allocate(testData.length - 1);
+ buffer.put(testData, 0, testData.length - 1);
+ buffer.position(0);
+ HSFriendlyNameElement.parse(buffer);
+ }
+
+ /**
+ * Verify that an expected HSFriendlyNameElement will be returned when parsing a buffer
+ * containing the default test data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithDefaultTestData() throws Exception {
+ byte[] testData = getTestData(new String[] {TEST_OPERATOR_NAME1, TEST_OPERATOR_NAME2});
+ ByteBuffer buffer = ByteBuffer.allocate(testData.length);
+ buffer.put(testData);
+ buffer.position(0);
+
+ // Setup expected element.
+ List<I18Name> nameList = new ArrayList<>();
+ nameList.add(new I18Name(TEST_LANGUAGE, TEST_LOCALE, TEST_OPERATOR_NAME1));
+ nameList.add(new I18Name(TEST_LANGUAGE, TEST_LOCALE, TEST_OPERATOR_NAME2));
+ HSFriendlyNameElement expectedElement = new HSFriendlyNameElement(nameList);
+
+ assertEquals(expectedElement, HSFriendlyNameElement.parse(buffer));
+ }
+
+ /**
+ * Verify that an expected HSFriendlyNameElement will be returned when parsing a buffer
+ * containing a operator name with the maximum length.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithMaxLengthOperatoreName() throws Exception {
+ // Operator name with the maximum length.
+ byte[] textData = new byte[HSFriendlyNameElement.MAXIMUM_OPERATOR_NAME_LENGTH];
+ Arrays.fill(textData, (byte) 'a');
+ String text = new String(textData);
+ byte[] testData = getTestData(new String[] {text});
+ ByteBuffer buffer = ByteBuffer.allocate(testData.length);
+ buffer.put(testData);
+ buffer.position(0);
+
+ // Setup expected element.
+ List<I18Name> nameList = new ArrayList<>();
+ nameList.add(new I18Name(TEST_LANGUAGE, TEST_LOCALE, text));
+ HSFriendlyNameElement expectedElement = new HSFriendlyNameElement(nameList);
+
+ assertEquals(expectedElement, HSFriendlyNameElement.parse(buffer));
+ }
+
+ /**
+ * Verify that ProtocolException will be thrown when parsing a buffer containing a
+ * operator name that exceeds the maximum length.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferWithOperatorNameLengthExceedMax() throws Exception {
+ byte[] textData = new byte[HSFriendlyNameElement.MAXIMUM_OPERATOR_NAME_LENGTH + 1];
+ Arrays.fill(textData, (byte) 'a');
+ String text = new String(textData);
+ byte[] testData = getTestData(new String[] {text});
+ ByteBuffer buffer = ByteBuffer.allocate(testData.length);
+ buffer.put(testData);
+ buffer.position(0);
+ HSFriendlyNameElement.parse(buffer);
+ }
+
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/I18NameTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/I18NameTest.java
index 29b196230..6920e581a 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/I18NameTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/I18NameTest.java
@@ -16,110 +16,151 @@
package com.android.server.wifi.hotspot2.anqp;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Test;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.net.ProtocolException;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
import java.util.Locale;
/**
- * Unit tests for {@link com.android.server.wifi.anqp.I18Name}.
+ * Unit tests for {@link com.android.server.wifi.hotspot2.anqp.I18Name}.
*/
@SmallTest
public class I18NameTest {
- private static class I18NameTestMapping {
- byte[] mBytes;
- String mExpectedLanguage;
- Locale mExpectedLocale;
- String mExpectedText;
- I18NameTestMapping(byte[] bytes, String language, Locale locale, String text) {
- this.mBytes = bytes;
- this.mExpectedLanguage = language;
- this.mExpectedLocale = locale;
- this.mExpectedText = text;
- }
+ private static final String TEST_LANGUAGE = "en";
+ private static final Locale TEST_LOCALE = Locale.forLanguageTag(TEST_LANGUAGE);
+ private static final String TEST_TEXT = "Hello World";
+
+ /**
+ * Helper function for returning byte array containing test data.
+ *
+ * @param language The language code string
+ * @param text The text string
+ * @return byte[]
+ * @throws IOException
+ */
+ private byte[] getTestData(String language, String text) throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ stream.write(language.getBytes(StandardCharsets.US_ASCII));
+ stream.write(new byte[]{(byte) 0x0}); // Padding for language code.
+ stream.write(text.getBytes(StandardCharsets.UTF_8));
+ return stream.toByteArray();
}
- private static final byte[][] MALFORMED_I18_NAME_BYTES =
- new byte[][] {
- // Too short.
- new byte[0],
- new byte[] {(byte) 0x01},
- new byte[] {(byte) 0x01, (byte) 0x02},
- // Length value of 0x02 shorter than the length of the language code field
- // (i.e. 3).
- new byte[] {
- (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0xb0, (byte) 0xb1},
- // Length value of 0xff longer than payload size.
- new byte[] {
- (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0xb0, (byte) 0xb1}
- };
+ /**
+ * Helper function for generating default test data. The test data include the language code
+ * and text field.
+ *
+ * @return byte[] of data
+ * @throws IOException
+ */
+ private byte[] getDefaultTestData() throws IOException {
+ return getTestData(TEST_LANGUAGE, TEST_TEXT);
+ }
- private static final I18NameTestMapping[] I18_NAME_MAPPINGS =
- new I18NameTestMapping[] {
- new I18NameTestMapping(
- new byte[] {
- (byte) 0x09, (byte) 0x65, (byte) 0x6e, (byte) 0x00,
- (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74,
- (byte) 0x41, (byte) 0x70},
- "en", Locale.ENGLISH, "testAp"),
- // TODO: Make sure the ISO-639 alpha-3 code is properly parsed (b/30311144).
- /*
- new I18NameTestMapping(
- new byte[] {
- (byte) 0x09, (byte) 0x65, (byte) 0x6e, (byte) 0x67,
- (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74,
- (byte) 0x41, (byte) 0x70},
- "eng", Locale.ENGLISH, "testAp"),
- */
- new I18NameTestMapping(
- new byte[] {
- (byte) 0x0b, (byte) 0x66, (byte) 0x72, (byte) 0x00,
- (byte) 0x62, (byte) 0x6c, (byte) 0x61, (byte) 0x68,
- (byte) 0x62, (byte) 0x6c, (byte) 0x61, (byte) 0x68},
- "fr", Locale.FRENCH, "blahblah")
- };
+ /**
+ * Helper function for returning a buffer containing a I18Name test data.
+ *
+ * @Param data The byte array of I18Name data
+ * @param length The length value to set in the I18Name header
+ * @return {@link ByteBuffer}
+ * @throws IOException
+ */
+ private ByteBuffer getTestBuffer(byte[] data, int length) throws IOException {
+ // Allocate extra byte for storing the length field.
+ ByteBuffer buffer = ByteBuffer.allocate(data.length + 1);
+ buffer.put((byte) length);
+ buffer.put(data);
+ buffer.position(0);
+ return buffer;
+ }
/**
- * Verifies that parsing malformed I18Name bytes results in a ProtocolException.
+ * Verify that BufferUnderflowException will be thrown when parsing from an empty buffer.
+ *
+ * @throws Exception
*/
- @Test
- public void testMalformedI18NameBytes() {
- for (byte[] malformedBytes : MALFORMED_I18_NAME_BYTES) {
- try {
- I18Name i18Name = new I18Name(ByteBuffer.wrap(
- malformedBytes).order(ByteOrder.LITTLE_ENDIAN));
- } catch (ProtocolException e) {
- continue;
- }
- fail("Expected exception while parsing malformed I18 Name bytes: " + malformedBytes);
- }
+ @Test(expected = BufferUnderflowException.class)
+ public void parseEmptyBuffer() throws Exception {
+ I18Name.parse(ByteBuffer.allocate(0));
+ }
+
+ /**
+ * Verify that BufferUnderflowException will be thrown when the length field is set to more
+ * than the actual buffer size.
+ *
+ * @throws Exception
+ */
+ @Test(expected = BufferUnderflowException.class)
+ public void parseTruncatedBuffer() throws Exception {
+ byte[] data = getDefaultTestData();
+ ByteBuffer buffer = getTestBuffer(data, data.length);
+ buffer.limit(buffer.remaining() - 1);
+ I18Name.parse(buffer);
}
/**
- * Verifies that a sampling of valid I18Name bytes are properly parsed.
+ * Verify that ProtocolException will be thrown when the length field is set to less than
+ * the minimum.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferWithLengthLessThanMinimum() throws Exception {
+ byte[] data = getDefaultTestData();
+ I18Name.parse(getTestBuffer(data, I18Name.MINIMUM_LENGTH - 1));
+ }
+
+ /**
+ * Verify that the expected I18Name will be returned when parsing a buffer contained the
+ * predefined test data.
+ *
+ * @throws Exception
*/
@Test
- public void testI18NameParsing() {
+ public void parseBufferWithDefaultTestData() throws Exception {
+ byte[] data = getDefaultTestData();
+ I18Name actualName = I18Name.parse(getTestBuffer(data, data.length));
+ I18Name expectedName = new I18Name(TEST_LANGUAGE, TEST_LOCALE, TEST_TEXT);
+ assertEquals(expectedName, actualName);
+ }
- for (I18NameTestMapping testMapping : I18_NAME_MAPPINGS) {
- try {
+ /**
+ * Verify that the expected I18Name will be returned when parsing a buffer contained
+ * a non-English (French) language.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithFrenchData() throws Exception {
+ // Test data for French.
+ String language = "fr";
+ String text = "Hello World";
+ byte[] data = getTestData(language, text);
+ I18Name actualName = I18Name.parse(getTestBuffer(data, data.length));
+ I18Name expectedName = new I18Name(language, Locale.forLanguageTag(language), text);
+ assertEquals(expectedName, actualName);
+ }
- I18Name i18Name = new I18Name(ByteBuffer.wrap(
- testMapping.mBytes).order(ByteOrder.LITTLE_ENDIAN));
- assertEquals(testMapping.mExpectedLanguage, i18Name.getLanguage());
- assertEquals(testMapping.mExpectedLocale, i18Name.getLocale());
- assertEquals(testMapping.mExpectedText, i18Name.getText());
- } catch (ProtocolException e) {
- fail("Exception encountered during parsing: " + e);
- }
- }
+ /**
+ * Verify that an I18Name with an empty text will be returned when parsing a buffer contained
+ * an empty text field.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithEmptyText() throws Exception {
+ byte[] data = getTestData(TEST_LANGUAGE, "");
+ I18Name actualName = I18Name.parse(getTestBuffer(data, data.length));
+ I18Name expectedName = new I18Name(TEST_LANGUAGE, TEST_LOCALE, "");
+ assertEquals(expectedName, actualName);
}
}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/IPAddressTypeAvailabilityElementTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/IPAddressTypeAvailabilityElementTest.java
new file mode 100644
index 000000000..bbe814832
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/IPAddressTypeAvailabilityElementTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.server.wifi.hotspot2.anqp;
+
+import static org.junit.Assert.assertEquals;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+
+import java.net.ProtocolException;
+import java.nio.ByteBuffer;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.hotspot2.anqp.IPAddressTypeAvailabilityElement}.
+ */
+@SmallTest
+public class IPAddressTypeAvailabilityElementTest {
+ private static final int TEST_IPV4_AVAILABILITY =
+ IPAddressTypeAvailabilityElement.IPV4_PUBLIC;
+ private static final int TEST_IPV6_AVAILABILITY =
+ IPAddressTypeAvailabilityElement.IPV6_AVAILABLE;
+
+ private static int getIPAvailability() {
+ return (TEST_IPV4_AVAILABILITY << 2) | TEST_IPV6_AVAILABILITY;
+ }
+
+ /**
+ * Verify that ProtocolException will be thrown when parsing an empty buffer.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferEmptyBuffer() throws Exception {
+ IPAddressTypeAvailabilityElement.parse(ByteBuffer.allocate(0));
+ }
+
+ /**
+ * Verify that ProtocolException will be thrown when parsing an buffer containing excess
+ * data.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferWithExcessData() throws Exception {
+ ByteBuffer buffer = ByteBuffer.allocate(
+ IPAddressTypeAvailabilityElement.EXPECTED_BUFFER_LENGTH + 1);
+ buffer.put((byte) getIPAvailability());
+ buffer.put((byte) 0); // Excess data.
+ buffer.position(0);
+ IPAddressTypeAvailabilityElement.parse(ByteBuffer.allocate(0));
+ }
+
+ /**
+ * Verify that the expected IPAddressTypeAvailabilityElement is returned when parsing
+ * a buffer containing the test data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithTestData() throws Exception {
+ ByteBuffer buffer = ByteBuffer.allocate(
+ IPAddressTypeAvailabilityElement.EXPECTED_BUFFER_LENGTH);
+ buffer.put((byte) getIPAvailability());
+ buffer.position(0);
+
+ IPAddressTypeAvailabilityElement expectedElement = new IPAddressTypeAvailabilityElement(
+ TEST_IPV4_AVAILABILITY, TEST_IPV6_AVAILABILITY);
+ assertEquals(expectedElement, IPAddressTypeAvailabilityElement.parse(buffer));
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/RoamingConsortiumElementTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/RoamingConsortiumElementTest.java
new file mode 100644
index 000000000..4e3bd1f9c
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/RoamingConsortiumElementTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016 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.server.wifi.hotspot2.anqp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
+
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.ProtocolException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.hotspot2.anqp.RoamingConsortiumElement}.
+ */
+@SmallTest
+public class RoamingConsortiumElementTest {
+ // Default test data. Each test data contained a pair indicating the number of bytes for the
+ // OI and the value of the OI.
+ private static final Pair<Integer, Long> TEST_OI1 = new Pair<Integer, Long>(1, 0x12L);
+ private static final Pair<Integer, Long> TEST_OI2 = new Pair<Integer, Long>(2, 0x1234L);
+ private static final Pair<Integer, Long> TEST_OI3 = new Pair<Integer, Long>(4, 0x12345678L);
+ private static final Pair<Integer, Long> TEST_OI4 = new Pair<Integer, Long>(8, 0x1234567890L);
+
+ /**
+ * Helper function for appending an OI field to the given output stream.
+ *
+ * @param stream The output stream to write to
+ * @param OI The OI to write to the output stream
+ */
+ private void appendOI(ByteArrayOutputStream stream, Pair<Integer, Long> oi) {
+ stream.write(oi.first.byteValue());
+ // Write the OI data in big-endian.
+ for (int i = oi.first.intValue() - 1; i >= 0; i--) {
+ stream.write((byte) ((oi.second.longValue() >> i * Byte.SIZE) & 0xFF));
+ }
+ }
+ /**
+ * Helper function for generating test data with the provided OIs.
+ *
+ * @param OIs The OIs to generate the data with
+ * @return byte[] of data
+ * @throws IOException
+ */
+ private byte[] getTestData(List<Pair<Integer, Long>> ois) throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ for (Pair<Integer, Long> oi : ois) {
+ appendOI(stream, oi);
+ }
+ return stream.toByteArray();
+ }
+
+ /**
+ * Helper function for generating test data using the predefined OIs.
+ *
+ * @return byte[] of data
+ * @throws IOException
+ */
+ private byte[] getDefaultTestData() throws IOException {
+ List<Pair<Integer, Long>> oiList = new ArrayList<>();
+ oiList.add(TEST_OI1);
+ oiList.add(TEST_OI2);
+ oiList.add(TEST_OI3);
+ oiList.add(TEST_OI4);
+ return getTestData(oiList);
+ }
+
+ /**
+ * Helper function for creating a RoamingConsortiumElement using the predefined OIs.
+ *
+ * @return {@link RoamingConsortiumElement}
+ */
+ private RoamingConsortiumElement getDefaultElement() {
+ List<Long> oiList = new ArrayList<>();
+ oiList.add(TEST_OI1.second);
+ oiList.add(TEST_OI2.second);
+ oiList.add(TEST_OI3.second);
+ oiList.add(TEST_OI4.second);
+ return new RoamingConsortiumElement(oiList);
+ }
+
+ /**
+ * Verify that no exception will be thrown when parsing an empty buffer and the returned
+ * RoamingConsortiumElement will contained an empty list of OIs.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseEmptyBuffer() throws Exception {
+ RoamingConsortiumElement element = RoamingConsortiumElement.parse(ByteBuffer.allocate(0));
+ assertTrue(element.getOIs().isEmpty());
+ }
+
+ /**
+ * Verify that BufferUnderflowException will be thrown when parsing a truncated buffer
+ * (missing a byte at the end).
+ *
+ * @throws Exception
+ */
+ @Test(expected = BufferUnderflowException.class)
+ public void parseTruncatedBuffer() throws Exception {
+ ByteBuffer buffer = ByteBuffer.wrap(getDefaultTestData());
+ buffer.limit(buffer.remaining() - 1);
+ RoamingConsortiumElement.parse(buffer);
+ }
+
+ /**
+ * Verify that an expected RoamingConsortiumElement will be returned when parsing a buffer
+ * containing valid data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithDefaultTestData() throws Exception {
+ // Setup expected element.
+ RoamingConsortiumElement expectedElement = getDefaultElement();
+
+ ByteBuffer buffer = ByteBuffer.wrap(getDefaultTestData());
+ assertEquals(expectedElement, RoamingConsortiumElement.parse(buffer));
+ }
+
+ /**
+ * Verify that ProtocolException will be thrown when parsing a buffer contained an OI length
+ * that's less than minimum allowed.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferWithOILengthLessThanMinimum() throws Exception {
+ ByteBuffer buffer = ByteBuffer.allocate(1);
+ buffer.put((byte) (RoamingConsortiumElement.MINIMUM_OI_LENGTH - 1));
+ buffer.position(0);
+ RoamingConsortiumElement.parse(buffer);
+ }
+
+ /**
+ * Verify that ProtocolException will be thrown when parsing a buffer contained an OI length
+ * that's more than maximum allowed.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferWithOILengthMoreThanMaximum() throws Exception {
+ ByteBuffer buffer = ByteBuffer.allocate(1);
+ buffer.put((byte) (RoamingConsortiumElement.MAXIMUM_OI_LENGTH + 1));
+ buffer.position(0);
+ RoamingConsortiumElement.parse(buffer);
+ }
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/VenueNameElementTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/VenueNameElementTest.java
index 90c3d25be..407e7bfde 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/VenueNameElementTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/anqp/VenueNameElementTest.java
@@ -16,117 +16,154 @@
package com.android.server.wifi.hotspot2.anqp;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Test;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.net.ProtocolException;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Locale;
/**
- * Unit tests for {@link com.android.server.wifi.anqp.VenueNameElement}.
+ * Unit tests for {@link com.android.server.wifi.hotspot2.anqp.VenueNameElement}.
*/
@SmallTest
public class VenueNameElementTest {
- private static class VenueNameElementTestMapping {
- byte[] mBytes;
- List<I18Name> mExpectedNames;
- VenueNameElementTestMapping(byte[] bytes, List<I18Name> names) {
- this.mBytes = bytes;
- this.mExpectedNames = names;
+ private static final String TEST_LANGUAGE = "en";
+ private static final Locale TEST_LOCALE = Locale.forLanguageTag(TEST_LANGUAGE);
+ private static final String TEST_VENUE_NAME1 = "Venue1";
+ private static final String TEST_VENUE_NAME2 = "Venue2";
+
+ /**
+ * Helper function for appending a Venue Name to an output stream.
+ *
+ * @param stream Stream to write to
+ * @param venue The venue name string
+ * @throws IOException
+ */
+ private void appendVenue(ByteArrayOutputStream stream, String venue) throws IOException {
+ byte[] venueBytes = venue.getBytes(StandardCharsets.UTF_8);
+ int length = I18Name.LANGUAGE_CODE_LENGTH + venue.length();
+ stream.write((byte) length);
+ stream.write(TEST_LANGUAGE.getBytes(StandardCharsets.US_ASCII));
+ stream.write(new byte[]{(byte) 0x0}); // Padding for language code.
+ stream.write(venueBytes);
+ }
+
+ /**
+ * Helper function for generating test data.
+ *
+ * @return byte[] of data
+ * @throws IOException
+ */
+ private byte[] getTestData(String[] names) throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ // Venue info data not currently used.
+ stream.write(new byte[VenueNameElement.VENUE_INFO_LENGTH]);
+ for (String name : names) {
+ appendVenue(stream, name);
}
+ return stream.toByteArray();
}
- // Raw bytes, laid out in little endian, that represent malformed Venue Name Element payloads
- // that do not conform to IEEE802.11-2012 section 8.4.4.4.
- private static final byte[][] MALFORMED_VENUE_NAME_ELEMENT_BYTES =
- new byte[][] {
- // Too short.
- new byte[0],
- new byte[] {(byte) 0x01},
- // 1 trailing byte.
- new byte[] {
- (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x65,
- (byte) 0x6e, (byte) 0x00, (byte) 0xab},
- // Length field (0xff) exceeds remaining payload size.
- new byte[] {
- (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0x65,
- (byte) 0x6e, (byte) 0x00, (byte) 0xab},
- };
-
- private static final VenueNameElementTestMapping[] VENUE_NAME_ELEMENT_MAPPINGS =
- new VenueNameElementTestMapping[] {
- // 0 Venue name Duples (i.e. Venue info field only).
- new VenueNameElementTestMapping(
- new byte[] {
- (byte) 0x00, (byte) 0x00},
- new ArrayList<I18Name>()),
- // 1 Venue name Duple.
- new VenueNameElementTestMapping(
- new byte[] {
- (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x65,
- (byte) 0x6e, (byte) 0x00, (byte) 0x74, (byte) 0x65,
- (byte) 0x73, (byte) 0x74, (byte) 0x56, (byte) 0x65,
- (byte) 0x6e, (byte) 0x75, (byte) 0x65, (byte) 0x31},
- new ArrayList<I18Name>() {{
- add(new I18Name("en", Locale.ENGLISH, "testVenue1"));
- }}),
- // 2 Venue Name Duples.
- new VenueNameElementTestMapping(
- new byte[] {
- (byte) 0x00, (byte) 0x00, (byte) 0x0d, (byte) 0x65,
- (byte) 0x6e, (byte) 0x00, (byte) 0x74, (byte) 0x65,
- (byte) 0x73, (byte) 0x74, (byte) 0x56, (byte) 0x65,
- (byte) 0x6e, (byte) 0x75, (byte) 0x65, (byte) 0x31,
- (byte) 0x0d, (byte) 0x66, (byte) 0x72, (byte) 0x00,
- (byte) 0x74, (byte) 0x65, (byte) 0x73, (byte) 0x74,
- (byte) 0x56, (byte) 0x65, (byte) 0x6e, (byte) 0x75,
- (byte) 0x65, (byte) 0x32},
- new ArrayList<I18Name>() {{
- add(new I18Name("en", Locale.ENGLISH, "testVenue1"));
- add(new I18Name("fr", Locale.FRENCH, "testVenue2"));
- }}),
- };
+ /**
+ * Verify that BufferUnderflowException will be thrown when parsing an empty buffer.
+ *
+ * @throws Exception
+ */
+ @Test(expected = BufferUnderflowException.class)
+ public void parseEmptyBuffer() throws Exception {
+ VenueNameElement.parse(ByteBuffer.allocate(0));
+ }
+
+ /**
+ * Verify that BufferUnderflowException will be thrown when parsing a truncated buffer
+ * (missing a byte at the end).
+ *
+ * @throws Exception
+ */
+ @Test(expected = BufferUnderflowException.class)
+ public void parseTruncatedBuffer() throws Exception {
+ ByteBuffer buffer = ByteBuffer.wrap(getTestData(new String[] {TEST_VENUE_NAME1}));
+ // Truncate a byte at the end.
+ buffer.limit(buffer.remaining() - 1);
+ VenueNameElement.parse(buffer);
+ }
/**
- * Verifies that parsing malformed Venue Name Element bytes results in a ProtocolException.
+ * Verify that a VenueNameElement with empty name list will be returned when parsing a buffer
+ * contained no venue name (only contained the venue info data).
+ *
+ * @throws Exception
*/
@Test
- public void testMalformedVenueNameElementBytes() {
- for (byte[] invalidBytes : MALFORMED_VENUE_NAME_ELEMENT_BYTES) {
- try {
- VenueNameElement venueNameElement = new VenueNameElement(
- Constants.ANQPElementType.ANQPVenueName,
- ByteBuffer.wrap(invalidBytes).order(ByteOrder.LITTLE_ENDIAN));
- } catch (ProtocolException e) {
- continue;
- }
- fail("Expected exception while parsing malformed Venue Name Element bytes: "
- + invalidBytes);
- }
+ public void parseBufferWithEmptyVenueName() throws Exception {
+ ByteBuffer buffer = ByteBuffer.wrap(getTestData(new String[0]));
+ assertTrue(VenueNameElement.parse(buffer).getNames().isEmpty());
+ }
+ /**
+ * Verify that an expected VenueNameElement will be returned when parsing a buffer contained
+ * valid Venue Name data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void parseBufferWithValidVenueNames() throws Exception {
+ // Setup expected element.
+ List<I18Name> nameList = new ArrayList<>();
+ nameList.add(new I18Name(TEST_LANGUAGE, TEST_LOCALE, TEST_VENUE_NAME1));
+ nameList.add(new I18Name(TEST_LANGUAGE, TEST_LOCALE, TEST_VENUE_NAME2));
+ VenueNameElement expectedElement = new VenueNameElement(nameList);
+
+ ByteBuffer buffer = ByteBuffer.wrap(
+ getTestData(new String[] {TEST_VENUE_NAME1, TEST_VENUE_NAME2}));
+ assertEquals(expectedElement, VenueNameElement.parse(buffer));
}
/**
- * Verifies that valid Venue Name Element bytes are properly parsed.
+ * Verify that an expected VenueNameElement will be returned when parsing a buffer
+ * contained a venue name with the maximum length.
+ *
+ * @throws Exception
*/
@Test
- public void testVenueNameElementParsing() {
- try {
- for (VenueNameElementTestMapping testMapping : VENUE_NAME_ELEMENT_MAPPINGS) {
- VenueNameElement venueNameElement =
- new VenueNameElement(
- Constants.ANQPElementType.ANQPVenueName,
- ByteBuffer.wrap(testMapping.mBytes).order(ByteOrder.LITTLE_ENDIAN));
- assertEquals(testMapping.mExpectedNames, venueNameElement.getNames());
- }
- } catch (ProtocolException e) {
- fail("Exception encountered during parsing: " + e);
- }
+ public void parseBufferWithMaxLengthVenueName() throws Exception {
+ // Venue name with maximum length.
+ byte[] textData = new byte[VenueNameElement.MAXIMUM_VENUE_NAME_LENGTH];
+ Arrays.fill(textData, (byte) 'a');
+ String text = new String(textData);
+ ByteBuffer buffer = ByteBuffer.wrap(getTestData(new String[] {text}));
+
+ // Setup expected element.
+ List<I18Name> nameList = new ArrayList<>();
+ nameList.add(new I18Name(TEST_LANGUAGE, TEST_LOCALE, text));
+ VenueNameElement expectedElement = new VenueNameElement(nameList);
+
+ assertEquals(expectedElement, VenueNameElement.parse(buffer));
+ }
+
+ /**
+ * Verify that ProtocolException will be thrown when parsing a buffer contained a
+ * venue name that exceeds the maximum length.
+ *
+ * @throws Exception
+ */
+ @Test(expected = ProtocolException.class)
+ public void parseBufferWithVenueNameLengthExceedMax() throws Exception {
+ byte[] textData = new byte[VenueNameElement.MAXIMUM_VENUE_NAME_LENGTH + 1];
+ Arrays.fill(textData, (byte) 'a');
+ String text = new String(textData);
+ ByteBuffer buffer = ByteBuffer.wrap(getTestData(new String[] {text}));
+ VenueNameElement.parse(buffer);
}
}