1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
3/*  Reference: http://wiki.apache.org/couchdb/View_collation */
4
5#include "../src/views/collate_json.h"
6#include "../macros.h"
7#include "view_tests.h"
8#include <string.h>
9#include <stdio.h>
10
11
12static int collateStrs(const char* str1, const char* str2, CollateJSONMode mode)
13{
14    /* Be evil and put numeric garbage past the ends of str1 and str2, to make
15       sure it doesn't confuse the numeric parsing in the collator: */
16    size_t len1 = strlen(str1), len2 = strlen(str2);
17    char *padded1 = malloc(len1 + 3);
18    char *padded2 = malloc(len2 + 3);
19    int ret;
20    sized_buf buf1;
21    sized_buf buf2;
22
23    cb_assert(padded1);
24    cb_assert(padded2);
25
26    strcpy(padded1, str1);
27    strcat(padded1, "99");
28    strcpy(padded2, str2);
29    strcat(padded2, "88");
30
31    buf1.buf = padded1;
32    buf1.size = len1;
33    buf2.buf = padded2;
34    buf2.size = len2;
35    ret =  CollateJSON(&buf1, &buf2, mode);
36    free(padded1);
37    free(padded2);
38    return ret;
39}
40
41
42static void testEscape(const char* source, char decoded) {
43    const char* pos = source;
44    assert_eq(ConvertJSONEscape(&pos), decoded);
45    assert_eq((size_t)pos, (size_t)(source + strlen(source) - 1));
46}
47
48
49static void TestCollateConvertEscape(void)
50{
51    fprintf(stderr, "escapes... ");
52    testEscape("\\\\",    '\\');
53    testEscape("\\t",     '\t');
54    testEscape("\\u0045", 'E');
55    testEscape("\\u0001", 1);
56    testEscape("\\u0000", 0);
57}
58
59static void TestCollateScalars(void)
60{
61    CollateJSONMode mode = kCollateJSON_Unicode;
62    fprintf(stderr, "scalars... ");
63    assert_eq(collateStrs("true", "false", mode), 1);
64    assert_eq(collateStrs("false", "true", mode), -1);
65    assert_eq(collateStrs("null", "17", mode), -1);
66    assert_eq(collateStrs("123", "123", mode), 0);
67    assert_eq(collateStrs("123", "1", mode), 1);
68    assert_eq(collateStrs("123", "0123.0", mode), 0);
69    assert_eq(collateStrs("123", "\"123\"", mode), -1);
70    assert_eq(collateStrs("\"1234\"", "\"123\"", mode), 1);
71    assert_eq(collateStrs("\"1234\"", "\"1235\"", mode), -1);
72    assert_eq(collateStrs("\"1234\"", "\"1234\"", mode), 0);
73    assert_eq(collateStrs("\"12\\/34\"", "\"12/34\"", mode), 0);
74    assert_eq(collateStrs("\"\\/1234\"", "\"/1234\"", mode), 0);
75    assert_eq(collateStrs("\"1234\\/\"", "\"1234/\"", mode), 0);
76    assert_eq(collateStrs("\"a\"", "\"A\"", mode), -1);
77    assert_eq(collateStrs("\"A\"", "\"aa\"", mode), -1);
78    assert_eq(collateStrs("\"B\"", "\"aa\"", mode), 1);
79}
80
81static void TestCollateASCII(void)
82{
83    CollateJSONMode mode = kCollateJSON_ASCII;
84    fprintf(stderr, "ASCII... ");
85    assert_eq(collateStrs("true", "false", mode), 1);
86    assert_eq(collateStrs("false", "true", mode), -1);
87    assert_eq(collateStrs("null", "17", mode), -1);
88    assert_eq(collateStrs("123", "1", mode), 1);
89    assert_eq(collateStrs("123", "0123.0", mode), 0);
90    assert_eq(collateStrs("123", "\"123\"", mode), -1);
91    assert_eq(collateStrs("\"1234\"", "\"123\"", mode), 1);
92    assert_eq(collateStrs("\"1234\"", "\"1235\"", mode), -1);
93    assert_eq(collateStrs("\"1234\"", "\"1234\"", mode), 0);
94    assert_eq(collateStrs("\"12\\/34\"", "\"12/34\"", mode), 0);
95    assert_eq(collateStrs("\"\\/1234\"", "\"/1234\"", mode), 0);
96    assert_eq(collateStrs("\"1234\\/\"", "\"1234/\"", mode), 0);
97    assert_eq(collateStrs("\"A\"", "\"a\"", mode), -1);
98    assert_eq(collateStrs("\"B\"", "\"a\"", mode), -1);
99}
100
101static void TestCollateRaw(void)
102{
103    CollateJSONMode mode = kCollateJSON_Raw;
104    fprintf(stderr, "raw... ");
105    assert_eq(collateStrs("false", "17", mode), 1);
106    assert_eq(collateStrs("false", "true", mode), -1);
107    assert_eq(collateStrs("null", "true", mode), -1);
108    assert_eq(collateStrs("[\"A\"]", "\"A\"", mode), -1);
109    assert_eq(collateStrs("\"A\"", "\"a\"", mode), -1);
110    assert_eq(collateStrs("[\"b\"]", "[\"b\",\"c\",\"a\"]", mode), -1);
111}
112
113static void TestCollateArrays(void)
114{
115    CollateJSONMode mode = kCollateJSON_Unicode;
116    fprintf(stderr, "arrays... ");
117    assert_eq(collateStrs("[]", "\"foo\"", mode), 1);
118    assert_eq(collateStrs("[]", "[]", mode), 0);
119    assert_eq(collateStrs("[true]", "[true]", mode), 0);
120    assert_eq(collateStrs("[false]", "[null]", mode), 1);
121    assert_eq(collateStrs("[]", "[null]", mode), -1);
122    assert_eq(collateStrs("[123]", "[45]", mode), 1);
123    assert_eq(collateStrs("[123]", "[45,67]", mode), 1);
124    assert_eq(collateStrs("[123.4,\"wow\"]", "[123.40,789]", mode), 1);
125}
126
127static void TestCollateNestedArrays(void)
128{
129    CollateJSONMode mode = kCollateJSON_Unicode;
130    fprintf(stderr, "nesting... ");
131    assert_eq(collateStrs("[[]]", "[]", mode), 1);
132    assert_eq(collateStrs("[1,[2,3],4]", "[1,[2,3.1],4,5,6]", mode), -1);
133}
134
135static void TestCollateUnicodeStrings(void)
136{
137    /* Make sure that TDJSON never creates escape sequences we can't parse.
138       That includes "\unnnn" for non-ASCII chars, and "\t", "\b", etc. */
139    CollateJSONMode mode = kCollateJSON_Unicode;
140    fprintf(stderr, "Unicode... ");
141    assert_eq(collateStrs("\"fréd\"", "\"fréd\"", mode), 0);
142    assert_eq(collateStrs("\"mip你好\"", "\"mip你好\"", mode), 0);
143    assert_eq(collateStrs("\"ømø\"",  "\"omo\"", mode), 1);
144    assert_eq(collateStrs("\"\t\"",   "\" \"", mode), -1);
145    assert_eq(collateStrs("\"\001\"", "\" \"", mode), -1);
146    /* MB-12967 */
147    assert_eq(collateStrs("\"法\"", "\"法、\"", mode), -1);
148}
149
150void test_collate_json(void)
151{
152    fprintf(stderr, "JSON collation: ");
153    TestCollateConvertEscape();
154    TestCollateScalars();
155    TestCollateASCII();
156    TestCollateRaw();
157    TestCollateArrays();
158    TestCollateNestedArrays();
159    TestCollateUnicodeStrings();
160    fprintf(stderr, "OK\n");
161}
162