Skip to content

Commit 5c0f525

Browse files
authored
Add unit tests for Resources reading (#3984)
1 parent 830d640 commit 5c0f525

File tree

1 file changed

+214
-0
lines changed

1 file changed

+214
-0
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
package com.codename1.ui.util;
2+
3+
import org.junit.jupiter.api.AfterEach;
4+
import org.junit.jupiter.api.Test;
5+
6+
import java.io.ByteArrayInputStream;
7+
import java.io.ByteArrayOutputStream;
8+
import java.io.DataOutputStream;
9+
import java.io.IOException;
10+
import java.io.InputStream;
11+
import java.nio.charset.StandardCharsets;
12+
import java.util.ArrayList;
13+
import java.util.Arrays;
14+
import java.util.Collection;
15+
import java.util.Enumeration;
16+
import java.util.Hashtable;
17+
import java.util.List;
18+
19+
import static org.junit.jupiter.api.Assertions.*;
20+
21+
public class ResourcesTest {
22+
23+
@AfterEach
24+
public void resetPassword() {
25+
Resources.setPassword(null);
26+
}
27+
28+
@Test
29+
public void testOpenFileParsesHeaderDataUiAndL10N() throws Exception {
30+
byte[] resourceBytes = createStandardResourceStream();
31+
Resources resources = new Resources(new ByteArrayInputStream(resourceBytes), 160);
32+
33+
assertEquals(2, resources.getMajorVersion());
34+
assertEquals(5, resources.getMinorVersion());
35+
assertArrayEquals(new String[]{"metaOne", "metaTwo"}, resources.getMetaData());
36+
37+
assertEquals(Resources.MAGIC_DATA, resources.getResourceType("binaryData"));
38+
assertEquals(Resources.MAGIC_UI, resources.getResourceType("uiDescriptor"));
39+
assertEquals(Resources.MAGIC_L10N, resources.getResourceType("translations"));
40+
41+
assertArrayEquals(new String[]{"binaryData"}, resources.getDataResourceNames());
42+
assertArrayEquals(new String[]{"uiDescriptor"}, resources.getUIResourceNames());
43+
assertArrayEquals(new String[]{"translations"}, resources.getL10NResourceNames());
44+
45+
List<String> resourceNames = Arrays.asList(resources.getResourceNames());
46+
assertTrue(resourceNames.contains("binaryData"));
47+
assertTrue(resourceNames.contains("uiDescriptor"));
48+
assertTrue(resourceNames.contains("translations"));
49+
50+
assertInputStreamContentEquals(new byte[]{10, 20, 30}, resources.getData("binaryData"));
51+
assertInputStreamContentEquals(new byte[]{1, 2, 3, 4}, resources.getUi("uiDescriptor"));
52+
53+
Hashtable<String, String> en = resources.getL10N("translations", "en");
54+
assertEquals("Hello", en.get("greeting"));
55+
assertEquals("Bye", en.get("farewell"));
56+
57+
Hashtable<String, String> es = resources.getL10N("translations", "es");
58+
assertEquals("Hola", es.get("greeting"));
59+
assertEquals("Adios", es.get("farewell"));
60+
61+
Enumeration localeEnum = resources.listL10NLocales("translations");
62+
Collection<String> locales = new ArrayList<String>();
63+
while (localeEnum.hasMoreElements()) {
64+
locales.add((String) localeEnum.nextElement());
65+
}
66+
assertTrue(locales.contains("en"));
67+
assertTrue(locales.contains("es"));
68+
69+
Collection<String> localeSet = resources.l10NLocaleSet("translations");
70+
assertTrue(localeSet.contains("en"));
71+
assertTrue(localeSet.contains("es"));
72+
}
73+
74+
@Test
75+
public void testPasswordProtectedResourceRequiresPassword() throws Exception {
76+
byte[] resourceBytes = createPasswordProtectedResourceStream("abcd", "protectedData", new byte[]{9, 8});
77+
assertThrows(IllegalStateException.class, () -> new Resources(new ByteArrayInputStream(resourceBytes), -1));
78+
}
79+
80+
@Test
81+
public void testPasswordProtectedResourceDecodesEntries() throws Exception {
82+
byte[] resourceBytes = createPasswordProtectedResourceStream("abcd", "protectedData", new byte[]{9, 8});
83+
Resources.setPassword("abcd");
84+
Resources resources = new Resources(new ByteArrayInputStream(resourceBytes), -1);
85+
86+
assertArrayEquals(new String[]{"protectedData"}, resources.getDataResourceNames());
87+
assertEquals(Resources.MAGIC_DATA, resources.getResourceType("protectedData"));
88+
assertInputStreamContentEquals(new byte[]{9, 8}, resources.getData("protectedData"));
89+
}
90+
91+
@Test
92+
public void testInvalidResourceCountThrows() throws IOException {
93+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
94+
DataOutputStream dos = new DataOutputStream(baos);
95+
dos.writeShort(-1);
96+
dos.flush();
97+
98+
byte[] resourceBytes = baos.toByteArray();
99+
assertThrows(IOException.class, () -> new Resources(new ByteArrayInputStream(resourceBytes), -1));
100+
}
101+
102+
private static byte[] createStandardResourceStream() throws IOException {
103+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
104+
DataOutputStream dos = new DataOutputStream(baos);
105+
106+
dos.writeShort(4);
107+
108+
dos.writeByte(Resources.MAGIC_HEADER);
109+
dos.writeUTF("headerEntry");
110+
dos.writeShort(0);
111+
dos.writeShort(2);
112+
dos.writeShort(5);
113+
dos.writeShort(2);
114+
dos.writeUTF("metaOne");
115+
dos.writeUTF("metaTwo");
116+
117+
dos.writeByte(Resources.MAGIC_DATA);
118+
dos.writeUTF("binaryData");
119+
dos.writeInt(3);
120+
dos.write(new byte[]{10, 20, 30});
121+
122+
dos.writeByte(Resources.MAGIC_UI);
123+
dos.writeUTF("uiDescriptor");
124+
dos.writeInt(4);
125+
dos.write(new byte[]{1, 2, 3, 4});
126+
127+
dos.writeByte(Resources.MAGIC_L10N);
128+
dos.writeUTF("translations");
129+
dos.writeShort(2);
130+
dos.writeShort(2);
131+
dos.writeUTF("greeting");
132+
dos.writeUTF("farewell");
133+
dos.writeUTF("en");
134+
dos.writeUTF("Hello");
135+
dos.writeUTF("Bye");
136+
dos.writeUTF("es");
137+
dos.writeUTF("Hola");
138+
dos.writeUTF("Adios");
139+
140+
dos.flush();
141+
return baos.toByteArray();
142+
}
143+
144+
private static byte[] createPasswordProtectedResourceStream(String password, String id, byte[] payload) throws IOException {
145+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
146+
DataOutputStream dos = new DataOutputStream(baos);
147+
148+
dos.writeShort(2);
149+
150+
dos.writeByte(Resources.MAGIC_PASSWORD);
151+
byte[] key = password.getBytes(StandardCharsets.UTF_8);
152+
char[] encodedPassword = new char[]{(char) ('l' ^ key[0]), (char) ('w' ^ key[1])};
153+
dos.writeUTF(new String(encodedPassword));
154+
155+
KeyEncoder encoder = new KeyEncoder(key, 2);
156+
dos.writeByte(encoder.encodeByte(Resources.MAGIC_DATA & 0xff));
157+
dos.writeUTF(encoder.encodeString(id));
158+
dos.writeInt(payload.length);
159+
dos.write(payload);
160+
161+
dos.flush();
162+
return baos.toByteArray();
163+
}
164+
165+
private static void assertInputStreamContentEquals(byte[] expected, InputStream stream) throws IOException {
166+
assertNotNull(stream);
167+
try (InputStream in = stream) {
168+
assertArrayEquals(expected, readAll(in));
169+
}
170+
}
171+
172+
private static byte[] readAll(InputStream inputStream) throws IOException {
173+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
174+
byte[] buffer = new byte[32];
175+
int len;
176+
while ((len = inputStream.read(buffer)) != -1) {
177+
baos.write(buffer, 0, len);
178+
}
179+
return baos.toByteArray();
180+
}
181+
182+
private static final class KeyEncoder {
183+
private final byte[] key;
184+
private int offset;
185+
186+
private KeyEncoder(byte[] key, int initialOffset) {
187+
this.key = key;
188+
this.offset = initialOffset % key.length;
189+
}
190+
191+
private byte encodeByte(int value) {
192+
int encoded = value ^ (key[offset] & 0xff);
193+
advance();
194+
return (byte) encoded;
195+
}
196+
197+
private String encodeString(String value) {
198+
char[] chars = value.toCharArray();
199+
char[] encoded = new char[chars.length];
200+
for (int i = 0; i < chars.length; i++) {
201+
encoded[i] = (char) (chars[i] ^ (key[offset] & 0xff));
202+
advance();
203+
}
204+
return new String(encoded);
205+
}
206+
207+
private void advance() {
208+
offset++;
209+
if (offset == key.length) {
210+
offset = 0;
211+
}
212+
}
213+
}
214+
}

0 commit comments

Comments
 (0)