1 /*
2 *
3 * Copyright 2015 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21
22 #include <grpc/support/alloc.h>
23 #include <grpc/support/log.h>
24 #include "test/core/util/test_config.h"
25
26 #include "src/core/lib/gpr/useful.h"
27 #include "src/core/lib/json/json_reader.h"
28 #include "src/core/lib/json/json_writer.h"
29
30 typedef struct json_writer_userdata {
31 FILE* cmp;
32 } json_writer_userdata;
33
34 typedef struct stacked_container {
35 grpc_json_type type;
36 struct stacked_container* next;
37 } stacked_container;
38
39 typedef struct json_reader_userdata {
40 FILE* in;
41 grpc_json_writer* writer;
42 char* scratchpad;
43 char* ptr;
44 size_t free_space;
45 size_t allocated;
46 size_t string_len;
47 stacked_container* top;
48 int did_eagain;
49 } json_reader_userdata;
50
json_writer_output_char(void * userdata,char c)51 static void json_writer_output_char(void* userdata, char c) {
52 json_writer_userdata* state = static_cast<json_writer_userdata*>(userdata);
53 int cmp = fgetc(state->cmp);
54
55 /* treat CRLF as LF */
56 if (cmp == '\r' && c == '\n') {
57 cmp = fgetc(state->cmp);
58 }
59 GPR_ASSERT(cmp == c);
60 }
61
json_writer_output_string(void * userdata,const char * str)62 static void json_writer_output_string(void* userdata, const char* str) {
63 while (*str) {
64 json_writer_output_char(userdata, *str++);
65 }
66 }
67
json_writer_output_string_with_len(void * userdata,const char * str,size_t len)68 static void json_writer_output_string_with_len(void* userdata, const char* str,
69 size_t len) {
70 size_t i;
71 for (i = 0; i < len; i++) {
72 json_writer_output_char(userdata, str[i]);
73 }
74 }
75
76 grpc_json_writer_vtable writer_vtable = {json_writer_output_char,
77 json_writer_output_string,
78 json_writer_output_string_with_len};
79
check_string(json_reader_userdata * state,size_t needed)80 static void check_string(json_reader_userdata* state, size_t needed) {
81 if (state->free_space >= needed) return;
82 needed -= state->free_space;
83 needed = (needed + 0xffu) & ~0xffu;
84 state->scratchpad = static_cast<char*>(
85 gpr_realloc(state->scratchpad, state->allocated + needed));
86 state->free_space += needed;
87 state->allocated += needed;
88 }
89
json_reader_string_clear(void * userdata)90 static void json_reader_string_clear(void* userdata) {
91 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
92 state->free_space = state->allocated;
93 state->string_len = 0;
94 }
95
json_reader_string_add_char(void * userdata,uint32_t c)96 static void json_reader_string_add_char(void* userdata, uint32_t c) {
97 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
98 check_string(state, 1);
99 GPR_ASSERT(c <= 256);
100 state->scratchpad[state->string_len++] = static_cast<char>(c);
101 }
102
json_reader_string_add_utf32(void * userdata,uint32_t c)103 static void json_reader_string_add_utf32(void* userdata, uint32_t c) {
104 if (c <= 0x7f) {
105 json_reader_string_add_char(userdata, c);
106 } else if (c <= 0x7ffu) {
107 uint32_t b1 = 0xc0u | ((c >> 6u) & 0x1fu);
108 uint32_t b2 = 0x80u | (c & 0x3fu);
109 json_reader_string_add_char(userdata, b1);
110 json_reader_string_add_char(userdata, b2);
111 } else if (c <= 0xffffu) {
112 uint32_t b1 = 0xe0u | ((c >> 12u) & 0x0fu);
113 uint32_t b2 = 0x80u | ((c >> 6u) & 0x3fu);
114 uint32_t b3 = 0x80u | (c & 0x3fu);
115 json_reader_string_add_char(userdata, b1);
116 json_reader_string_add_char(userdata, b2);
117 json_reader_string_add_char(userdata, b3);
118 } else if (c <= 0x1fffffu) {
119 uint32_t b1 = 0xf0u | ((c >> 18u) & 0x07u);
120 uint32_t b2 = 0x80u | ((c >> 12u) & 0x3fu);
121 uint32_t b3 = 0x80u | ((c >> 6u) & 0x3fu);
122 uint32_t b4 = 0x80u | (c & 0x3fu);
123 json_reader_string_add_char(userdata, b1);
124 json_reader_string_add_char(userdata, b2);
125 json_reader_string_add_char(userdata, b3);
126 json_reader_string_add_char(userdata, b4);
127 }
128 }
129
json_reader_read_char(void * userdata)130 static uint32_t json_reader_read_char(void* userdata) {
131 int r;
132 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
133
134 if (!state->did_eagain) {
135 state->did_eagain = 1;
136 return GRPC_JSON_READ_CHAR_EAGAIN;
137 }
138
139 state->did_eagain = 0;
140
141 r = fgetc(state->in);
142 if (r == EOF) r = GRPC_JSON_READ_CHAR_EOF;
143 return static_cast<uint32_t>(r);
144 }
145
json_reader_container_begins(void * userdata,grpc_json_type type)146 static void json_reader_container_begins(void* userdata, grpc_json_type type) {
147 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
148 stacked_container* container =
149 static_cast<stacked_container*>(gpr_malloc(sizeof(stacked_container)));
150
151 container->type = type;
152 container->next = state->top;
153 state->top = container;
154
155 grpc_json_writer_container_begins(state->writer, type);
156 }
157
json_reader_container_ends(void * userdata)158 static grpc_json_type json_reader_container_ends(void* userdata) {
159 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
160 stacked_container* container = state->top;
161
162 grpc_json_writer_container_ends(state->writer, container->type);
163 state->top = container->next;
164 gpr_free(container);
165 return state->top ? state->top->type : GRPC_JSON_TOP_LEVEL;
166 }
167
json_reader_set_key(void * userdata)168 static void json_reader_set_key(void* userdata) {
169 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
170 json_reader_string_add_char(userdata, 0);
171
172 grpc_json_writer_object_key(state->writer, state->scratchpad);
173 }
174
json_reader_set_string(void * userdata)175 static void json_reader_set_string(void* userdata) {
176 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
177 json_reader_string_add_char(userdata, 0);
178
179 grpc_json_writer_value_string(state->writer, state->scratchpad);
180 }
181
json_reader_set_number(void * userdata)182 static int json_reader_set_number(void* userdata) {
183 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
184
185 grpc_json_writer_value_raw_with_len(state->writer, state->scratchpad,
186 state->string_len);
187
188 return 1;
189 }
190
json_reader_set_true(void * userdata)191 static void json_reader_set_true(void* userdata) {
192 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
193
194 grpc_json_writer_value_raw_with_len(state->writer, "true", 4);
195 }
196
json_reader_set_false(void * userdata)197 static void json_reader_set_false(void* userdata) {
198 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
199
200 grpc_json_writer_value_raw_with_len(state->writer, "false", 5);
201 }
202
json_reader_set_null(void * userdata)203 static void json_reader_set_null(void* userdata) {
204 json_reader_userdata* state = static_cast<json_reader_userdata*>(userdata);
205
206 grpc_json_writer_value_raw_with_len(state->writer, "null", 4);
207 }
208
209 static grpc_json_reader_vtable reader_vtable = {
210 json_reader_string_clear, json_reader_string_add_char,
211 json_reader_string_add_utf32, json_reader_read_char,
212 json_reader_container_begins, json_reader_container_ends,
213 json_reader_set_key, json_reader_set_string,
214 json_reader_set_number, json_reader_set_true,
215 json_reader_set_false, json_reader_set_null};
216
rewrite_and_compare(FILE * in,FILE * cmp,int indent)217 int rewrite_and_compare(FILE* in, FILE* cmp, int indent) {
218 grpc_json_writer writer;
219 grpc_json_reader reader;
220 grpc_json_reader_status status;
221 json_writer_userdata writer_user;
222 json_reader_userdata reader_user;
223
224 GPR_ASSERT(in);
225 GPR_ASSERT(cmp);
226
227 reader_user.writer = &writer;
228 reader_user.in = in;
229 reader_user.top = nullptr;
230 reader_user.scratchpad = nullptr;
231 reader_user.string_len = 0;
232 reader_user.free_space = 0;
233 reader_user.allocated = 0;
234 reader_user.did_eagain = 0;
235
236 writer_user.cmp = cmp;
237
238 grpc_json_writer_init(&writer, indent, &writer_vtable, &writer_user);
239 grpc_json_reader_init(&reader, &reader_vtable, &reader_user);
240
241 do {
242 status = grpc_json_reader_run(&reader);
243 } while (status == GRPC_JSON_EAGAIN);
244
245 free(reader_user.scratchpad);
246 while (reader_user.top) {
247 stacked_container* container = reader_user.top;
248 reader_user.top = container->next;
249 free(container);
250 }
251
252 return status == GRPC_JSON_DONE;
253 }
254
255 typedef struct test_file {
256 const char* input;
257 const char* cmp;
258 int indent;
259 } test_file;
260
261 static test_file test_files[] = {
262 {"test/core/json/rewrite_test_input.json",
263 "test/core/json/rewrite_test_output_condensed.json", 0},
264 {"test/core/json/rewrite_test_input.json",
265 "test/core/json/rewrite_test_output_indented.json", 2},
266 {"test/core/json/rewrite_test_output_indented.json",
267 "test/core/json/rewrite_test_output_condensed.json", 0},
268 {"test/core/json/rewrite_test_output_condensed.json",
269 "test/core/json/rewrite_test_output_indented.json", 2},
270 };
271
test_rewrites()272 void test_rewrites() {
273 unsigned i;
274
275 for (i = 0; i < GPR_ARRAY_SIZE(test_files); i++) {
276 test_file* test = test_files + i;
277 FILE* input = fopen(test->input, "rb");
278 FILE* cmp = fopen(test->cmp, "rb");
279 int status;
280 gpr_log(GPR_INFO, "Testing file %s against %s using indent=%i", test->input,
281 test->cmp, test->indent);
282 status = rewrite_and_compare(input, cmp, test->indent);
283 GPR_ASSERT(status);
284 fclose(input);
285 fclose(cmp);
286 }
287 }
288
main(int argc,char ** argv)289 int main(int argc, char** argv) {
290 grpc_test_init(argc, argv);
291 test_rewrites();
292 gpr_log(GPR_INFO, "json_rewrite_test success");
293 return 0;
294 }
295