Compare commits

...

3 commits

12 changed files with 333 additions and 8 deletions

View file

@ -6,6 +6,8 @@ project(
C C
) )
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_library( add_library(
${PROJECT_NAME} ${PROJECT_NAME}
json.c json.c

View file

@ -4,7 +4,7 @@
int main() int main()
{ {
auto json = json_init(stdout, INDENT_2); auto json = json_init(stdout, MINIFIED, false);
json_begin_object(&json); json_begin_object(&json);
{ {

View file

@ -27,6 +27,7 @@
clang-tools clang-tools
ctags ctags
valgrind valgrind
cdecl
]; ];
in in
{ {

7
json.c
View file

@ -4,13 +4,14 @@
#define UNREACHABLE() assert(false) #define UNREACHABLE() assert(false)
Json json_init(FILE* stream, Whitespace whitespace) Json json_init(FILE* stream, Whitespace whitespace, bool comma_separate)
{ {
return (Json){ return (Json){
.stream = stream, .stream = stream,
.whitespace = whitespace, .whitespace = whitespace,
.indent_level = 0, .indent_level = 0,
.next_punctuation = BEGINNING, .next_punctuation = BEGINNING,
.comma_separate = comma_separate,
}; };
} }
@ -169,7 +170,11 @@ void begin_value(Json* json)
/// End a JSON value. /// End a JSON value.
void end_value(Json* json) void end_value(Json* json)
{ {
if (json->indent_level > 0 || json->comma_separate) {
json->next_punctuation = COMMA; json->next_punctuation = COMMA;
} else {
json->next_punctuation = BEGINNING;
}
} }
/// Increment the indent level by one. /// Increment the indent level by one.

11
json.h
View file

@ -25,9 +25,10 @@ typedef struct Json {
Whitespace whitespace; Whitespace whitespace;
int indent_level; int indent_level;
Punctuation next_punctuation; Punctuation next_punctuation;
bool comma_separate;
} Json; } Json;
Json json_init(FILE* stream, Whitespace whitespace); Json json_init(FILE* stream, Whitespace whitespace, bool comma_separate);
void json_free(Json* json); void json_free(Json* json);
void json_begin_array(Json* json); void json_begin_array(Json* json);
@ -41,5 +42,13 @@ void json_add_double(Json* json, double value);
void json_add_bool(Json* json, bool value); void json_add_bool(Json* json, bool value);
void json_add_null(Json* json); void json_add_null(Json* json);
#define json_add_number(json, value) \
_Generic( \
(value), \
int: json_add_long((json), (long)value), \
long: json_add_long((json), value), \
float: json_add_double((json), (double)value), \
double: json_add_double((json), value))
#endif // JSON_H #endif // JSON_H

View file

@ -13,6 +13,8 @@ list(
json_tests_array json_tests_array
json_tests_object json_tests_object
json_tests_complex json_tests_complex
json_tests_comma_separated
json_tests_non_comma_separated
) )
foreach(JSON_TEST IN LISTS JSON_TESTS) foreach(JSON_TEST IN LISTS JSON_TESTS)
add_executable( add_executable(

View file

@ -15,7 +15,7 @@ void setUp()
tmp = tmpfile(); tmp = tmpfile();
TEST_ASSERT_NOT_NULL(tmp); TEST_ASSERT_NOT_NULL(tmp);
json = json_init(tmp, MINIFIED); json = json_init(tmp, MINIFIED, false);
} }
void tearDown() void tearDown()

View file

@ -0,0 +1,147 @@
#include <stdio.h>
#include <string.h>
#include <unity.h>
#include <json.h>
static FILE* tmp = nullptr;
static char buffer[256];
static Json json;
void setUp()
{
tmp = tmpfile();
TEST_ASSERT_NOT_NULL(tmp);
json = json_init(tmp, MINIFIED, true);
}
void tearDown()
{
json_free(&json);
if (tmp) {
fclose(tmp);
tmp = nullptr;
}
}
void test_json_comma_separated_string()
{
json_add_string(&json, "one");
json_add_string(&json, "two");
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("\"one\",\"two\"", buffer);
}
void test_json_comma_separated_long()
{
json_add_long(&json, 42);
json_add_long(&json, 67);
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("42,67", buffer);
}
void test_json_comma_separated_double()
{
json_add_double(&json, 3.14);
json_add_double(&json, 6.28);
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("3.14,6.28", buffer);
}
void test_json_comma_separated_bool()
{
json_add_bool(&json, true);
json_add_bool(&json, false);
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("true,false", buffer);
}
void test_json_comma_separated_null()
{
json_add_null(&json);
json_add_null(&json);
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("null,null", buffer);
}
void test_json_comma_separated_object()
{
for (int i = 0; i < 2; ++i) {
json_begin_object(&json);
{
json_add_object_field(&json, "test");
json_add_number(&json, i);
}
json_end_object(&json);
}
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("{\"test\":0},{\"test\":1}", buffer);
}
void test_json_comma_separated_array()
{
for (int i = 0; i < 2; ++i) {
json_begin_array(&json);
{
json_add_number(&json, i);
}
json_end_array(&json);
}
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("[0],[1]", buffer);
}
int main()
{
UNITY_BEGIN();
{
RUN_TEST(test_json_comma_separated_string);
RUN_TEST(test_json_comma_separated_long);
RUN_TEST(test_json_comma_separated_double);
RUN_TEST(test_json_comma_separated_bool);
RUN_TEST(test_json_comma_separated_null);
RUN_TEST(test_json_comma_separated_object);
RUN_TEST(test_json_comma_separated_array);
}
return UNITY_END();
}

View file

@ -15,7 +15,7 @@ void setUp()
tmp = tmpfile(); tmp = tmpfile();
TEST_ASSERT_NOT_NULL(tmp); TEST_ASSERT_NOT_NULL(tmp);
json = json_init(tmp, INDENT_TAB); json = json_init(tmp, INDENT_TAB, false);
} }
void tearDown() void tearDown()

View file

@ -0,0 +1,147 @@
#include <stdio.h>
#include <string.h>
#include <unity.h>
#include <json.h>
static FILE* tmp = nullptr;
static char buffer[256];
static Json json;
void setUp()
{
tmp = tmpfile();
TEST_ASSERT_NOT_NULL(tmp);
json = json_init(tmp, MINIFIED, false);
}
void tearDown()
{
json_free(&json);
if (tmp) {
fclose(tmp);
tmp = nullptr;
}
}
void test_json_non_comma_separated_string()
{
json_add_string(&json, "one");
json_add_string(&json, "two");
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("\"one\"\"two\"", buffer);
}
void test_json_non_comma_separated_long()
{
json_add_long(&json, 42);
json_add_long(&json, 67);
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("4267", buffer);
}
void test_json_non_comma_separated_double()
{
json_add_double(&json, 3.14);
json_add_double(&json, 6.28);
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("3.146.28", buffer);
}
void test_json_non_comma_separated_bool()
{
json_add_bool(&json, true);
json_add_bool(&json, false);
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("truefalse", buffer);
}
void test_json_non_comma_separated_null()
{
json_add_null(&json);
json_add_null(&json);
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("nullnull", buffer);
}
void test_json_non_comma_separated_object()
{
for (int i = 0; i < 2; ++i) {
json_begin_object(&json);
{
json_add_object_field(&json, "test");
json_add_number(&json, i);
}
json_end_object(&json);
}
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("{\"test\":0}{\"test\":1}", buffer);
}
void test_json_non_comma_separated_array()
{
for (int i = 0; i < 2; ++i) {
json_begin_array(&json);
{
json_add_number(&json, i);
}
json_end_array(&json);
}
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("[0][1]", buffer);
}
int main()
{
UNITY_BEGIN();
{
RUN_TEST(test_json_non_comma_separated_string);
RUN_TEST(test_json_non_comma_separated_long);
RUN_TEST(test_json_non_comma_separated_double);
RUN_TEST(test_json_non_comma_separated_bool);
RUN_TEST(test_json_non_comma_separated_null);
RUN_TEST(test_json_non_comma_separated_object);
RUN_TEST(test_json_non_comma_separated_array);
}
return UNITY_END();
}

View file

@ -15,7 +15,7 @@ void setUp()
tmp = tmpfile(); tmp = tmpfile();
TEST_ASSERT_NOT_NULL(tmp); TEST_ASSERT_NOT_NULL(tmp);
json = json_init(tmp, MINIFIED); json = json_init(tmp, MINIFIED, false);
} }
void tearDown() void tearDown()

View file

@ -15,7 +15,7 @@ void setUp()
tmp = tmpfile(); tmp = tmpfile();
TEST_ASSERT_NOT_NULL(tmp); TEST_ASSERT_NOT_NULL(tmp);
json = json_init(tmp, MINIFIED); json = json_init(tmp, MINIFIED, false);
} }
void tearDown() void tearDown()
@ -64,6 +64,18 @@ void test_json_add_double()
TEST_ASSERT_EQUAL_STRING("3.14", buffer); TEST_ASSERT_EQUAL_STRING("3.14", buffer);
} }
void test_json_add_number()
{
json_add_number(&json, 3.14f);
fflush(tmp);
rewind(tmp);
auto n = fread(buffer, 1, sizeof(buffer) - 1, tmp);
buffer[n] = '\0';
TEST_ASSERT_EQUAL_STRING("3.14", buffer);
}
void test_json_add_bool() void test_json_add_bool()
{ {
json_add_bool(&json, true); json_add_bool(&json, true);