c008dec7f3e9ff6f8a971ff4ad2224d301f46d13
[nikiroo-utils.git] / src / be / nikiroo / utils / test_code / SerialTest.java
1 package be.nikiroo.utils.test_code;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.NotSerializableException;
8 import java.net.URL;
9 import java.util.Arrays;
10
11 import be.nikiroo.utils.serial.Exporter;
12 import be.nikiroo.utils.serial.Importer;
13 import be.nikiroo.utils.test.TestCase;
14 import be.nikiroo.utils.test.TestLauncher;
15
16 class SerialTest extends TestLauncher {
17 /**
18 * Required for Import/Export of objects.
19 */
20 public SerialTest() {
21 this(null);
22 }
23
24 private void encodeRecodeTest(TestCase test, Object data) throws Exception {
25 byte[] encoded = toBytes(data, true);
26 Object redata = fromBytes(toBytes(data, false));
27 byte[] reencoded = toBytes(redata, true);
28
29 // We suppose text mode
30 if (encoded.length < 256 && reencoded.length < 256) {
31 test.assertEquals("Different data after encode/decode/encode",
32 new String(encoded, "UTF-8"),
33 new String(reencoded, "UTF-8"));
34 } else {
35 test.assertEquals("Different data after encode/decode/encode",
36 true, Arrays.equals(encoded, reencoded));
37 }
38 }
39
40 // try to remove pointer addresses
41 private byte[] toBytes(Object data, boolean clearRefs)
42 throws NotSerializableException, IOException {
43 ByteArrayOutputStream out = new ByteArrayOutputStream();
44 new Exporter(out).append(data);
45 out.flush();
46
47 if (clearRefs) {
48 String tmp = new String(out.toByteArray(), "UTF-8");
49 tmp = tmp.replaceAll("@[0-9]*", "@REF");
50 return tmp.getBytes("UTF-8");
51 }
52
53 return out.toByteArray();
54 }
55
56 private Object fromBytes(byte[] data) throws NoSuchFieldException,
57 NoSuchMethodException, ClassNotFoundException,
58 NullPointerException, IOException {
59
60 InputStream in = new ByteArrayInputStream(data);
61 try {
62 return new Importer().read(in).getValue();
63 } finally {
64 in.close();
65 }
66 }
67
68 public SerialTest(String[] args) {
69 super("Serial test", args);
70
71 addTest(new TestCase("Simple class Import/Export") {
72 @Override
73 public void test() throws Exception {
74 Data data = new Data(42);
75 encodeRecodeTest(this, data);
76 }
77 });
78 addTest(new TestCase() {
79 @SuppressWarnings("unused")
80 private TestCase me = setName("Anonymous inner class");
81
82 @Override
83 public void test() throws Exception {
84 Data data = new Data() {
85 @SuppressWarnings("unused")
86 int value = 42;
87 };
88 encodeRecodeTest(this, data);
89 }
90 });
91 addTest(new TestCase() {
92 @SuppressWarnings("unused")
93 private TestCase me = setName("Array of anonymous inner classes");
94
95 @Override
96 public void test() throws Exception {
97 Data[] data = new Data[] { new Data() {
98 @SuppressWarnings("unused")
99 int value = 42;
100 } };
101
102 byte[] encoded = toBytes(data, false);
103 Object redata = fromBytes(encoded);
104
105 // Comparing the 2 arrays won't be useful, because the @REFs
106 // will be ZIP-encoded; so we parse and re-encode each object
107
108 byte[] encoded1 = toBytes(data[0], true);
109 byte[] reencoded1 = toBytes(((Object[]) redata)[0], true);
110
111 assertEquals("Different data after encode/decode/encode", true,
112 Arrays.equals(encoded1, reencoded1));
113 }
114 });
115 addTest(new TestCase("URL Import/Export") {
116 @Override
117 public void test() throws Exception {
118 URL data = new URL("https://fanfan.be/");
119 encodeRecodeTest(this, data);
120 }
121 });
122 addTest(new TestCase("URL-String Import/Export") {
123 @Override
124 public void test() throws Exception {
125 String data = new URL("https://fanfan.be/").toString();
126 encodeRecodeTest(this, data);
127 }
128 });
129 addTest(new TestCase("URL/URL-String arrays Import/Export") {
130 @Override
131 public void test() throws Exception {
132 final String url = "https://fanfan.be/";
133 Object[] data = new Object[] { new URL(url), url };
134
135 byte[] encoded = toBytes(data, false);
136 Object redata = fromBytes(encoded);
137
138 // Comparing the 2 arrays won't be useful, because the @REFs
139 // will be ZIP-encoded; so we parse and re-encode each object
140
141 byte[] encoded1 = toBytes(data[0], true);
142 byte[] reencoded1 = toBytes(((Object[]) redata)[0], true);
143 byte[] encoded2 = toBytes(data[1], true);
144 byte[] reencoded2 = toBytes(((Object[]) redata)[1], true);
145
146 assertEquals("Different data 1 after encode/decode/encode",
147 true, Arrays.equals(encoded1, reencoded1));
148 assertEquals("Different data 2 after encode/decode/encode",
149 true, Arrays.equals(encoded2, reencoded2));
150 }
151 });
152 addTest(new TestCase("Import/Export with nested objects") {
153 @Override
154 public void test() throws Exception {
155 Data data = new DataObject(new Data(21));
156 encodeRecodeTest(this, data);
157 }
158 });
159 addTest(new TestCase("Import/Export with nested objects forming a loop") {
160 @Override
161 public void test() throws Exception {
162 DataLoop data = new DataLoop("looping");
163 data.next = new DataLoop("level 2");
164 data.next.next = data;
165 encodeRecodeTest(this, data);
166 }
167 });
168 addTest(new TestCase("Array in Object Import/Export") {
169 @Override
170 public void test() throws Exception {
171 Object data = new DataArray();// new String[] { "un", "deux" };
172 encodeRecodeTest(this, data);
173 }
174 });
175 addTest(new TestCase("Array Import/Export") {
176 @Override
177 public void test() throws Exception {
178 Object data = new String[] { "un", "deux" };
179 encodeRecodeTest(this, data);
180 }
181 });
182 addTest(new TestCase("Enum Import/Export") {
183 @Override
184 public void test() throws Exception {
185 Object data = EnumToSend.FANFAN;
186 encodeRecodeTest(this, data);
187 }
188 });
189 }
190
191 class DataArray {
192 public String[] data = new String[] { "un", "deux" };
193 }
194
195 class Data {
196 private int value;
197
198 private Data() {
199 }
200
201 public Data(int value) {
202 this.value = value;
203 }
204
205 @Override
206 public boolean equals(Object obj) {
207 if (obj instanceof Data) {
208 Data other = (Data) obj;
209 return other.value == this.value;
210 }
211
212 return false;
213 }
214
215 @Override
216 public int hashCode() {
217 return new Integer(value).hashCode();
218 }
219 }
220
221 @SuppressWarnings("unused")
222 class DataObject extends Data {
223 private Data data;
224
225 @SuppressWarnings("synthetic-access")
226 private DataObject() {
227 }
228
229 @SuppressWarnings("synthetic-access")
230 public DataObject(Data data) {
231 this.data = data;
232 }
233 }
234
235 @SuppressWarnings("unused")
236 class DataLoop extends Data {
237 public DataLoop next;
238 private String value;
239
240 @SuppressWarnings("synthetic-access")
241 private DataLoop() {
242 }
243
244 @SuppressWarnings("synthetic-access")
245 public DataLoop(String value) {
246 this.value = value;
247 }
248 }
249
250 enum EnumToSend {
251 FANFAN, TULIPE,
252 }
253 }