blob: 356342e799b2c202ac28b63506256abb08238ba6 [file] [log] [blame]
The Android Open Source Project455ed292009-03-13 13:04:22 -07001/*
2 * Copyright (C) 2009 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
17#include "PhoneticStringUtils.h"
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
Daisuke Miyakawae919af52009-06-26 22:58:32 +090023#include <utils/String8.h>
24
The Android Open Source Project455ed292009-03-13 13:04:22 -070025using namespace android;
26
27class TestExecutor {
28 public:
29 TestExecutor() : m_total_count(0), m_success_count(0), m_success(true) {}
30 bool DoAllTests();
31 private:
32 void DoOneTest(void (TestExecutor::*test)());
33
Daisuke Miyakawa1ec1f3d2009-07-09 14:03:07 +090034 void testUtf32At();
The Android Open Source Project455ed292009-03-13 13:04:22 -070035 void testGetPhoneticallySortableCodePointAscii();
36 void testGetPhoneticallySortableCodePointKana();
Daisuke Miyakawa0c45e822009-03-27 19:41:52 -070037 void testGetPhoneticallySortableCodePointWhitespaceOnly();
The Android Open Source Project455ed292009-03-13 13:04:22 -070038 void testGetPhoneticallySortableCodePointSimpleCompare();
Daisuke Miyakawae919af52009-06-26 22:58:32 +090039 void testGetUtf8FromUtf32();
The Android Open Source Project455ed292009-03-13 13:04:22 -070040 void testGetPhoneticallySortableString();
Daisuke Miyakawad28cdc42009-05-18 14:51:52 +090041 void testGetNormalizedString();
The Android Open Source Project455ed292009-03-13 13:04:22 -070042
43 // Note: When adding a test, do not forget to add it to DoOneTest().
44
45 int m_total_count;
46 int m_success_count;
47
48 bool m_success;
49};
50
51#define ASSERT_EQ_VALUE(input, expected) \
52 ({ \
53 if ((expected) != (input)) { \
54 printf("0x%X(result) != 0x%X(expected)\n", input, expected); \
55 m_success = false; \
56 return; \
57 } \
58 })
59
60#define EXPECT_EQ_VALUE(input, expected) \
61 ({ \
62 if ((expected) != (input)) { \
63 printf("0x%X(result) != 0x%X(expected)\n", input, expected); \
64 m_success = false; \
65 } \
66 })
67
68
69bool TestExecutor::DoAllTests() {
Daisuke Miyakawa1ec1f3d2009-07-09 14:03:07 +090070 DoOneTest(&TestExecutor::testUtf32At);
The Android Open Source Project455ed292009-03-13 13:04:22 -070071 DoOneTest(&TestExecutor::testGetPhoneticallySortableCodePointAscii);
72 DoOneTest(&TestExecutor::testGetPhoneticallySortableCodePointKana);
Daisuke Miyakawa0c45e822009-03-27 19:41:52 -070073 DoOneTest(&TestExecutor::testGetPhoneticallySortableCodePointWhitespaceOnly);
The Android Open Source Project455ed292009-03-13 13:04:22 -070074 DoOneTest(&TestExecutor::testGetPhoneticallySortableCodePointSimpleCompare);
Daisuke Miyakawae919af52009-06-26 22:58:32 +090075 DoOneTest(&TestExecutor::testGetUtf8FromUtf32);
The Android Open Source Project455ed292009-03-13 13:04:22 -070076 DoOneTest(&TestExecutor::testGetPhoneticallySortableString);
Daisuke Miyakawad28cdc42009-05-18 14:51:52 +090077 DoOneTest(&TestExecutor::testGetNormalizedString);
The Android Open Source Project455ed292009-03-13 13:04:22 -070078
79 printf("Test total: %d\nSuccess: %d\nFailure: %d\n",
80 m_total_count, m_success_count, m_total_count - m_success_count);
81
82 bool success = m_total_count == m_success_count;
83 printf("\n%s\n", success ? "Success" : "Failure");
84
85 return success;
86}
87
88void TestExecutor::DoOneTest(void (TestExecutor::*test)()) {
89 m_success = true;
90
91 (this->*test)();
92
93 ++m_total_count;
94 m_success_count += m_success ? 1 : 0;
95}
96
Daisuke Miyakawae919af52009-06-26 22:58:32 +090097#define TEST_GET_UTF32AT(src, index, expected_next, expected_value) \
98 ({ \
99 size_t next; \
Daisuke Miyakawa1ec1f3d2009-07-09 14:03:07 +0900100 int32_t ret = utf32_at(src, strlen(src), index, &next); \
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900101 if (ret < 0) { \
102 printf("getUtf32At() returned negative value (src: %s, index: %d)\n", \
103 (src), (index)); \
104 m_success = false; \
105 } else if (next != (expected_next)) { \
106 printf("next is unexpected value (src: %s, actual: %u, expected: %u)\n", \
107 (src), next, (expected_next)); \
108 } else { \
109 EXPECT_EQ_VALUE(ret, (expected_value)); \
110 } \
111 })
The Android Open Source Project455ed292009-03-13 13:04:22 -0700112
Daisuke Miyakawa1ec1f3d2009-07-09 14:03:07 +0900113void TestExecutor::testUtf32At() {
114 printf("testUtf32At()\n");
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900115
116 TEST_GET_UTF32AT("a", 0, 1, 97);
The Android Open Source Project455ed292009-03-13 13:04:22 -0700117 // Japanese hiragana "a"
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900118 TEST_GET_UTF32AT("\xE3\x81\x82", 0, 3, 0x3042);
The Android Open Source Project455ed292009-03-13 13:04:22 -0700119 // Japanese fullwidth katakana "a" with ascii a
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900120 TEST_GET_UTF32AT("a\xE3\x82\xA2", 1, 4, 0x30A2);
The Android Open Source Project455ed292009-03-13 13:04:22 -0700121
122 // 2 PUA
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900123 TEST_GET_UTF32AT("\xF3\xBE\x80\x80\xF3\xBE\x80\x88", 0, 4, 0xFE000);
124 TEST_GET_UTF32AT("\xF3\xBE\x80\x80\xF3\xBE\x80\x88", 4, 8, 0xFE008);
The Android Open Source Project455ed292009-03-13 13:04:22 -0700125}
126
127void TestExecutor::testGetPhoneticallySortableCodePointAscii() {
128 printf("testGetPhoneticallySortableCodePoint()\n");
129 int halfwidth[94];
130 int fullwidth[94];
Daisuke Miyakawa441321a2009-07-10 15:50:49 +0900131 int i;
132 char32_t codepoint;
The Android Open Source Project455ed292009-03-13 13:04:22 -0700133 bool next_is_consumed;
134 for (i = 0, codepoint = 0x0021; codepoint <= 0x007E; ++i, ++codepoint) {
Daisuke Miyakawac30779b2009-07-10 16:48:36 +0900135 halfwidth[i] = GetPhoneticallySortableCodePoint(codepoint, 0,
The Android Open Source Project455ed292009-03-13 13:04:22 -0700136 &next_is_consumed);
137 if (halfwidth[i] < 0) {
138 printf("returned value become negative at 0x%04X", codepoint);
Daisuke Miyakawa0c45e822009-03-27 19:41:52 -0700139 m_success = false;
140 return;
The Android Open Source Project455ed292009-03-13 13:04:22 -0700141 }
142 if (next_is_consumed) {
143 printf("next_is_consumed become true at 0x%04X", codepoint);
144 m_success = false;
145 return;
146 }
147 }
148 for (i = 0, codepoint = 0xFF01; codepoint <= 0xFF5E; ++i, ++codepoint) {
Daisuke Miyakawac30779b2009-07-10 16:48:36 +0900149 fullwidth[i] = GetPhoneticallySortableCodePoint(codepoint, 0,
The Android Open Source Project455ed292009-03-13 13:04:22 -0700150 &next_is_consumed);
151 if (fullwidth[i] < 0) {
152 printf("returned value become negative at 0x%04X", codepoint);
Daisuke Miyakawa0c45e822009-03-27 19:41:52 -0700153 m_success = false;
154 return;
The Android Open Source Project455ed292009-03-13 13:04:22 -0700155 }
156 if (next_is_consumed) {
157 printf("next_is_consumed become true at 0x%04X", codepoint);
158 m_success = false;
159 return;
160 }
161 }
162
163 for (i = 0; i < 94; i++) {
164 EXPECT_EQ_VALUE(halfwidth[i], fullwidth[i]);
165 }
166}
167
168void TestExecutor::testGetPhoneticallySortableCodePointKana() {
169 printf("testGetPhoneticallySortableCodePointKana()\n");
170 int hiragana[86];
171 int fullwidth_katakana[86];
Daisuke Miyakawa441321a2009-07-10 15:50:49 +0900172 int i;
173 char32_t codepoint;
The Android Open Source Project455ed292009-03-13 13:04:22 -0700174 bool next_is_consumed;
175
176 for (i = 0, codepoint = 0x3041; codepoint <= 0x3096; ++i, ++codepoint) {
Daisuke Miyakawac30779b2009-07-10 16:48:36 +0900177 hiragana[i] = GetPhoneticallySortableCodePoint(codepoint, 0,
The Android Open Source Project455ed292009-03-13 13:04:22 -0700178 &next_is_consumed);
179 if (hiragana[i] < 0) {
180 printf("returned value become negative at 0x%04X", codepoint);
Daisuke Miyakawa0c45e822009-03-27 19:41:52 -0700181 m_success = false;
182 return;
The Android Open Source Project455ed292009-03-13 13:04:22 -0700183 }
184 if (next_is_consumed) {
185 printf("next_is_consumed become true at 0x%04X", codepoint);
186 m_success = false;
187 return;
188 }
189 }
190
191 for (i = 0, codepoint = 0x30A1; codepoint <= 0x30F6; ++i, ++codepoint) {
Daisuke Miyakawac30779b2009-07-10 16:48:36 +0900192 fullwidth_katakana[i] = GetPhoneticallySortableCodePoint(codepoint, 0,
The Android Open Source Project455ed292009-03-13 13:04:22 -0700193 &next_is_consumed);
194 if (fullwidth_katakana[i] < 0) {
195 printf("returned value become negative at 0x%04X", codepoint);
Daisuke Miyakawa0c45e822009-03-27 19:41:52 -0700196 m_success = false;
197 return;
The Android Open Source Project455ed292009-03-13 13:04:22 -0700198 }
199 if (next_is_consumed) {
200 printf("next_is_consumed become true at 0x%04X", codepoint);
201 m_success = false;
202 return;
203 }
204 }
205
206 // hankaku-katakana space do not have some characters corresponding to
207 // zenkaku-hiragana (e.g. xwa, xka, xku). To make test easier, insert
208 // zenkaku-katakana version of them into this array (See the value 0x30??).
Daisuke Miyakawac30779b2009-07-10 16:48:36 +0900209 char32_t halfwidth_katakana[] = {
The Android Open Source Project455ed292009-03-13 13:04:22 -0700210 0xFF67, 0xFF71, 0xFF68, 0xFF72, 0xFF69, 0xFF73, 0xFF6A, 0xFF74, 0xFF6B,
211 0xFF75, 0xFF76, 0xFF76, 0xFF9E, 0xFF77, 0xFF77, 0xFF9E, 0xFF78, 0xFF78,
212 0xFF9E, 0xFF79, 0xFF79, 0xFF9E, 0xFF7A, 0xFF7A, 0xFF9E, 0xFF7B, 0xFF7B,
213 0xFF9E, 0xFF7C, 0xFF7C, 0xFF9E, 0xFF7D, 0xFF7D, 0xFF9E, 0xFF7E, 0xFF7E,
214 0xFF9E, 0xFF7F, 0xFF7F, 0xFF9E, 0xFF80, 0xFF80, 0xFF9E, 0xFF81, 0xFF81,
215 0xFF9E, 0xFF6F, 0xFF82, 0xFF82, 0xFF9E, 0xFF83, 0xFF83, 0xFF9E, 0xFF84,
216 0xFF84, 0xFF9E, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8A,
217 0xFF9E, 0xFF8A, 0xFF9F, 0xFF8B, 0xFF8B, 0xFF9E, 0xFF8B, 0xFF9F, 0xFF8C,
218 0xFF8C, 0xFF9E, 0xFF8C, 0xFF9F, 0xFF8D, 0xFF8D, 0xFF9E, 0xFF8D, 0xFF9F,
219 0xFF8E, 0xFF8E, 0xFF9E, 0xFF8E, 0xFF9F, 0xFF8F, 0xFF90, 0xFF91, 0xFF92,
220 0xFF93, 0xFF6C, 0xFF94, 0xFF6D, 0xFF95, 0xFF6E, 0xFF96, 0xFF97, 0xFF98,
221 0xFF99, 0xFF9A, 0xFF9B, 0x30EE, 0xFF9C, 0x30F0, 0x30F1, 0xFF66, 0xFF9D,
222 0xFF73, 0xFF9E, 0x30F5, 0x30F6};
223 int len = sizeof(halfwidth_katakana)/sizeof(int);
224
225 int halfwidth_katakana_result[86];
226
227 int j;
228 for (i = 0, j = 0; i < len && j < 86; ++i, ++j) {
Daisuke Miyakawac30779b2009-07-10 16:48:36 +0900229 char32_t codepoint = halfwidth_katakana[i];
230 char32_t next_codepoint = i + 1 < len ? halfwidth_katakana[i + 1] : 0;
The Android Open Source Project455ed292009-03-13 13:04:22 -0700231 halfwidth_katakana_result[j] =
232 GetPhoneticallySortableCodePoint(codepoint, next_codepoint,
233 &next_is_consumed);
234 // Consume voiced mark/half-voiced mark.
235 if (next_is_consumed) {
236 ++i;
237 }
238 }
239 ASSERT_EQ_VALUE(i, len);
240 ASSERT_EQ_VALUE(j, 86);
241
242 for (i = 0; i < 86; ++i) {
243 EXPECT_EQ_VALUE(fullwidth_katakana[i], hiragana[i]);
244 EXPECT_EQ_VALUE(halfwidth_katakana_result[i], hiragana[i]);
245 }
246}
247
Daisuke Miyakawa0c45e822009-03-27 19:41:52 -0700248void TestExecutor::testGetPhoneticallySortableCodePointWhitespaceOnly() {
Daisuke Miyakawad28cdc42009-05-18 14:51:52 +0900249 printf("testGetPhoneticallySortableCodePointWhitespaceOnly()\n");
Daisuke Miyakawa0c45e822009-03-27 19:41:52 -0700250 // Halfwidth space
251 int result = GetPhoneticallySortableCodePoint(0x0020, 0x0061, NULL);
252 ASSERT_EQ_VALUE(result, -1);
253 // Fullwidth space
254 result = GetPhoneticallySortableCodePoint(0x3000, 0x0062, NULL);
255 ASSERT_EQ_VALUE(result, -1);
256 // tab
257 result = GetPhoneticallySortableCodePoint(0x0009, 0x0062, NULL);
258 ASSERT_EQ_VALUE(result, -1);
259}
260
The Android Open Source Project455ed292009-03-13 13:04:22 -0700261void TestExecutor::testGetPhoneticallySortableCodePointSimpleCompare() {
262 printf("testGetPhoneticallySortableCodePointSimpleCompare()\n");
263
Daisuke Miyakawa441321a2009-07-10 15:50:49 +0900264 char32_t codepoints[] = {
The Android Open Source Project455ed292009-03-13 13:04:22 -0700265 0x3042, 0x30AB, 0xFF7B, 0x305F, 0x30CA, 0xFF8A, 0x30D0, 0x3071,
266 0x307E, 0x30E4, 0xFF97, 0x308F, 0x3093, 0x3094, 'A', 'Z',
267 '0', '9', '!', '/', ':', '?', '[', '`', '{', '~'};
268 size_t len = sizeof(codepoints)/sizeof(int);
269 bool next_is_consumed;
270 for (size_t i = 0; i < len - 1; ++i) {
271 int codepoint_a =
Daisuke Miyakawac30779b2009-07-10 16:48:36 +0900272 GetPhoneticallySortableCodePoint(codepoints[i], 0,
The Android Open Source Project455ed292009-03-13 13:04:22 -0700273 &next_is_consumed);
274 if (next_is_consumed) {
275 printf("next_is_consumed become true at 0x%04X", codepoint_a);
276 m_success = false;
277 return;
278 }
279 int codepoint_b =
Daisuke Miyakawac30779b2009-07-10 16:48:36 +0900280 GetPhoneticallySortableCodePoint(codepoints[i + 1], 0,
The Android Open Source Project455ed292009-03-13 13:04:22 -0700281 &next_is_consumed);
282 if (next_is_consumed) {
283 printf("next_is_consumed become true at 0x%04X", codepoint_b);
284 m_success = false;
285 return;
286 }
287
288 if (codepoint_a >= codepoint_b) {
289 printf("0x%04X (from 0x%04X) >= 0x%04X (from 0x%04X)\n",
290 codepoint_a, codepoints[i], codepoint_b, codepoints[i + 1]);
291 m_success = false;
292 return;
293 }
294 }
295}
296
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900297#define EXPECT_EQ_CODEPOINT_UTF8(codepoint, expected) \
The Android Open Source Project455ed292009-03-13 13:04:22 -0700298 ({ \
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900299 char32_t codepoints[1] = {codepoint}; \
300 status_t ret = string8.setTo(codepoints, 1); \
301 if (ret != NO_ERROR) { \
The Android Open Source Project455ed292009-03-13 13:04:22 -0700302 printf("GetUtf8FromCodePoint() returned false at 0x%04X\n", codepoint); \
303 m_success = false; \
The Android Open Source Project455ed292009-03-13 13:04:22 -0700304 } else { \
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900305 const char* string = string8.string(); \
306 if (strcmp(string, expected) != 0) { \
The Android Open Source Project455ed292009-03-13 13:04:22 -0700307 printf("Failed at codepoint 0x%04X\n", codepoint); \
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900308 for (const char *ch = string; *ch != '\0'; ++ch) { \
The Android Open Source Project455ed292009-03-13 13:04:22 -0700309 printf("0x%X ", *ch); \
310 } \
311 printf("!= "); \
312 for (const char *ch = expected; *ch != '\0'; ++ch) { \
313 printf("0x%X ", *ch); \
314 } \
315 printf("\n"); \
316 m_success = false; \
317 } \
318 } \
319 })
320
Daisuke Miyakawae919af52009-06-26 22:58:32 +0900321void TestExecutor::testGetUtf8FromUtf32() {
322 printf("testGetUtf8FromUtf32()\n");
323 String8 string8;
The Android Open Source Project455ed292009-03-13 13:04:22 -0700324
325 EXPECT_EQ_CODEPOINT_UTF8('a', "\x61");
326 // Armenian capital letter AYB (2 bytes in UTF8)
327 EXPECT_EQ_CODEPOINT_UTF8(0x0530, "\xD4\xB0");
328 // Japanese 'a' (3 bytes in UTF8)
329 EXPECT_EQ_CODEPOINT_UTF8(0x3042, "\xE3\x81\x82");
330 // Kanji
331 EXPECT_EQ_CODEPOINT_UTF8(0x65E5, "\xE6\x97\xA5");
332 // PUA (4 byets in UTF8)
333 EXPECT_EQ_CODEPOINT_UTF8(0xFE016, "\xF3\xBE\x80\x96");
334 EXPECT_EQ_CODEPOINT_UTF8(0xFE972, "\xF3\xBE\xA5\xB2");
The Android Open Source Project455ed292009-03-13 13:04:22 -0700335}
336
337#define EXPECT_EQ_UTF8_UTF8(src, expected) \
338 ({ \
339 if (!GetPhoneticallySortableString(src, &dst, &len)) { \
340 printf("GetPhoneticallySortableString() returned false.\n"); \
341 m_success = false; \
342 } else { \
343 if (strcmp(dst, expected) != 0) { \
344 for (const char *ch = dst; *ch != '\0'; ++ch) { \
345 printf("0x%X ", *ch); \
346 } \
347 printf("!= "); \
348 for (const char *ch = expected; *ch != '\0'; ++ch) { \
349 printf("0x%X ", *ch); \
350 } \
351 printf("\n"); \
352 m_success = false; \
353 } \
354 free(dst); \
355 } \
356 })
357
358void TestExecutor::testGetPhoneticallySortableString() {
Daisuke Miyakawad28cdc42009-05-18 14:51:52 +0900359 printf("testGetPhoneticallySortableString()\n");
The Android Open Source Project455ed292009-03-13 13:04:22 -0700360 char *dst;
361 size_t len;
362
363 // halfwidth alphabets -> fullwidth alphabets.
364 EXPECT_EQ_UTF8_UTF8("ABCD",
365 "\xEF\xBC\xA1\xEF\xBC\xA2\xEF\xBC\xA3\xEF\xBC\xA4");
366 // halfwidth/fullwidth-katakana -> hiragana
367 EXPECT_EQ_UTF8_UTF8(
368 "\xE3\x81\x82\xE3\x82\xA4\xE3\x81\x86\xEF\xBD\xB4\xE3\x82\xAA",
369 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
Daisuke Miyakawa0c45e822009-03-27 19:41:52 -0700370
371 // whitespace -> string which should be placed at last
372 EXPECT_EQ_UTF8_UTF8(" \t", "\xF0\x9F\xBF\xBD");
The Android Open Source Project455ed292009-03-13 13:04:22 -0700373}
374
Daisuke Miyakawad28cdc42009-05-18 14:51:52 +0900375#undef EXPECT_EQ_UTF8_UTF8
376
377#define EXPECT_EQ_UTF8_UTF8(src, expected) \
378 ({ \
379 if (!GetNormalizedString(src, &dst, &len)) { \
380 printf("GetPhoneticallySortableString() returned false.\n"); \
381 m_success = false; \
382 } else { \
383 if (strcmp(dst, expected) != 0) { \
384 for (const char *ch = dst; *ch != '\0'; ++ch) { \
385 printf("0x%X ", *ch); \
386 } \
387 printf("!= "); \
388 for (const char *ch = expected; *ch != '\0'; ++ch) { \
389 printf("0x%X ", *ch); \
390 } \
391 printf("\n"); \
392 m_success = false; \
393 } \
394 free(dst); \
395 } \
396 })
397
398void TestExecutor::testGetNormalizedString() {
399 printf("testGetNormalizedString()\n");
400 char *dst;
401 size_t len;
402
403 // halfwidth alphabets/symbols -> keep it as is.
404 EXPECT_EQ_UTF8_UTF8("ABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%^&'()",
405 "ABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%^&'()");
406 EXPECT_EQ_UTF8_UTF8("abcdefghijklmnopqrstuvwxyz[]{}\\@/",
407 "abcdefghijklmnopqrstuvwxyz[]{}\\@/");
408
409 // halfwidth/fullwidth-katakana -> hiragana
410 EXPECT_EQ_UTF8_UTF8(
411 "\xE3\x81\x82\xE3\x82\xA4\xE3\x81\x86\xEF\xBD\xB4\xE3\x82\xAA",
412 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A");
413
414 // whitespace -> keep it as is.
415 EXPECT_EQ_UTF8_UTF8(" \t", " \t");
416}
417
The Android Open Source Project455ed292009-03-13 13:04:22 -0700418int main() {
419 TestExecutor executor;
420 if(executor.DoAllTests()) {
421 return 0;
422 } else {
423 return 1;
424 }
425}