Skip to content

Commit

Permalink
test(obj): add match_object unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
RiadhAdrani committed Feb 3, 2025
1 parent dabc106 commit 660e4c0
Show file tree
Hide file tree
Showing 18 changed files with 336 additions and 65 deletions.
21 changes: 21 additions & 0 deletions common.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,24 @@ JsonValue *match_any(char *json, int *current, int size)

return value;
}

char *slice_string(const char *str, int start, int end)
{
if (!str || start < 0 || end <= start || start >= (int)strlen(str))
{
return NULL; // Handle invalid input
}

int length = end - start;
char *result = (char *)malloc(length + 1); // Allocate memory for new string

if (!result)
{
return NULL; // Handle memory allocation failure
}

strncpy(result, str + start, length); // Copy substring
result[length] = '\0'; // Null-terminate the string

return result;
}
2 changes: 2 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,6 @@ char *get_json_file_content(char *path);
JsonError *create_json_error(int index, char *code);
void free_json_error(JsonError *error);

char *slice_string(const char *str, int start, int end);

#endif
149 changes: 84 additions & 65 deletions obj.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,107 +30,126 @@ JsonValue *match_object(char *json, int *index, int size)

JsonValue *value = NULL;
JsonValue *key = NULL;
int comma = 0;

int expect_key = 1;
int expect_colon = 0;
int expect_value = 0;
int expect_comma = 0;
int expect_end = 1;

char ch = '\0';
int insert = -1;

while (result->end < size)
{
skip_empty(json, &result->end, size);

if (json[result->end] == '}')
ch = json[result->end];

if (expect_end && ch == '}')
{
// no trailing comma
if (comma == 0)
{
free_json_error(result->error);
result->error = NULL;
}
else
{
result->error->code = "object-no-trailing-comma";
result->error->index = result->end;
}
free_json_error(result->error);
result->error = NULL;

break;
}
else
{
expect_end = 0;
}

if (value != NULL)
if (expect_key)
{
// we need to match a comma, as we didn't match a closing brace
if (json[result->end] != ',')
key = match_string(json, &result->end, size);

if (key->error != NULL)
{
result->error->code = "object-missing-comma";
result->error->code = "object-expected-a-key";
result->error->index = result->end;
break;
}

result->end++;
skip_empty(json, &result->end, size);

value = NULL;
result->end = key->end + 1;
expect_key = 0;
expect_colon = 1;
continue;
}

// just in case
if (key != NULL)
if (expect_colon)
{
break;
}
if (json[result->end] != ':')
{
result->error->code = "object-no-colon-between-key-and-value";
result->error->index = result->end;
break;
}

// start by matching a key
key = match_string(json, &result->end, size);
if (key->error != NULL)
{
result->error->code = "object-invalid-key";
result->error->index = result->end;
break;
result->end++;
expect_colon = 0;
expect_value = 1;
continue;
}

result->end = key->end + 1;
skip_empty(json, &result->end, size);

// match a colon
if (json[result->end] != ':')
if (expect_value)
{
result->error->code = "object-no-colon-between-key-and-value";
result->error->index = result->end;
break;
}
value = match_any(json, &result->end, size);

result->end++;
if (value->error != NULL)
{
result->error = value->error;
break;
}

skip_empty(json, &result->end, size);
insert = insert_in_object(result->object, key->string, value);
if (insert != INSERT_OK)
{
if (insert == INSERT_EXISTS)
{
result->error->code = "object-duplicate-key";
}
else if (insert == INSERT_OVERFLOW)
{
result->error->code = "object-max-capacity-reached";
}
else
{
result->error->code = "object-unable-to-insert-value";
}

// match a value
value = match_any(json, &result->end, size);
break;
}

if (value == NULL)
{
result->error->code = "object-invalid-value";
result->error->index = result->end;
break;
result->end = value->end + (value->type == JSON_NUMBER ? 0 : 1);
expect_comma = 1;
expect_end = 1;
expect_value = 0;
key = NULL;
value = NULL;
continue;
}

result->end = value->end + 1;

// append key and value
// check for collision
if (get_object_value(result->object, key->string) != NULL)
if (expect_comma)
{
result->error->code = "object-key-collision";
result->error->index = result->end;
break;
}

insert_in_object(result->object, key->string, value);
if (json[result->end] != ',')
{
result->error->code = "object-missing-seperation-comma";
result->error->index = result->end;
break;
}

value = NULL;
key = NULL;
result->end++;
expect_comma = 0;
expect_end = 0;
expect_key = 1;
continue;
}

result->end++;
break;
}

if (result->error != NULL)
{
if (strcmp(result->error->code, "") && json[result->end] != '}')
if (strcmp(result->error->code, "") == 0 && ch != '}')
{
result->error->code = "object-missing-closing-brace";
}
Expand Down
7 changes: 7 additions & 0 deletions str.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "str.h"

JsonValue *match_string(char *json, int *index, int size)
Expand Down Expand Up @@ -87,5 +88,11 @@ JsonValue *match_string(char *json, int *index, int size)
}
}

if (result->error == NULL)
{
// copy the value of the string from start to end in a new string
result->string = slice_string(json, result->start + 1, result->end);
}

return result;
}
9 changes: 9 additions & 0 deletions tests/json/obj_count.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"number":1,
"string":"hello",
"true":true,
"false":false,
"null":null,
"array":[1,2,3],
"object":{"type":"object"}
}
1 change: 1 addition & 0 deletions tests/json/obj_duplicate_key.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "hello":"world", "hello":2 }
1 change: 1 addition & 0 deletions tests/json/obj_nested_1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"obj":{"count":1}}
1 change: 1 addition & 0 deletions tests/json/obj_nested_2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"obj":{"count":{"count":1}}}
1 change: 1 addition & 0 deletions tests/json/obj_nested_3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"obj":{"count":{"count":{"count":1}}}}
1 change: 1 addition & 0 deletions tests/json/obj_no_closing_brace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "hello":"world"
1 change: 1 addition & 0 deletions tests/json/obj_no_seperation_colon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"k" 2}
1 change: 1 addition & 0 deletions tests/json/obj_no_seperation_comma.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"k":2 "b":3}
1 change: 1 addition & 0 deletions tests/json/obj_no_starting_brace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
}
1 change: 1 addition & 0 deletions tests/json/obj_no_trailing_comma.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"hello":{},}
1 change: 1 addition & 0 deletions tests/json/obj_simple.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
2 changes: 2 additions & 0 deletions tests/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "number.h"
#include "str.h"
#include "array.h"
#include "obj.h"
#include "common.h"

void add_suite(char *name, CU_TestInfo items[])
Expand Down Expand Up @@ -38,6 +39,7 @@ int main()
add_suite("Number", number_tests);
add_suite("String", str_tests);
add_suite("Array", array_tests);
add_suite("Object", obj_tests);

// Run tests using the basic interface
CU_basic_set_mode(CU_BRM_VERBOSE);
Expand Down
Loading

0 comments on commit 660e4c0

Please sign in to comment.