rjp/tests/parse.c

203 lines
6.3 KiB
C

#include "rjp.h"
#include "rjp_internal.h"
#include "rjp_string.h"
#include <stdio.h>
#include <string.h>
#define MIN(x, y) ((x < y) ? (x) : (y))
typedef struct parse_stuff{
const char* str;
int len;
int pos;
}parse_stuff;
int read_callback(char* c, int size, void* userdata){
parse_stuff* data = (parse_stuff*)userdata;
if(data->pos >= data->len)
return 0;
int min = MIN(size, data->len - data->pos);
int i;
for(i = 0;i < min;++i){
c[i] = data->str[data->pos++];
}
return i;
}
int handle_res(RJP_value* res){
if(res){
fprintf(stderr, "Accepted\n");
}
#ifndef RJP_ENABLE_DIAGNOSTICS
else{
fprintf(stderr, "Failed\n");
}
#endif
int failed = res == NULL;
rjp_free_value(res);
return failed;
}
int test_cbacks(const char* str, RJP_parse_flag flags){
RJP_parse_callback cbacks;
parse_stuff cback_data = {str, strlen(str), 0};
cbacks.read = read_callback;
cbacks.data = &cback_data;
RJP_value* res;
res = rjp_parse_cback(flags, &cbacks);
return handle_res(res);
}
int test(const char* str, RJP_parse_flag flags){
RJP_value* res;
res = rjp_parse(str, flags);
return handle_res(res);
}
struct parse_pair{
const char* str;
RJP_parse_flag flags;
};
struct parse_pair should_pass_strings[] = {
{"{}", RJP_PARSE_NONE},
{"[]", RJP_PARSE_NONE},
{"\"s\"", RJP_PARSE_NONE},
{"\"\\n\"", RJP_PARSE_NONE},
{"\"\\\"\"", RJP_PARSE_NONE},
{"\"str\\nstr\"", RJP_PARSE_NONE},
{"\"\\uD83D\\uDE10\"", RJP_PARSE_NONE},
{"true", RJP_PARSE_NONE},
{"false", RJP_PARSE_NONE},
{"null", RJP_PARSE_NONE},
{"5", RJP_PARSE_NONE},
{"-5", RJP_PARSE_NONE},
{"+5", RJP_PARSE_NONE},
{"5.5", RJP_PARSE_NONE},
{"-5.5", RJP_PARSE_NONE},
{"+5.5", RJP_PARSE_NONE},
{"5.5e6", RJP_PARSE_NONE},
{"-5.5e6", RJP_PARSE_NONE},
{"+5.5e6", RJP_PARSE_NONE},
{"5.5e+6", RJP_PARSE_NONE},
{"-5.5e+6", RJP_PARSE_NONE},
{"+5.5e+6", RJP_PARSE_NONE},
{"5.5e-6", RJP_PARSE_NONE},
{"-5.5e-6", RJP_PARSE_NONE},
{"+5.5e-6", RJP_PARSE_NONE},
{" {}", RJP_PARSE_NONE},
{"\n{}\n", RJP_PARSE_NONE},
{" { \"key\" \t:\n\n\n5 \n\t\n } ", RJP_PARSE_NONE},
{" {\t }\n", RJP_PARSE_NONE},
{"5.5 ", RJP_PARSE_NONE},
{"{\"key\":5}", RJP_PARSE_NONE},
{"{\"key\":{}}", RJP_PARSE_NONE},
{"{\"\\uD83D\\uDE10\":5}", RJP_PARSE_NONE},
{"{\"😐\":5}", RJP_PARSE_NONE},
{"{\"key\":{\"key\":5}}", RJP_PARSE_NONE},
{"{\"key\":{\"key\":5,\"key2\":6}}", RJP_PARSE_NONE},
{"{\"key\":{\"key\":5},\"key2\":6}", RJP_PARSE_NONE},
{"[5, 6, 7, 8, 9, \"10\"]", RJP_PARSE_NONE},
{"[[5,6],[7,8],[9,\"10\"]]", RJP_PARSE_NONE},
{"{\"arr\":[5,6,6]}", RJP_PARSE_NONE},
{"[{\"arr\":[5,6,6]}]", RJP_PARSE_NONE},
{"[{\"arr\":[5,6,6]}, 6]", RJP_PARSE_NONE},
{"[5,6,6,6,6.6]", RJP_PARSE_NONE},
{"[6,7,]", RJP_PARSE_ALLOW_TRAILING_COMMA},
{"{\"1\":1,\"2\":2,}", RJP_PARSE_ALLOW_TRAILING_COMMA},
{"[6,]", RJP_PARSE_ALLOW_TRAILING_COMMA},
{"{\"1\":1,}", RJP_PARSE_ALLOW_TRAILING_COMMA},
{"//comment\n{}", RJP_PARSE_ALLOW_COMMENTS},
{"{\"key\"://comment\n5}", RJP_PARSE_ALLOW_COMMENTS},
{"{\"key\"//comment\n:5}", RJP_PARSE_ALLOW_COMMENTS},
{"{}//comment", RJP_PARSE_ALLOW_COMMENTS},
{"{//\"key\":5\n}", RJP_PARSE_ALLOW_COMMENTS},
{"5 //comment*/", RJP_PARSE_ALLOW_COMMENTS},
{"{/*\"key\":5*/\"key\":5}", RJP_PARSE_ALLOW_COMMENTS},
{"[5, /*comment*/6]", RJP_PARSE_ALLOW_COMMENTS},
};
const int should_pass_cnt = sizeof(should_pass_strings)/sizeof(should_pass_strings[0]);
struct parse_pair should_fail_strings[] = {
{"//comment\n{}", RJP_PARSE_NONE},
{"{", RJP_PARSE_NONE},
{"}", RJP_PARSE_NONE},
{"[", RJP_PARSE_NONE},
{"]", RJP_PARSE_NONE},
{"6.", RJP_PARSE_NONE},
{"6.6e", RJP_PARSE_NONE},
{"6.6e+", RJP_PARSE_NONE},
{"5e", RJP_PARSE_NONE},
{"{6}", RJP_PARSE_NONE},
{"[\"key\":5]", RJP_PARSE_NONE},
{"\"string\n\"", RJP_PARSE_NONE},
{"[3 4]", RJP_PARSE_NONE},
{"\"\\uD83D\\uDE1\"", RJP_PARSE_NONE},
{"\"\\uD83D\\uDE1Q\"", RJP_PARSE_NONE},
{"\"\\uD83\\uDE10\"", RJP_PARSE_NONE},
{"\"\\uF83D\\uDE10\"", RJP_PARSE_NONE},
{"\"\\uU83D\\uDE10\"", RJP_PARSE_NONE},
{"{\"key\":1 \"key2\":2}", RJP_PARSE_NONE},
{"{\"key\" 1}", RJP_PARSE_NONE},
{"6, 7", RJP_PARSE_NONE},
{"[,]", RJP_PARSE_NONE},
{"{, RJP_PARSE_NONE}", RJP_PARSE_NONE},
{"[1, 2],", RJP_PARSE_NONE},
{"{\"key\nkey\":5}", RJP_PARSE_NONE},
{"{\"key\":\"key\n\"}", RJP_PARSE_NONE},
{"[6,7,]", RJP_PARSE_NONE},
{"{\"1\":1,\"2\":2, RJP_PARSE_NONE}", RJP_PARSE_NONE},
{"[6,]", RJP_PARSE_NONE},
{"{\"1\":1, RJP_PARSE_NONE}", RJP_PARSE_NONE},
{"{//comment\"key\":\n5}", RJP_PARSE_NONE},
{"{/*\"key\":*/5}", RJP_PARSE_NONE},
{"[5, /*6*/, 7]", RJP_PARSE_NONE},
{"{/*comment}", RJP_PARSE_NONE},
{"{//comment}", RJP_PARSE_NONE},
{"{\"key\"://comment\n5}", RJP_PARSE_NONE},
{"{\"key\"//comment\n:5}", RJP_PARSE_NONE},
{"{}//comment", RJP_PARSE_NONE},
{"{//\"key\":5\n}", RJP_PARSE_NONE},
{"5 //comment*/", RJP_PARSE_NONE},
{"{/*\"key\":5*/\"key\":5}", RJP_PARSE_NONE},
{"[5, /*comment*/6]", RJP_PARSE_NONE},
{"{\"key\"//:5}", RJP_PARSE_ALLOW_COMMENTS},
{"{,}", RJP_PARSE_ALLOW_TRAILING_COMMA},
{"[,]", RJP_PARSE_ALLOW_TRAILING_COMMA},
};
const int should_fail_cnt = sizeof(should_fail_strings)/sizeof(should_fail_strings[0]);
const int total_tests = should_pass_cnt + should_fail_cnt;
int run_test(int (*fun)(const char*,RJP_parse_flag)){
int passed = 0;
fprintf(stderr, "Running %d tests that should pass...\n", should_pass_cnt);
for(unsigned i = 0;i < sizeof(should_pass_strings)/sizeof(should_pass_strings[0]);++i){
fprintf(stderr, "%8d) ", i+1);
if(!fun(should_pass_strings[i].str, should_pass_strings[i].flags)){
++passed;
}else{
fprintf(stderr, "%13s%s\n", "", should_pass_strings[i].str);
}
}
fprintf(stderr, "\n");
printf("Running %d tests that should fail...\n", should_fail_cnt);
for(unsigned i = 0;i < sizeof(should_fail_strings)/sizeof(should_fail_strings[0]);++i){
fprintf(stderr, "%8d) ", i+1);
if(fun(should_fail_strings[i].str, should_fail_strings[i].flags)){
++passed;
}else{
fprintf(stderr, "%13s%s\n", "", should_fail_strings[i].str);
}
}
return passed;
}
int main(){
int normal_passed = run_test(test);
int cback_passed = run_test(test_cbacks);
int total_passed = normal_passed + cback_passed;
fprintf(stderr, "\nResults: %d/%d normal tests passed\n", normal_passed, total_tests);
fprintf(stderr, "Results: %d/%d callback tests passed\n", cback_passed, total_tests);
fprintf(stderr, "Results: %d/%d tests passed\n", total_passed, total_tests*2);
}