Saving progress. Wrote tests for json

This commit is contained in:
Андреев Григорий 2026-01-28 01:39:58 +03:00
parent ff3edd6426
commit 11de21a90b
3 changed files with 105 additions and 40 deletions

View File

@ -7,6 +7,7 @@
/* Points to some string (BIN segment) + contains decoded json object */
typedef struct {
U32 version;
Json gltf;
/* If length is 0, BIN segment is absent */
SpanU8 bin_segment;
@ -26,6 +27,7 @@ int glb_file_get_segments(SpanU8 file, GLBFileSegments* ret){
if (*(const U32*)file.data != 0x46546C67) {
return 2;
}
U32 version = *(const U32*)(file.data + 4);
/* Nobody cares about version */
if (*(const U32*)(file.data + 8) != file.len) {
return 3;
@ -54,17 +56,18 @@ int glb_file_get_segments(SpanU8 file, GLBFileSegments* ret){
}
bin_segment = cur_segment;
}
cur += 8 + chunk_length;
}
if (json_segment.len == 0) {
/* Illegal, no json segment */
return 8;
}
// if (json_segment.len == 0) {
// /* Illegal, no json segment */
// return 8;
// }
OptionJson parsed_json = json_decode(json_segment, 15);
if (parsed_json.variant == Option_None) {
return 9;
}
/* Everything is correct */
*ret = (GLBFileSegments){.gltf = parsed_json.some, .bin_segment = bin_segment};
*ret = (GLBFileSegments){.version = version, .gltf = parsed_json.some, .bin_segment = bin_segment};
return 0;
}

View File

@ -127,7 +127,7 @@ int json_decoding_parse_string(SpanU8* rem, VecU8* ret_str){
} else if (ch == 'f') {
VecU8_append(&res, '\f');
} else if (ch == 'n') {
VecU8_append(&res, '\b');
VecU8_append(&res, '\n');
} else if (ch == 'r') {
VecU8_append(&res, '\r');
} else if (ch == 't') {
@ -173,14 +173,16 @@ OptionJson json_decoding_h_no_spaces(SpanU8* rem, U32 depth_rem){
if (depth_rem == 0) {
return None_Json();
}
float fl_value;
int fl_code = SpanU8_read_float(rem, &fl_value);
if (fl_code == 0)
return Some_Json(Json_from_float(fl_value));
S64 int_value;
int int_code = SpanU8_read_S64(rem, &int_value);
if (int_code == 0)
return Some_Json(Json_from_int(int_value));
float fl_value;
int fl_code = SpanU8_read_float(rem, &fl_value);
if (fl_code == 0)
return Some_Json(Json_from_float(fl_value));
bool false_code = SpanU8_parsing_try_read_prefix(rem, cstr("false"));
if (false_code)
return Some_Json(Json_False);
@ -234,30 +236,31 @@ OptionJson json_decoding_h_no_spaces(SpanU8* rem, U32 depth_rem){
RBTree_MapVecU8ToJson_drop(dict);
return None_Json();
}
VecU8 key;
int key_code = json_decoding_parse_string(rem, &key);
if (key_code) {
RBTree_MapVecU8ToJson_drop(dict);
return None_Json();
}
SpanU8_parsing_skip_spaces(rem);
if (!SpanU8_parsing_try_read_char(rem, ':')) {
RBTree_MapVecU8ToJson_drop(dict);
VecU8_drop(key);
return None_Json();
}
OptionJson x = json_decoding_h(rem, depth_rem - 1);
if (x.variant == Option_None) {
RBTree_MapVecU8ToJson_drop(dict);
VecU8_drop(key);
return None_Json();
}
bool iret = RBTree_MapVecU8ToJson_insert(&dict, key, x.some);
if (!iret) {
/* Two elements of dictionary share the same key. Very illegal */
RBTree_MapVecU8ToJson_drop(dict);
return None_Json();
}
}
SpanU8_parsing_skip_spaces(rem);
VecU8 key;
int key_code = json_decoding_parse_string(rem, &key);
if (key_code) {
RBTree_MapVecU8ToJson_drop(dict);
return None_Json();
}
SpanU8_parsing_skip_spaces(rem);
if (!SpanU8_parsing_try_read_char(rem, ':')) {
RBTree_MapVecU8ToJson_drop(dict);
VecU8_drop(key);
return None_Json();
}
OptionJson x = json_decoding_h(rem, depth_rem - 1);
if (x.variant == Option_None) {
RBTree_MapVecU8ToJson_drop(dict);
VecU8_drop(key);
return None_Json();
}
bool iret = RBTree_MapVecU8ToJson_insert(&dict, key, x.some);
if (!iret) {
/* Two elements of dictionary share the same key. Very illegal */
RBTree_MapVecU8ToJson_drop(dict);
return None_Json();
}
}
}

View File

@ -165,13 +165,17 @@ void tt15(){
test_s64_reading_with_good_inp(cstr("0-"), 0, 1);
}
void test_float_near(float right_val, float val, float eps){
check((right_val >= +1e60 && val >= +1e60) || (right_val <= -1e60 && val <= -1e60) || fabsf(right_val - val) < eps);
}
void test_float_reading_with_good_inp(SpanU8 str, float right_val, float eps, U64 lo){
SpanU8 rem = str;
float val;
int c = SpanU8_read_float(&rem, &val);
check(c == 0);
check(rem.data == str.data + str.len - lo && rem.len == lo);
check((right_val >= +1e60 && val >= +1e60) || (right_val <= -1e60 && val <= -1e60) || fabsf(right_val - val) < eps);
test_float_near(right_val, val, eps);
}
void tt16(){
@ -321,18 +325,69 @@ void test_json_equal(const Json* a, const Json* b){
if (a->variant == Json_integer) {
check(a->integer == b->integer);
} else if (a->variant == Json_float) {
check(fabsf(a->float_num - b->float_num))
test_float_near(a->float_num, b->float_num, 0.01f);
} else if (a->variant == Json_str) {
check(VecU8_equal_VecU8(&a->str, &b->str));
} else if (a->variant == Json_arr) {
const VecJson* A = &a->arr;
const VecJson* B = &b->arr;
check(A->len == B->len);
for (size_t i = 0; i < A->len; i++) {
test_json_equal(&A->buf[i], &B->buf[i]);
}
} else if (a->variant == Json_dict) {
const json_dictionary_t* A = &a->dict;
const json_dictionary_t* B = &b->dict;
RBTreeNode_KVPVecU8ToJson* i_a = RBTree_MapVecU8ToJson_find_min(A);
RBTreeNode_KVPVecU8ToJson* i_b = RBTree_MapVecU8ToJson_find_min(B);
while (i_a != NULL && i_b != NULL) {
check(VecU8_equal_VecU8(&i_a->key, &i_b->key));
test_json_equal(&i_a->value, &i_b->value);
i_a = RBTree_MapVecU8ToJson_find_next(A, i_a);
i_b = RBTree_MapVecU8ToJson_find_next(B, i_b);
}
check(i_a == NULL);
check(i_b == NULL);
}
}
void test_json_decoding_ok(const char* str_lit, Json right_ans){
OptionJson my_ans = json_decode(SpanU8_from_cstr(str_lit), 10);
check(my_ans.variant == Option_Some);
test_json_equal(&my_ans.some, &right_ans);
Json_drop(my_ans.some);
Json_drop(right_ans);
}
void tt27(){
test_json_decoding_ok("true", Json_True);
test_json_decoding_ok("\n\n1233", Json_from_int(1233));
test_json_decoding_ok("false\r \t ", Json_False);
test_json_decoding_ok(" none", Json_None);
test_json_decoding_ok("999999999999999999999999999999999999999", Json_from_float(1e100));
test_json_decoding_ok(" [ \t\r\r\n ]", Json_from_VecJson(VecJson_new()));
test_json_decoding_ok(" { } ", Json_from_MapVecU8ToJson(RBTree_MapVecU8ToJson_new()));
test_json_decoding_ok(" \"7\" ", Json_from_SpanU8(cstr("7")));
test_json_decoding_ok(" \"XXX\" ", Json_from_SpanU8(cstr("XXX")));
{
VecJson x = VecJson_new();
VecJson_append(&x, Json_from_int(12));
VecJson_append(&x, Json_from_int(23));
VecJson_append(&x, Json_from_int(34));
test_json_decoding_ok("[ 12,23 , \n 34 ]", Json_from_VecJson(x));
}
{
json_dictionary_t x = RBTree_MapVecU8ToJson_new();
RBTree_MapVecU8ToJson_insert(&x, vcstr("XXX"), Json_from_int(9990));
test_json_decoding_ok(" { \"XXX\" : 9990 }", Json_from_MapVecU8ToJson(x));
}
}
void tt28(){
json_dictionary_t x = RBTree_MapVecU8ToJson_new();
RBTree_MapVecU8ToJson_insert(&x, vcstr("9\u0449AB-"), Json_from_bool(false));
RBTree_MapVecU8ToJson_insert(&x, vcstr("9\u0449A"), Json_from_int(999));
test_json_decoding_ok(" { \"9\u0449A\" : 999 , \"9\\u0449AB-\" : false }", Json_from_MapVecU8ToJson(x));
}
void test_json_decoding_with_ill_formed_inp(const char* str_lit){
@ -340,11 +395,14 @@ void test_json_decoding_with_ill_formed_inp(const char* str_lit){
check(res.variant == Option_None);
}
void tt28(){
void tt29(){
test_json_decoding_with_ill_formed_inp("{");
test_json_decoding_with_ill_formed_inp("{\"A\": 12, \"A\": 12}");
test_json_decoding_with_ill_formed_inp("[");
test_json_decoding_with_ill_formed_inp("123e2222222222222222222222222");
test_json_decoding_with_ill_formed_inp("999999999999999999999999999999999999999");
test_json_decoding_with_ill_formed_inp("\"666");
test_json_decoding_with_ill_formed_inp("{{{}}");
test_json_decoding_with_ill_formed_inp("{\"a\": 2 \"b\": 12}");
test_json_decoding_with_ill_formed_inp("f");
test_json_decoding_with_ill_formed_inp("tru");
test_json_decoding_with_ill_formed_inp("none3");
@ -356,6 +414,7 @@ void tt28(){
int main(){
tt1(); tt2(); tt3(); tt4(); tt5(); tt6(); tt7(); tt8(); tt9(); tt10(); tt11(); tt12(); tt13(); tt14(); tt15();
tt16(); tt17(); tt18(); tt19();
tt20(); tt21(); tt22(); tt23(); tt24(); tt25(); tt26();
tt20(); tt21(); tt22(); tt23(); tt24(); tt25(); tt26(); tt27();
tt28(); tt29();
return 0;
}