mirror of
https://github.com/kgabis/parson.git
synced 2025-01-14 06:12:54 +08:00
Merged changes from parson-devel (serialization, copying, comparing, validation, creating values).
This commit is contained in:
parent
55856a2eab
commit
638190d6a0
76
README.md
Normal file → Executable file
76
README.md
Normal file → Executable file
@ -1,6 +1,5 @@
|
|||||||
##About
|
##About
|
||||||
Parson is a lighweight [json](http://json.org) parser and reader written in C.
|
Parson is a lighweight [json](http://json.org) library written in C.
|
||||||
If you need serialization and json value building in code, use [parson-devel](https://github.com/kgabis/parson-devel), which has extended API, but may change in future.
|
|
||||||
|
|
||||||
##Features
|
##Features
|
||||||
* Full JSON support
|
* Full JSON support
|
||||||
@ -11,7 +10,7 @@ If you need serialization and json value building in code, use [parson-devel](ht
|
|||||||
* Test suites
|
* Test suites
|
||||||
|
|
||||||
##Installation
|
##Installation
|
||||||
Run the following code:
|
Run:
|
||||||
```
|
```
|
||||||
git clone https://github.com/kgabis/parson.git
|
git clone https://github.com/kgabis/parson.git
|
||||||
```
|
```
|
||||||
@ -19,8 +18,9 @@ and copy parson.h and parson.c to you source code tree.
|
|||||||
|
|
||||||
Run ```make test``` to compile and run tests.
|
Run ```make test``` to compile and run tests.
|
||||||
|
|
||||||
##Example
|
##Examples
|
||||||
Here is a function, which prints basic commit info (date, sha and author) from a github repository. It's also included in tests.c file, you can just uncomment and run it.
|
###Parsing JSON
|
||||||
|
Here is a function, which prints basic commit info (date, sha and author) from a github repository.
|
||||||
```c
|
```c
|
||||||
void print_commits_info(const char *username, const char *repo) {
|
void print_commits_info(const char *username, const char *repo) {
|
||||||
JSON_Value *root_value;
|
JSON_Value *root_value;
|
||||||
@ -75,5 +75,71 @@ Date SHA Author
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
###Persistence
|
||||||
|
In this example I'm using parson to save user information to a file and then load it and validate later.
|
||||||
|
```c
|
||||||
|
void persistence_example(void) {
|
||||||
|
JSON_Value *schema = json_parse_string("{\"name\":\"\"}");
|
||||||
|
JSON_Value *user_data = json_parse_file("user_data.json");
|
||||||
|
char buf[256];
|
||||||
|
const char *name = NULL;
|
||||||
|
if (!user_data || !json_validate(schema, user_data) == JSONSuccess) {
|
||||||
|
puts("Enter your name:");
|
||||||
|
scanf("%s", buf);
|
||||||
|
user_data = json_value_init_object();
|
||||||
|
json_object_set_string(json_object(user_data), "name", buf);
|
||||||
|
json_serialize_to_file(user_data, "user_data.json");
|
||||||
|
}
|
||||||
|
name = json_object_get_string(json_object(user_data), "name");
|
||||||
|
printf("Hello, %s.", name);
|
||||||
|
json_value_free(schema);
|
||||||
|
json_value_free(user_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
###Serialization
|
||||||
|
Creating JSON values is very simple thanks to the dot notation.
|
||||||
|
Object hierarchy is automatically created when addressing specific fields.
|
||||||
|
In the following example I create a simple JSON value containing basic information about a person.
|
||||||
|
```c
|
||||||
|
void serialization_example(void) {
|
||||||
|
JSON_Value *root_value = json_value_init_object();
|
||||||
|
JSON_Object *root_object = json_value_get_object(root_value);
|
||||||
|
char *serialized_string = NULL;
|
||||||
|
json_object_set_string(root_object, "name", "John Smith");
|
||||||
|
json_object_set_number(root_object, "age", 25);
|
||||||
|
json_object_dotset_string(root_object, "address.city", "Cupertino");
|
||||||
|
json_object_dotset_value(root_object, "contact.emails", json_parse_string("[\"email@example.com\",\"email2@example.com\"]"));
|
||||||
|
serialized_string = json_serialize_to_string(root_value);
|
||||||
|
puts(serialized_string);
|
||||||
|
json_free_serialized_string(serialized_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Created value (after formatting outside parson):
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"name":"John Smith",
|
||||||
|
"age":25,
|
||||||
|
"address":{
|
||||||
|
"city":"Cupertino"
|
||||||
|
},
|
||||||
|
"contact":{
|
||||||
|
"emails":[
|
||||||
|
"email@example.com",
|
||||||
|
"email2@example.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##Contributing
|
||||||
|
|
||||||
|
I will always merge *working* bug fixes. However, if you want to add something to the API,
|
||||||
|
I *won't* merge it without prior discussion.
|
||||||
|
Remember to follow parson's code style and write appropriate tests.
|
||||||
|
|
||||||
##License
|
##License
|
||||||
[The MIT License (MIT)](http://opensource.org/licenses/mit-license.php)
|
[The MIT License (MIT)](http://opensource.org/licenses/mit-license.php)
|
131
parson.h
Normal file → Executable file
131
parson.h
Normal file → Executable file
@ -36,38 +36,68 @@ typedef struct json_object_t JSON_Object;
|
|||||||
typedef struct json_array_t JSON_Array;
|
typedef struct json_array_t JSON_Array;
|
||||||
typedef struct json_value_t JSON_Value;
|
typedef struct json_value_t JSON_Value;
|
||||||
|
|
||||||
typedef enum json_value_type {
|
enum json_value_type {
|
||||||
JSONError = 0,
|
JSONError = -1,
|
||||||
JSONNull = 1,
|
JSONNull = 1,
|
||||||
JSONString = 2,
|
JSONString = 2,
|
||||||
JSONNumber = 3,
|
JSONNumber = 3,
|
||||||
JSONObject = 4,
|
JSONObject = 4,
|
||||||
JSONArray = 5,
|
JSONArray = 5,
|
||||||
JSONBoolean = 6
|
JSONBoolean = 6
|
||||||
} JSON_Value_Type;
|
};
|
||||||
|
typedef int JSON_Value_Type;
|
||||||
|
|
||||||
|
enum json_result_t {
|
||||||
|
JSONSuccess = 0,
|
||||||
|
JSONFailure = -1
|
||||||
|
};
|
||||||
|
typedef int JSON_Status;
|
||||||
|
|
||||||
/* Parses first JSON value in a file, returns NULL in case of error */
|
/* Parses first JSON value in a file, returns NULL in case of error */
|
||||||
JSON_Value * json_parse_file(const char *filename);
|
JSON_Value * json_parse_file(const char *filename);
|
||||||
|
|
||||||
/* Parses first JSON value in a file and ignores comments (/ * * / and //),
|
/* Parses first JSON value in a file and ignores comments (/ * * / and //),
|
||||||
returns NULL in case of error */
|
returns NULL in case of error */
|
||||||
JSON_Value * json_parse_file_with_comments(const char *filename);
|
JSON_Value * json_parse_file_with_comments(const char *filename);
|
||||||
|
|
||||||
/* Parses first JSON value in a string, returns NULL in case of error */
|
/* Parses first JSON value in a string, returns NULL in case of error */
|
||||||
JSON_Value * json_parse_string(const char *string);
|
JSON_Value * json_parse_string(const char *string);
|
||||||
|
|
||||||
/* Parses first JSON value in a string and ignores comments (/ * * / and //),
|
/* Parses first JSON value in a string and ignores comments (/ * * / and //),
|
||||||
returns NULL in case of error */
|
returns NULL in case of error */
|
||||||
JSON_Value * json_parse_string_with_comments(const char *string);
|
JSON_Value * json_parse_string_with_comments(const char *string);
|
||||||
|
|
||||||
/* JSON Object */
|
/* Serialization */
|
||||||
|
size_t json_serialization_size(const JSON_Value *value);
|
||||||
|
JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
|
||||||
|
JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename);
|
||||||
|
char * json_serialize_to_string(const JSON_Value *value);
|
||||||
|
void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string */
|
||||||
|
|
||||||
|
/* Comparing */
|
||||||
|
int json_value_equals(const JSON_Value *a, const JSON_Value *b);
|
||||||
|
|
||||||
|
/* Validation
|
||||||
|
This is *NOT* JSON Schema. It validates json by checking if object have identically
|
||||||
|
named fields with matching types.
|
||||||
|
For example schema {"name":"", "age":0} will validate
|
||||||
|
{"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
|
||||||
|
but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
|
||||||
|
In case of arrays, only first value in schema is checked against all values in tested array.
|
||||||
|
Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays,
|
||||||
|
null validates values of every type.
|
||||||
|
*/
|
||||||
|
JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JSON Object
|
||||||
|
*/
|
||||||
JSON_Value * json_object_get_value (const JSON_Object *object, const char *name);
|
JSON_Value * json_object_get_value (const JSON_Object *object, const char *name);
|
||||||
const char * json_object_get_string (const JSON_Object *object, const char *name);
|
const char * json_object_get_string (const JSON_Object *object, const char *name);
|
||||||
JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
|
JSON_Object * json_object_get_object (const JSON_Object *object, const char *name);
|
||||||
JSON_Array * json_object_get_array (const JSON_Object *object, const char *name);
|
JSON_Array * json_object_get_array (const JSON_Object *object, const char *name);
|
||||||
double json_object_get_number (const JSON_Object *object, const char *name);
|
double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
|
||||||
int json_object_get_boolean(const JSON_Object *object, const char *name);
|
int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
|
||||||
|
|
||||||
/* dotget functions enable addressing values with dot notation in nested objects,
|
/* dotget functions enable addressing values with dot notation in nested objects,
|
||||||
just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
|
just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
|
||||||
@ -77,30 +107,95 @@ JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *
|
|||||||
const char * json_object_dotget_string (const JSON_Object *object, const char *name);
|
const char * json_object_dotget_string (const JSON_Object *object, const char *name);
|
||||||
JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
|
JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name);
|
||||||
JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name);
|
JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name);
|
||||||
double json_object_dotget_number (const JSON_Object *object, const char *name);
|
double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */
|
||||||
int json_object_dotget_boolean(const JSON_Object *object, const char *name);
|
int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
|
||||||
|
|
||||||
/* Functions to get available names */
|
/* Functions to get available names */
|
||||||
size_t json_object_get_count(const JSON_Object *object);
|
size_t json_object_get_count(const JSON_Object *object);
|
||||||
const char * json_object_get_name (const JSON_Object *object, size_t index);
|
const char * json_object_get_name (const JSON_Object *object, size_t index);
|
||||||
|
|
||||||
/* JSON Array */
|
/* Creates new name-value pair or frees and replaces old value with new one. */
|
||||||
|
JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
|
||||||
|
JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
|
||||||
|
JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
|
||||||
|
JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
|
||||||
|
JSON_Status json_object_set_null(JSON_Object *object, const char *name);
|
||||||
|
|
||||||
|
/* Works like dotget functions, but creates whole hierarchy if necessary. */
|
||||||
|
JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value);
|
||||||
|
JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string);
|
||||||
|
JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number);
|
||||||
|
JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean);
|
||||||
|
JSON_Status json_object_dotset_null(JSON_Object *object, const char *name);
|
||||||
|
|
||||||
|
/* Frees and removes name-value pair */
|
||||||
|
JSON_Status json_object_remove(JSON_Object *object, const char *name);
|
||||||
|
|
||||||
|
/* Works like dotget function, but removes name-value pair only on exact match. */
|
||||||
|
JSON_Status json_object_dotremove(JSON_Object *object, const char *key);
|
||||||
|
|
||||||
|
/* Removes all name-value pairs in object */
|
||||||
|
JSON_Status json_object_clear(JSON_Object *object);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*JSON Array
|
||||||
|
*/
|
||||||
JSON_Value * json_array_get_value (const JSON_Array *array, size_t index);
|
JSON_Value * json_array_get_value (const JSON_Array *array, size_t index);
|
||||||
const char * json_array_get_string (const JSON_Array *array, size_t index);
|
const char * json_array_get_string (const JSON_Array *array, size_t index);
|
||||||
JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
|
JSON_Object * json_array_get_object (const JSON_Array *array, size_t index);
|
||||||
JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
|
JSON_Array * json_array_get_array (const JSON_Array *array, size_t index);
|
||||||
double json_array_get_number (const JSON_Array *array, size_t index);
|
double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */
|
||||||
int json_array_get_boolean(const JSON_Array *array, size_t index);
|
int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
|
||||||
size_t json_array_get_count (const JSON_Array *array);
|
size_t json_array_get_count (const JSON_Array *array);
|
||||||
|
|
||||||
|
/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
|
||||||
|
* Order of values in array may change during execution. */
|
||||||
|
JSON_Status json_array_remove(JSON_Array *array, size_t i);
|
||||||
|
|
||||||
|
/* Frees and removes from array value at given index and replaces it with given one.
|
||||||
|
* Does nothing and returns JSONFailure if index doesn't exist. */
|
||||||
|
JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
|
||||||
|
JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string);
|
||||||
|
JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
|
||||||
|
JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
|
||||||
|
JSON_Status json_array_replace_null(JSON_Array *array, size_t i);
|
||||||
|
|
||||||
|
/* Frees and removes all values from array */
|
||||||
|
JSON_Status json_array_clear(JSON_Array *array);
|
||||||
|
|
||||||
|
/* Appends new value at the end of array. */
|
||||||
|
JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value);
|
||||||
|
JSON_Status json_array_append_string(JSON_Array *array, const char *string);
|
||||||
|
JSON_Status json_array_append_number(JSON_Array *array, double number);
|
||||||
|
JSON_Status json_array_append_boolean(JSON_Array *array, int boolean);
|
||||||
|
JSON_Status json_array_append_null(JSON_Array *array);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*JSON Value
|
||||||
|
*/
|
||||||
|
JSON_Value * json_value_init_object (void);
|
||||||
|
JSON_Value * json_value_init_array (void);
|
||||||
|
JSON_Value * json_value_init_string (const char *string); /* copies passed string */
|
||||||
|
JSON_Value * json_value_init_number (double number);
|
||||||
|
JSON_Value * json_value_init_boolean(int boolean);
|
||||||
|
JSON_Value * json_value_init_null (void);
|
||||||
|
JSON_Value * json_value_deep_copy (const JSON_Value *value);
|
||||||
|
void json_value_free (JSON_Value *value);
|
||||||
|
|
||||||
/* JSON Value */
|
|
||||||
JSON_Value_Type json_value_get_type (const JSON_Value *value);
|
JSON_Value_Type json_value_get_type (const JSON_Value *value);
|
||||||
JSON_Object * json_value_get_object (const JSON_Value *value);
|
JSON_Object * json_value_get_object (const JSON_Value *value);
|
||||||
JSON_Array * json_value_get_array (const JSON_Value *value);
|
JSON_Array * json_value_get_array (const JSON_Value *value);
|
||||||
const char * json_value_get_string (const JSON_Value *value);
|
const char * json_value_get_string (const JSON_Value *value);
|
||||||
double json_value_get_number (const JSON_Value *value);
|
double json_value_get_number (const JSON_Value *value);
|
||||||
int json_value_get_boolean(const JSON_Value *value);
|
int json_value_get_boolean(const JSON_Value *value);
|
||||||
void json_value_free (JSON_Value *value);
|
|
||||||
|
/* Same as above, but shorter */
|
||||||
|
JSON_Value_Type json_type (const JSON_Value *value);
|
||||||
|
JSON_Object * json_object (const JSON_Value *value);
|
||||||
|
JSON_Array * json_array (const JSON_Value *value);
|
||||||
|
const char * json_string (const JSON_Value *value);
|
||||||
|
double json_number (const JSON_Value *value);
|
||||||
|
int json_boolean(const JSON_Value *value);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
154
tests.c
Normal file → Executable file
154
tests.c
Normal file → Executable file
@ -20,6 +20,9 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "parson.h"
|
#include "parson.h"
|
||||||
|
|
||||||
@ -30,53 +33,68 @@
|
|||||||
#define TEST(A) printf("%-72s-",#A); \
|
#define TEST(A) printf("%-72s-",#A); \
|
||||||
if(A){puts(" OK");tests_passed++;} \
|
if(A){puts(" OK");tests_passed++;} \
|
||||||
else{puts(" FAIL");tests_failed++;}
|
else{puts(" FAIL");tests_failed++;}
|
||||||
#define STREQ(A, B) (A && B ? strcmp(A, B) == 0 : 0)
|
#define STREQ(A, B) ((A) && (B) ? strcmp((A), (B)) == 0 : 0)
|
||||||
|
|
||||||
|
void test_suite_1(void); /* Test 3 files from json.org + serialization*/
|
||||||
void test_suite_1(void);
|
void test_suite_2(JSON_Value *value); /* Test correctness of parsed values */
|
||||||
void test_suite_2(JSON_Value *value);
|
|
||||||
void test_suite_2_no_comments(void);
|
void test_suite_2_no_comments(void);
|
||||||
void test_suite_2_with_comments(void);
|
void test_suite_2_with_comments(void);
|
||||||
void test_suite_3(void);
|
void test_suite_3(void); /* Test incorrect values */
|
||||||
|
void test_suite_4(void); /* Test deep copy funtion */
|
||||||
|
void test_suite_5(void); /* Test building json values from scratch */
|
||||||
|
void test_suite_6(void); /* Test value comparing verification */
|
||||||
|
void test_suite_7(void); /* Test schema validation */
|
||||||
|
void test_suite_8(void); /* Test serialization to file */
|
||||||
|
|
||||||
char *read_file(const char *filename);
|
|
||||||
void print_commits_info(const char *username, const char *repo);
|
void print_commits_info(const char *username, const char *repo);
|
||||||
|
void persistence_example(void);
|
||||||
|
void serialization_example(void);
|
||||||
|
|
||||||
static int tests_passed;
|
static int tests_passed;
|
||||||
static int tests_failed;
|
static int tests_failed;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
/* Example function from readme file: */
|
/* Example functions from readme file: */
|
||||||
/* print_commits_info("torvalds", "linux"); */
|
/* print_commits_info("torvalds", "linux"); */
|
||||||
|
/* serialization_example(); */
|
||||||
|
/* persistence_example(); */
|
||||||
test_suite_1();
|
test_suite_1();
|
||||||
test_suite_2_no_comments();
|
test_suite_2_no_comments();
|
||||||
test_suite_2_with_comments();
|
test_suite_2_with_comments();
|
||||||
test_suite_3();
|
test_suite_3();
|
||||||
|
test_suite_4();
|
||||||
|
test_suite_5();
|
||||||
|
test_suite_6();
|
||||||
|
test_suite_7();
|
||||||
|
test_suite_8();
|
||||||
printf("Tests failed: %d\n", tests_failed);
|
printf("Tests failed: %d\n", tests_failed);
|
||||||
printf("Tests passed: %d\n", tests_passed);
|
printf("Tests passed: %d\n", tests_passed);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3 test files from json.org */
|
|
||||||
void test_suite_1(void) {
|
void test_suite_1(void) {
|
||||||
JSON_Value *val;
|
JSON_Value *val;
|
||||||
TEST((val = json_parse_file("tests/test_1_1.txt")) != NULL);
|
TEST((val = json_parse_file("tests/test_1_1.txt")) != NULL);
|
||||||
|
TEST(json_value_equals(json_parse_string(json_serialize_to_string(val)), val));
|
||||||
if (val) { json_value_free(val); }
|
if (val) { json_value_free(val); }
|
||||||
TEST((val = json_parse_file("tests/test_1_2.txt")) != NULL);
|
TEST((val = json_parse_file("tests/test_1_2.txt")) != NULL);
|
||||||
|
TEST(json_value_equals(json_parse_string(json_serialize_to_string(val)), val));
|
||||||
if (val) { json_value_free(val); }
|
if (val) { json_value_free(val); }
|
||||||
TEST((val = json_parse_file("tests/test_1_3.txt")) != NULL);
|
TEST((val = json_parse_file("tests/test_1_3.txt")) != NULL);
|
||||||
|
TEST(json_value_equals(json_parse_string(json_serialize_to_string(val)), val));
|
||||||
if (val) { json_value_free(val); }
|
if (val) { json_value_free(val); }
|
||||||
|
|
||||||
TEST((val = json_parse_file_with_comments("tests/test_1_1.txt")) != NULL);
|
TEST((val = json_parse_file_with_comments("tests/test_1_1.txt")) != NULL);
|
||||||
|
TEST(json_value_equals(json_parse_string(json_serialize_to_string(val)), val));
|
||||||
if (val) { json_value_free(val); }
|
if (val) { json_value_free(val); }
|
||||||
TEST((val = json_parse_file_with_comments("tests/test_1_2.txt")) != NULL);
|
TEST((val = json_parse_file_with_comments("tests/test_1_2.txt")) != NULL);
|
||||||
|
TEST(json_value_equals(json_parse_string(json_serialize_to_string(val)), val));
|
||||||
if (val) { json_value_free(val); }
|
if (val) { json_value_free(val); }
|
||||||
TEST((val = json_parse_file_with_comments("tests/test_1_3.txt")) != NULL);
|
TEST((val = json_parse_file_with_comments("tests/test_1_3.txt")) != NULL);
|
||||||
|
TEST(json_value_equals(json_parse_string(json_serialize_to_string(val)), val));
|
||||||
if (val) { json_value_free(val); }
|
if (val) { json_value_free(val); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Testing correctness of parsed values */
|
|
||||||
void test_suite_2(JSON_Value *root_value) {
|
void test_suite_2(JSON_Value *root_value) {
|
||||||
JSON_Object *root_object;
|
JSON_Object *root_object;
|
||||||
JSON_Array *array;
|
JSON_Array *array;
|
||||||
@ -125,11 +143,11 @@ void test_suite_2(JSON_Value *root_value) {
|
|||||||
TEST(json_object_dotget_value(root_object, "") == NULL);
|
TEST(json_object_dotget_value(root_object, "") == NULL);
|
||||||
|
|
||||||
array = json_object_dotget_array(root_object, "object.nested array");
|
array = json_object_dotget_array(root_object, "object.nested array");
|
||||||
|
TEST(array != NULL);
|
||||||
|
TEST(json_array_get_count(array) > 1);
|
||||||
if (array != NULL && json_array_get_count(array) > 1) {
|
if (array != NULL && json_array_get_count(array) > 1) {
|
||||||
TEST(STREQ(json_array_get_string(array, 0), "lorem"));
|
TEST(STREQ(json_array_get_string(array, 0), "lorem"));
|
||||||
TEST(STREQ(json_array_get_string(array, 1), "ipsum"));
|
TEST(STREQ(json_array_get_string(array, 1), "ipsum"));
|
||||||
} else {
|
|
||||||
tests_failed++;
|
|
||||||
}
|
}
|
||||||
TEST(json_object_dotget_boolean(root_object, "nested true"));
|
TEST(json_object_dotget_boolean(root_object, "nested true"));
|
||||||
|
|
||||||
@ -142,22 +160,21 @@ void test_suite_2(JSON_Value *root_value) {
|
|||||||
void test_suite_2_no_comments(void) {
|
void test_suite_2_no_comments(void) {
|
||||||
const char *filename = "tests/test_2.txt";
|
const char *filename = "tests/test_2.txt";
|
||||||
JSON_Value *root_value = NULL;
|
JSON_Value *root_value = NULL;
|
||||||
printf("Testing %s:\n", filename);
|
|
||||||
root_value = json_parse_file(filename);
|
root_value = json_parse_file(filename);
|
||||||
test_suite_2(root_value);
|
test_suite_2(root_value);
|
||||||
|
TEST(json_value_equals(root_value, json_parse_string(json_serialize_to_string(root_value))));
|
||||||
json_value_free(root_value);
|
json_value_free(root_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_suite_2_with_comments(void) {
|
void test_suite_2_with_comments(void) {
|
||||||
const char *filename = "tests/test_2_comments.txt";
|
const char *filename = "tests/test_2_comments.txt";
|
||||||
JSON_Value *root_value = NULL;
|
JSON_Value *root_value = NULL;
|
||||||
printf("Testing %s:\n", filename);
|
|
||||||
root_value = json_parse_file_with_comments(filename);
|
root_value = json_parse_file_with_comments(filename);
|
||||||
test_suite_2(root_value);
|
test_suite_2(root_value);
|
||||||
|
TEST(json_value_equals(root_value, json_parse_string(json_serialize_to_string(root_value))));
|
||||||
json_value_free(root_value);
|
json_value_free(root_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Testing values, on which parsing should fail */
|
|
||||||
void test_suite_3(void) {
|
void test_suite_3(void) {
|
||||||
char nested_20x[] = "[[[[[[[[[[[[[[[[[[[[\"hi\"]]]]]]]]]]]]]]]]]]]]";
|
char nested_20x[] = "[[[[[[[[[[[[[[[[[[[[\"hi\"]]]]]]]]]]]]]]]]]]]]";
|
||||||
puts("Testing invalid strings:");
|
puts("Testing invalid strings:");
|
||||||
@ -205,6 +222,80 @@ void test_suite_3(void) {
|
|||||||
TEST(json_parse_string("[\"\\uDF67\\uD834\"]") == NULL); /* wrong order surrogate pair */
|
TEST(json_parse_string("[\"\\uDF67\\uD834\"]") == NULL); /* wrong order surrogate pair */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_suite_4() {
|
||||||
|
const char *filename = "tests/test_2.txt";
|
||||||
|
JSON_Value *a = NULL, *a_copy = NULL;
|
||||||
|
printf("Testing %s:\n", filename);
|
||||||
|
a = json_parse_file(filename);
|
||||||
|
TEST(json_value_equals(a, a)); /* test equality test */
|
||||||
|
a_copy = json_value_deep_copy(a);
|
||||||
|
TEST(a_copy != NULL);
|
||||||
|
TEST(json_value_equals(a, a_copy));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_suite_5(void) {
|
||||||
|
JSON_Value *val_from_file = json_parse_file("tests/test_5.txt");
|
||||||
|
|
||||||
|
JSON_Value *val = json_value_init_object();
|
||||||
|
JSON_Object *obj = json_value_get_object(val);
|
||||||
|
TEST(json_object_set_string(obj, "first", "John") == JSONSuccess);
|
||||||
|
TEST(json_object_set_string(obj, "last", "Doe") == JSONSuccess);
|
||||||
|
TEST(json_object_set_number(obj, "age", 25) == JSONSuccess);
|
||||||
|
TEST(json_object_set_boolean(obj, "registered", 1) == JSONSuccess);
|
||||||
|
TEST(json_object_set_value(obj, "interests", json_value_init_array()) == JSONSuccess);
|
||||||
|
TEST(json_array_append_string(json_object_get_array(obj, "interests"), "Writing") == JSONSuccess);
|
||||||
|
TEST(json_array_append_string(json_object_get_array(obj, "interests"), "Mountain Biking") == JSONSuccess);
|
||||||
|
TEST(json_array_replace_string(json_object_get_array(obj, "interests"), 0, "Reading") == JSONSuccess);
|
||||||
|
TEST(json_object_dotset_string(obj, "favorites.color", "blue") == JSONSuccess);
|
||||||
|
TEST(json_object_dotset_string(obj, "favorites.sport", "running") == JSONSuccess);
|
||||||
|
TEST(json_object_dotset_string(obj, "favorites.fruit", "apple") == JSONSuccess);
|
||||||
|
TEST(json_object_dotremove(obj, "favorites.fruit") == JSONSuccess);
|
||||||
|
TEST(json_object_set_string(obj, "utf string", "\\u006corem\\u0020ipsum") == JSONSuccess);
|
||||||
|
TEST(json_object_set_string(obj, "utf-8 string", "あいうえお") == JSONSuccess);
|
||||||
|
TEST(json_object_set_string(obj, "surrogate string", "lorem\\uD834\\uDD1Eipsum\\uD834\\uDF67lorem") == JSONSuccess);
|
||||||
|
TEST(json_value_equals(val_from_file, val));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_suite_6(void) {
|
||||||
|
const char *filename = "tests/test_2.txt";
|
||||||
|
JSON_Value *a = NULL;
|
||||||
|
JSON_Value *b = NULL;
|
||||||
|
a = json_parse_file(filename);
|
||||||
|
b = json_parse_file(filename);
|
||||||
|
TEST(json_value_equals(a, b));
|
||||||
|
json_object_set_string(json_object(a), "string", "eki");
|
||||||
|
TEST(!json_value_equals(a, b));
|
||||||
|
a = json_value_deep_copy(b);
|
||||||
|
TEST(json_value_equals(a, b));
|
||||||
|
json_array_append_number(json_object_get_array(json_object(b), "string array"), 1337);
|
||||||
|
TEST(!json_value_equals(a, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_suite_7(void) {
|
||||||
|
JSON_Value *val_from_file = json_parse_file("tests/test_5.txt");
|
||||||
|
JSON_Value *schema = json_value_init_object();
|
||||||
|
JSON_Object *schema_obj = json_value_get_object(schema);
|
||||||
|
json_object_set_string(schema_obj, "first", "");
|
||||||
|
json_object_set_string(schema_obj, "last", "");
|
||||||
|
json_object_set_number(schema_obj, "age", 0);
|
||||||
|
json_object_set_null(schema_obj, "favorites");
|
||||||
|
TEST(json_validate(schema, val_from_file) == JSONSuccess);
|
||||||
|
json_object_set_string(schema_obj, "age", "");
|
||||||
|
TEST(json_validate(schema, val_from_file) == JSONFailure);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_suite_8(void) {
|
||||||
|
const char *filename = "tests/test_2.txt";
|
||||||
|
const char *temp_filename = "tests/test_2_serialized.txt";
|
||||||
|
JSON_Value *a = NULL;
|
||||||
|
JSON_Value *b = NULL;
|
||||||
|
a = json_parse_file(filename);
|
||||||
|
TEST(json_serialize_to_file(a, temp_filename) == JSONSuccess);
|
||||||
|
b = json_parse_file(temp_filename);
|
||||||
|
TEST(json_value_equals(a, b));
|
||||||
|
remove(temp_filename);
|
||||||
|
}
|
||||||
|
|
||||||
void print_commits_info(const char *username, const char *repo) {
|
void print_commits_info(const char *username, const char *repo) {
|
||||||
JSON_Value *root_value;
|
JSON_Value *root_value;
|
||||||
JSON_Array *commits;
|
JSON_Array *commits;
|
||||||
@ -244,3 +335,36 @@ void print_commits_info(const char *username, const char *repo) {
|
|||||||
json_value_free(root_value);
|
json_value_free(root_value);
|
||||||
system(cleanup_command);
|
system(cleanup_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void persistence_example(void) {
|
||||||
|
JSON_Value *schema = json_parse_string("{\"name\":\"\"}");
|
||||||
|
JSON_Value *user_data = json_parse_file("user_data.json");
|
||||||
|
char buf[256];
|
||||||
|
const char *name = NULL;
|
||||||
|
if (!user_data || json_validate(schema, user_data) == JSONSuccess) {
|
||||||
|
puts("Enter your name:");
|
||||||
|
scanf("%s", buf);
|
||||||
|
user_data = json_value_init_object();
|
||||||
|
json_object_set_string(json_object(user_data), "name", buf);
|
||||||
|
json_serialize_to_file(user_data, "user_data.json");
|
||||||
|
}
|
||||||
|
name = json_object_get_string(json_object(user_data), "name");
|
||||||
|
printf("Hello, %s.", name);
|
||||||
|
json_value_free(schema);
|
||||||
|
json_value_free(user_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialization_example(void) {
|
||||||
|
JSON_Value *root_value = json_value_init_object();
|
||||||
|
JSON_Object *root_object = json_value_get_object(root_value);
|
||||||
|
char *serialized_string = NULL;
|
||||||
|
json_object_set_string(root_object, "name", "John Smith");
|
||||||
|
json_object_set_number(root_object, "age", 25);
|
||||||
|
json_object_dotset_string(root_object, "address.city", "Cupertino");
|
||||||
|
json_object_dotset_value(root_object, "contact.emails",
|
||||||
|
json_parse_string("[\"email@example.com\", \"email2@example.com\"]"));
|
||||||
|
serialized_string = json_serialize_to_string(root_value);
|
||||||
|
puts(serialized_string);
|
||||||
|
json_free_serialized_string(serialized_string);
|
||||||
|
}
|
||||||
|
0
tests/test_1_1.txt
Normal file → Executable file
0
tests/test_1_1.txt
Normal file → Executable file
0
tests/test_1_2.txt
Normal file → Executable file
0
tests/test_1_2.txt
Normal file → Executable file
0
tests/test_1_3.txt
Normal file → Executable file
0
tests/test_1_3.txt
Normal file → Executable file
0
tests/test_2.txt
Normal file → Executable file
0
tests/test_2.txt
Normal file → Executable file
0
tests/test_2_comments.txt
Normal file → Executable file
0
tests/test_2_comments.txt
Normal file → Executable file
14
tests/test_5.txt
Normal file
14
tests/test_5.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"first": "John",
|
||||||
|
"last": "Doe",
|
||||||
|
"age": 25,
|
||||||
|
"registered": true,
|
||||||
|
"interests": [ "Reading", "Mountain Biking" ],
|
||||||
|
"favorites": {
|
||||||
|
"color": "blue",
|
||||||
|
"sport": "running"
|
||||||
|
},
|
||||||
|
"utf string" : "\u006corem\u0020ipsum",
|
||||||
|
"utf-8 string": "あいうえお",
|
||||||
|
"surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user