/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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.google.devrel.gmscore.tools.apk.arsc;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devrel.gmscore.tools.apk.arsc.ResourceString.Type.UTF16;
import static com.google.devrel.gmscore.tools.apk.arsc.ResourceString.Type.UTF8;
import com.google.common.base.Strings;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
@RunWith(JUnit4.class)
public class ResourceStringTest {
/**
* A special string chosen because it contains a different encoding length compared to its
* character length.
*/
private static final String TEST_STRING = "ābĉ123";
/** Used to test length where length > 0x7F. */
private static final String LENGTH_BYTE_STRING = Strings.repeat("a", 0xFF);
/** Used to test length where length > 0x7FFF. */
private static final String LENGTH_WORD_STRING = Strings.repeat("a", 0xFFFF);
/** Contains the {@code TEST_STRING} in UTF-8 encoding. */
private static final byte[] UTF8_STRING = {0x06, 0x08, // 6 characters; 8 bytes
(byte) 0xC4, (byte) 0x81, 0x62, (byte) 0xC4, (byte) 0x89, 0x31, 0x32, 0x33, // ābĉ123
0x00}; // Null-terminated
/** Contains the {@code TEST_STRING} in UTF-16 encoding. */
private static final byte[] UTF16_STRING = {0x06, 0x00, // Length of string in little-endian
0x01, 0x01, 0x62, 0x00, 0x09, 0x01, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, // ābĉ123
0x00, 0x00}; // Null-terminated
/** Contains the two length prefixes for {@code LENGTH_BYTE_STRING} in UTF-8 encoding. */
private static final byte[] UTF8_LENGTH_BYTE =
{(byte) 0x80, (byte) 0xFF, (byte) 0x80, (byte) 0xFF};
/** Contains the length prefix for {@code LENGTH_BYTE_STRING} in UTF-16 encoding. */
private static final byte[] UTF16_LENGTH_BYTE = {(byte) 0xFF, 0x00};
/** Contains the length prefix for {@code LENGTH_BYTE_WORD} in UTF-16 encoding. */
private static final byte[] UTF16_LENGTH_WORD = {0x00, (byte) 0x80, (byte) 0xFF, (byte) 0xFF};
@Test
public void decodeUtf8String() {
ByteBuffer utf8 = ByteBuffer.wrap(UTF8_STRING).order(ByteOrder.LITTLE_ENDIAN);
assertThat(ResourceString.decodeString(utf8, 0, UTF8)).isEqualTo(TEST_STRING);
}
@Test
public void decodeUtf16String() {
ByteBuffer utf16 = ByteBuffer.wrap(UTF16_STRING).order(ByteOrder.LITTLE_ENDIAN);
assertThat(ResourceString.decodeString(utf16, 0, UTF16)).isEqualTo(TEST_STRING);
}
@Test
public void encodeUtf8String() {
byte[] utf8 = ResourceString.encodeString(TEST_STRING, UTF8);
assertThat(utf8).isEqualTo(UTF8_STRING);
}
@Test
public void encodeUtf16String() {
byte[] utf16 = ResourceString.encodeString(TEST_STRING, UTF16);
assertThat(utf16).isEqualTo(UTF16_STRING);
}
@Test
public void parseLargeUtf8String() {
parseString(LENGTH_BYTE_STRING, UTF8, UTF8_LENGTH_BYTE);
}
@Test
public void parseMediumUtf16String() {
parseString(LENGTH_BYTE_STRING, UTF16, UTF16_LENGTH_BYTE);
}
@Test
public void parseLargeUtf16String() {
parseString(LENGTH_WORD_STRING, UTF16, UTF16_LENGTH_WORD);
}
private void parseString(String str, ResourceString.Type type, byte[] prefix) {
byte[] utf = ResourceString.encodeString(str, type);
byte[] utfPrefix = Arrays.copyOf(utf, prefix.length);
assertThat(utfPrefix).isEqualTo(prefix);
ByteBuffer buffer = ByteBuffer.wrap(utf).order(ByteOrder.LITTLE_ENDIAN);
assertThat(ResourceString.decodeString(buffer, 0, type)).isEqualTo(str);
}
}