mirror of
https://github.com/mauiaaron/apple2.git
synced 2025-02-23 03:29:03 +00:00
Add JSON serialization and tests
- Encourage use of opaque reference rather than internal struct
This commit is contained in:
parent
b87273e742
commit
01b25527fe
4
externals/jsmn/jsmn.h
vendored
4
externals/jsmn/jsmn.h
vendored
@ -4,8 +4,8 @@
|
||||
#include <stddef.h>
|
||||
|
||||
// APPLE2IX : define these ...
|
||||
#define JSMN_PARENT_LINKS
|
||||
#define JSMN_STRICT
|
||||
#define JSMN_PARENT_LINKS 1
|
||||
#define JSMN_STRICT 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
253
src/json_parse.c
253
src/json_parse.c
@ -5,21 +5,174 @@
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
* Copyright 2015-2016 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#include "json_parse.h"
|
||||
#include "common.h"
|
||||
#include "json_parse_private.h"
|
||||
|
||||
#define JSON_LENGTH 16
|
||||
#define DEFAULT_NUMTOK 16
|
||||
#define MAX_INDENT 16
|
||||
|
||||
static int _json_createFromString(const char *jsonString, INOUT JSON_s *parsedData, ssize_t jsonLen) {
|
||||
|
||||
static bool _json_write(const char *jsonString, size_t buflen, int fd) {
|
||||
ssize_t idx = 0;
|
||||
size_t chunk = buflen;
|
||||
do {
|
||||
ssize_t outlen = 0;
|
||||
TEMP_FAILURE_RETRY(outlen = write(fd, jsonString+idx, chunk));
|
||||
if (outlen <= 0) {
|
||||
break;
|
||||
}
|
||||
idx += outlen;
|
||||
chunk -= outlen;
|
||||
} while (idx < buflen);
|
||||
return idx == buflen;
|
||||
}
|
||||
|
||||
// recursive
|
||||
static bool _json_prettyPrint(JSON_s *parsedData, int start, int end, const unsigned int indent, int fd) {
|
||||
|
||||
char indentBuf[MAX_INDENT+1];
|
||||
indentBuf[MAX_INDENT] = '\0';
|
||||
|
||||
bool success = false;
|
||||
do {
|
||||
if (indent > MAX_INDENT) {
|
||||
break;
|
||||
}
|
||||
memset(indentBuf, '\t', indent);
|
||||
|
||||
jsmntok_t parent = { -1 };
|
||||
int idx = start;
|
||||
if (idx < end) {
|
||||
jsmntok_t tok = parsedData->jsonTokens[idx];
|
||||
if (tok.parent >= 0) {
|
||||
parent = parsedData->jsonTokens[tok.parent];
|
||||
}
|
||||
}
|
||||
|
||||
bool isKey = true;
|
||||
|
||||
while (idx < end) {
|
||||
|
||||
jsmntok_t tok = parsedData->jsonTokens[idx];
|
||||
bool isFirst = (idx == start);
|
||||
|
||||
// print finishing ", \n" stuff ...
|
||||
if (parent.type == JSMN_OBJECT) {
|
||||
if (!isKey) {
|
||||
if (!_json_write(" : ", 3, fd)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!isFirst) {
|
||||
if (!_json_write(",\n", 2, fd)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_json_write(indentBuf, indent, fd)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (parent.type == JSMN_ARRAY) {
|
||||
if (!isFirst) {
|
||||
if (!_json_write(", ", 2, fd)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jsmntype_t type = parsedData->jsonTokens[idx].type;
|
||||
|
||||
if (type == JSMN_PRIMITIVE) {
|
||||
char lastChar = parsedData->jsonString[tok.end];
|
||||
parsedData->jsonString[tok.end] = '\0';
|
||||
if (!_json_write(&parsedData->jsonString[tok.start], tok.end-tok.start, fd)) {
|
||||
break;
|
||||
}
|
||||
parsedData->jsonString[tok.end] = lastChar;
|
||||
++idx;
|
||||
} else if (type == JSMN_STRING) {
|
||||
char lastChar = parsedData->jsonString[tok.end];
|
||||
parsedData->jsonString[tok.end] = '\0';
|
||||
if (!_json_write("\"", 1, fd)) {
|
||||
break;
|
||||
}
|
||||
if (!_json_write(&parsedData->jsonString[tok.start], tok.end-tok.start, fd)) {
|
||||
break;
|
||||
}
|
||||
if (!_json_write("\"", 1, fd)) {
|
||||
break;
|
||||
}
|
||||
parsedData->jsonString[tok.end] = lastChar;
|
||||
++idx;
|
||||
} else if (type == JSMN_OBJECT) {
|
||||
if (!_json_write("{\n", 2, fd)) {
|
||||
break;
|
||||
}
|
||||
if (!_json_prettyPrint(parsedData, idx+1, idx+tok.skip, indent+1, fd)) {
|
||||
break;
|
||||
}
|
||||
if (!_json_write(indentBuf, indent, fd)) {
|
||||
break;
|
||||
}
|
||||
if (!_json_write("}", 1, fd)) {
|
||||
break;
|
||||
}
|
||||
idx += tok.skip;
|
||||
} else if (type == JSMN_ARRAY) {
|
||||
if (!_json_write("[ ", 2, fd)) {
|
||||
break;
|
||||
}
|
||||
if (!_json_prettyPrint(parsedData, idx+1, idx+tok.skip, indent+1, fd)) {
|
||||
break;
|
||||
}
|
||||
if (!_json_write(" ]", 2, fd)) {
|
||||
break;
|
||||
}
|
||||
idx += tok.skip;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
isKey = !isKey;
|
||||
}
|
||||
|
||||
if (idx != end) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (parent.type != JSMN_ARRAY) {
|
||||
if (!_json_write("\n", 1, fd)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
} while (0);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static int _json_createFromString(const char *jsonString, INOUT JSON_ref *jsonRef, ssize_t jsonLen) {
|
||||
|
||||
jsmnerr_t errCount = JSMN_ERROR_NOMEM;
|
||||
do {
|
||||
jsmn_parser parser = { 0 };
|
||||
|
||||
if (!jsonRef) {
|
||||
break;
|
||||
}
|
||||
|
||||
JSON_s *parsedData = MALLOC(sizeof(*parsedData));
|
||||
if (!parsedData) {
|
||||
break;
|
||||
}
|
||||
*jsonRef = parsedData;
|
||||
|
||||
if (!parsedData) {
|
||||
break;
|
||||
}
|
||||
@ -73,38 +226,29 @@ static int _json_createFromString(const char *jsonString, INOUT JSON_s *parsedDa
|
||||
}
|
||||
|
||||
parsedData->numTokens = errCount;
|
||||
parsedData->jsonLen = jsonLen;
|
||||
|
||||
} while (0);
|
||||
|
||||
if (errCount < 0) {
|
||||
if (parsedData) {
|
||||
json_destroy(parsedData);
|
||||
if (*jsonRef) {
|
||||
json_destroy(jsonRef);
|
||||
}
|
||||
}
|
||||
|
||||
return errCount;
|
||||
}
|
||||
|
||||
int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData) {
|
||||
int json_createFromFD(int fd, INOUT JSON_ref *jsonRef) {
|
||||
|
||||
int fd = -1;
|
||||
ssize_t jsonIdx = 0;
|
||||
ssize_t jsonLen = 0;
|
||||
|
||||
char *jsonString = NULL;
|
||||
jsmnerr_t errCount = JSMN_ERROR_NOMEM;
|
||||
|
||||
do {
|
||||
if (!filePath) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parsedData) {
|
||||
break;
|
||||
}
|
||||
|
||||
TEMP_FAILURE_RETRY(fd = open(filePath, O_RDONLY));
|
||||
if (fd < 0) {
|
||||
ERRLOG("Error opening file : %s", strerror(errno));
|
||||
if (!jsonRef) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -136,7 +280,6 @@ int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData) {
|
||||
jsonString = newString;
|
||||
}
|
||||
}
|
||||
|
||||
} while (bytesRead);
|
||||
|
||||
if (bytesRead < 0) {
|
||||
@ -144,13 +287,37 @@ int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData) {
|
||||
}
|
||||
|
||||
jsonLen = jsonIdx;
|
||||
TEMP_FAILURE_RETRY(close(fd));
|
||||
fd = -1;
|
||||
|
||||
// now parse the string
|
||||
jsmnerr_t errCount = _json_createFromString(jsonString, parsedData, jsonLen);
|
||||
errCount = _json_createFromString(jsonString, jsonRef, jsonLen);
|
||||
|
||||
} while (0);
|
||||
|
||||
if (jsonString) {
|
||||
FREE(jsonString);
|
||||
}
|
||||
|
||||
return errCount;
|
||||
}
|
||||
|
||||
int json_createFromFile(const char *filePath, INOUT JSON_ref *jsonRef) {
|
||||
|
||||
int fd = -1;
|
||||
jsmnerr_t errCount = JSMN_ERROR_NOMEM;
|
||||
do {
|
||||
if (!filePath) {
|
||||
break;
|
||||
}
|
||||
if (!jsonRef) {
|
||||
break;
|
||||
}
|
||||
|
||||
TEMP_FAILURE_RETRY(fd = open(filePath, O_RDONLY));
|
||||
if (fd < 0) {
|
||||
ERRLOG("Error opening file : %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
errCount = json_createFromFD(fd, jsonRef);
|
||||
|
||||
} while (0);
|
||||
|
||||
@ -159,15 +326,11 @@ int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData) {
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
if (jsonString) {
|
||||
FREE(jsonString);
|
||||
}
|
||||
|
||||
return JSMN_ERROR_NOMEM;
|
||||
return errCount;
|
||||
}
|
||||
|
||||
int json_createFromString(const char *jsonString, INOUT JSON_s *parsedData) {
|
||||
return _json_createFromString(jsonString, parsedData, strlen(jsonString));
|
||||
int json_createFromString(const char *jsonString, INOUT JSON_ref *jsonRef) {
|
||||
return _json_createFromString(jsonString, jsonRef, strlen(jsonString));
|
||||
}
|
||||
|
||||
static bool _json_mapGetStringValue(const JSON_s *map, const char *key, INOUT char **val, INOUT int *len) {
|
||||
@ -236,7 +399,8 @@ static bool _json_mapGetStringValue(const JSON_s *map, const char *key, INOUT ch
|
||||
return foundMatch;
|
||||
}
|
||||
|
||||
bool json_mapCopyStringValue(const JSON_s *map, const char *key, INOUT char **val) {
|
||||
bool json_mapCopyStringValue(const JSON_ref jsonRef, const char *key, INOUT char **val) {
|
||||
JSON_s *map = (JSON_s *)jsonRef;
|
||||
int len = 0;
|
||||
bool foundMatch = _json_mapGetStringValue(map, key, val, &len);
|
||||
if (foundMatch) {
|
||||
@ -245,7 +409,8 @@ bool json_mapCopyStringValue(const JSON_s *map, const char *key, INOUT char **va
|
||||
return foundMatch;
|
||||
}
|
||||
|
||||
bool json_mapParseLongValue(const JSON_s *map, const char *key, INOUT long *val, const long base) {
|
||||
bool json_mapParseLongValue(const JSON_ref jsonRef, const char *key, INOUT long *val, const long base) {
|
||||
JSON_s *map = (JSON_s *)jsonRef;
|
||||
bool foundMatch = false;
|
||||
|
||||
do {
|
||||
@ -267,7 +432,8 @@ bool json_mapParseLongValue(const JSON_s *map, const char *key, INOUT long *val,
|
||||
return foundMatch;
|
||||
}
|
||||
|
||||
bool json_mapParseFloatValue(const JSON_s *map, const char *key, INOUT float *val) {
|
||||
bool json_mapParseFloatValue(const JSON_ref jsonRef, const char *key, INOUT float *val) {
|
||||
JSON_s *map = (JSON_s *)jsonRef;
|
||||
bool foundMatch = false;
|
||||
|
||||
do {
|
||||
@ -289,8 +455,23 @@ bool json_mapParseFloatValue(const JSON_s *map, const char *key, INOUT float *va
|
||||
return foundMatch;
|
||||
}
|
||||
|
||||
void json_destroy(JSON_s *parsedData) {
|
||||
FREE(parsedData->jsonString);
|
||||
FREE(parsedData->jsonTokens);
|
||||
bool json_serialize(JSON_ref jsonRef, int fd, bool pretty) {
|
||||
JSON_s *parsedData = (JSON_s *)jsonRef;
|
||||
if (pretty) {
|
||||
return _json_prettyPrint(parsedData, /*start:*/0, /*end:*/parsedData->numTokens, /*indent:*/0, fd);
|
||||
} else {
|
||||
return _json_write(parsedData->jsonString, strlen(parsedData->jsonString), fd);
|
||||
}
|
||||
}
|
||||
|
||||
void json_destroy(JSON_ref *jsonRef) {
|
||||
if (!jsonRef) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSON_s *parsedData = (JSON_s *)*jsonRef;
|
||||
FREE(parsedData->jsonString);
|
||||
FREE(parsedData->jsonTokens);
|
||||
FREE(*jsonRef);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
* Copyright 2015-2016 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
@ -15,39 +15,43 @@
|
||||
#include "common.h"
|
||||
#include "../externals/jsmn/jsmn.h"
|
||||
|
||||
typedef struct JSON_s {
|
||||
char *jsonString;
|
||||
int numTokens;
|
||||
jsmntok_t *jsonTokens;
|
||||
} JSON_s;
|
||||
// opaque type
|
||||
typedef const struct JSON_s *JSON_ref;
|
||||
|
||||
// parses string into tokens. returns positive token count or negative jsmnerr_t error code.
|
||||
int json_createFromString(const char *jsonString, INOUT JSON_s *parsedData);
|
||||
int json_createFromString(const char *jsonString, INOUT JSON_ref *jsonRef);
|
||||
|
||||
// parses file into string and tokens. returns positive token count or negative jsmnerr_t error code.
|
||||
int json_createFromFile(const char *filePath, INOUT JSON_s *parsedData);
|
||||
int json_createFromFile(const char *filePath, INOUT JSON_ref *jsonRef);
|
||||
|
||||
// parses FD into string and tokens. returns positive token count or negative jsmnerr_t error code.
|
||||
int json_createFromFD(int fd, INOUT JSON_ref *jsonRef);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// map functions
|
||||
|
||||
// get string value for key in map JSON, returns true upon success and strdup()'d value in *val
|
||||
bool json_mapCopyStringValue(const JSON_s *map, const char *key, INOUT char **val);
|
||||
bool json_mapCopyStringValue(const JSON_ref map, const char *key, INOUT char **val);
|
||||
|
||||
// get long value for key in map JSON, returns true upon success
|
||||
bool json_mapParseLongValue(const JSON_s *dict, const char *key, INOUT long *val, const long base);
|
||||
bool json_mapParseLongValue(const JSON_ref map, const char *key, INOUT long *val, const long base);
|
||||
|
||||
// get float value for key in map JSON, returns true upon success
|
||||
bool json_mapParseFloatValue(const JSON_s *dict, const char *key, INOUT float *val);
|
||||
bool json_mapParseFloatValue(const JSON_ref map, const char *key, INOUT float *val);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// array functions
|
||||
|
||||
//bool json_arrayCopyStringValueAtIndex(const JSON_s *array, unsigned long index, INOUT const char **val);
|
||||
//bool json_arrayParseLongValueAtIndex(const JSON_s *array, unsigned long index, INOUT const long *val);
|
||||
//bool json_arrayParseFloatValueAtIndex(const JSON_s *array, unsigned long index, INOUT const float *val);
|
||||
//bool json_arrayCopyStringValueAtIndex(const JSON_ref array, unsigned long index, INOUT const char **val);
|
||||
//bool json_arrayParseLongValueAtIndex(const JSON_ref array, unsigned long index, INOUT const long *val, const long base);
|
||||
//bool json_arrayParseFloatValueAtIndex(const JSON_ref array, unsigned long index, INOUT const float *val);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// serialization
|
||||
bool json_serialize(JSON_ref json, int fd, bool pretty);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// destroys internal allocated memory (if any)
|
||||
void json_destroy(JSON_s *parsedData);
|
||||
void json_destroy(JSON_ref *jsonRef);
|
||||
|
||||
#endif
|
||||
|
18
src/json_parse_private.h
Normal file
18
src/json_parse_private.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2015-2016 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct JSON_s {
|
||||
size_t jsonLen;
|
||||
char *jsonString;
|
||||
int numTokens;
|
||||
jsmntok_t *jsonTokens;
|
||||
} JSON_s;
|
||||
|
@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "testcommon.h"
|
||||
#include "json_parse_private.h"
|
||||
|
||||
static bool test_thread_running = false;
|
||||
|
||||
@ -49,12 +50,8 @@ static const char *get_default_preferences(void) {
|
||||
;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// JSON/prefs tests ...
|
||||
|
||||
TEST test_json_map_1() {
|
||||
|
||||
const char *testMapStr0 =
|
||||
static const char *get_sample_json_1(void) {
|
||||
return
|
||||
" { "
|
||||
" \"key0\" : \"a value zero\", "
|
||||
" \"key1\" : \" \", "
|
||||
@ -82,94 +79,258 @@ TEST test_json_map_1() {
|
||||
" \"floatKey3\" : -3.1e2 "
|
||||
" } "
|
||||
;
|
||||
}
|
||||
|
||||
JSON_s parsedData = { 0 };
|
||||
int tokCount = json_createFromString(testMapStr0, &parsedData);
|
||||
if (tokCount < 0) {
|
||||
return 1;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// JSON/prefs tests ...
|
||||
|
||||
TEST test_json_map_0(JSON_ref parsedData) {
|
||||
|
||||
long lVal;
|
||||
float fVal;
|
||||
char *val;
|
||||
|
||||
json_mapParseLongValue(&parsedData, "intKey2", &lVal, 10);
|
||||
json_mapParseLongValue(parsedData, "intKey2", &lVal, 10);
|
||||
ASSERT(lVal == 0);
|
||||
|
||||
json_mapCopyStringValue(&parsedData, "key0", &val);
|
||||
json_mapCopyStringValue(parsedData, "key0", &val);
|
||||
ASSERT(strcmp(val, "a value zero") == 0);
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(&parsedData, "key1", &val);
|
||||
json_mapCopyStringValue(parsedData, "key1", &val);
|
||||
ASSERT(strcmp(val, " \t ") == 0);
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(&parsedData, "key2", &val);
|
||||
json_mapCopyStringValue(parsedData, "key2", &val);
|
||||
ASSERT(strcmp(val, "{ \t \n}") == 0);
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(&parsedData, "key3", &val);
|
||||
json_mapCopyStringValue(parsedData, "key3", &val);
|
||||
ASSERT(strcmp(val, "{ \t \n \"subkey0\" : \"subval0\", \"subkey1\" : { \"moar\" : \"recursion\" } , \"subkey2\" : \"line0 \n \tline1 \tline2\" \n}") == 0);
|
||||
{
|
||||
JSON_s parsedSubData = { 0 };
|
||||
do {
|
||||
JSON_ref parsedSubData = NULL;
|
||||
int tokSubCount = json_createFromString(val, &parsedSubData);
|
||||
if (tokSubCount < 0) {
|
||||
return 1;
|
||||
}
|
||||
ASSERT(tokSubCount > 0);
|
||||
|
||||
char *subval;
|
||||
json_mapCopyStringValue(&parsedSubData, "subkey0", &subval);
|
||||
json_mapCopyStringValue(parsedSubData, "subkey0", &subval);
|
||||
ASSERT(strcmp(subval, "subval0") == 0);
|
||||
FREE(subval);
|
||||
|
||||
json_mapCopyStringValue(&parsedSubData, "subkey1", &subval);
|
||||
json_mapCopyStringValue(parsedSubData, "subkey1", &subval);
|
||||
ASSERT(strcmp(subval, "{ \"moar\" : \"recursion\" }") == 0);
|
||||
FREE(subval);
|
||||
|
||||
json_mapCopyStringValue(&parsedSubData, "subkey2", &subval);
|
||||
json_mapCopyStringValue(parsedSubData, "subkey2", &subval);
|
||||
ASSERT(strcmp(subval, "line0 \n \tline1 \tline2") == 0);
|
||||
FREE(subval);
|
||||
}
|
||||
|
||||
json_destroy(&parsedSubData);
|
||||
} while (0);
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(&parsedData, "key4", &val);
|
||||
json_mapCopyStringValue(parsedData, "key4", &val);
|
||||
ASSERT(strcmp(val, "[ \"Q\", \"W\", \"E\", \"R\", \"T\", \"Y\", \"U\", \"I\", \"O\", \"P\", { \"x\" : [ 22, 4, \"ab\" ] } ]") == 0);
|
||||
// TODO : subarray checks
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(&parsedData, "key5", &val);
|
||||
json_mapCopyStringValue(parsedData, "key5", &val);
|
||||
ASSERT(strcmp(val, "") == 0);
|
||||
FREE(val);
|
||||
|
||||
json_mapParseLongValue(&parsedData, "intKey0", &lVal, 10);
|
||||
json_mapParseLongValue(parsedData, "intKey0", &lVal, 10);
|
||||
ASSERT(lVal == 42);
|
||||
|
||||
json_mapParseLongValue(&parsedData, "intKey1", &lVal, 10);
|
||||
json_mapParseLongValue(parsedData, "intKey1", &lVal, 10);
|
||||
ASSERT(lVal == -101);
|
||||
|
||||
json_mapParseLongValue(&parsedData, "intKey3", &lVal, 16);
|
||||
json_mapParseLongValue(parsedData, "intKey3", &lVal, 16);
|
||||
ASSERT(lVal == 0x2400);
|
||||
|
||||
json_mapParseLongValue(&parsedData, "intKey4", &lVal, 2);
|
||||
json_mapParseLongValue(parsedData, "intKey4", &lVal, 2);
|
||||
ASSERT(lVal == 191);
|
||||
|
||||
json_mapParseLongValue(&parsedData, "intKey4", &lVal, 10);
|
||||
json_mapParseLongValue(parsedData, "intKey4", &lVal, 10);
|
||||
ASSERT(lVal == 10111111);
|
||||
|
||||
json_mapParseFloatValue(&parsedData, "floatKey0", &fVal);
|
||||
json_mapParseFloatValue(parsedData, "floatKey0", &fVal);
|
||||
ASSERT(fVal == 0.f);
|
||||
|
||||
json_mapParseFloatValue(&parsedData, "floatKey1", &fVal);
|
||||
json_mapParseFloatValue(parsedData, "floatKey1", &fVal);
|
||||
ASSERT(fVal == -.0001220703125);
|
||||
|
||||
json_mapParseFloatValue(&parsedData, "floatKey2", &fVal);
|
||||
json_mapParseFloatValue(parsedData, "floatKey2", &fVal);
|
||||
ASSERT((long)(fVal*10000000) == 31415928);
|
||||
|
||||
json_mapParseFloatValue(&parsedData, "floatKey3", &fVal);
|
||||
json_mapParseFloatValue(parsedData, "floatKey3", &fVal);
|
||||
ASSERT((long)fVal == -310);
|
||||
|
||||
json_destroy(&parsedData);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST test_json_map_1() {
|
||||
|
||||
const char *testMapStr0 = get_sample_json_1();
|
||||
|
||||
JSON_ref parsedData = NULL;
|
||||
int tokCount = json_createFromString(testMapStr0, &parsedData);
|
||||
ASSERT(tokCount > 0);
|
||||
|
||||
test_json_map_0(parsedData);
|
||||
|
||||
json_destroy(&parsedData);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST test_json_serialization() {
|
||||
|
||||
const char *testMapStr0 = get_sample_json_1();
|
||||
|
||||
JSON_ref parsedData = NULL;
|
||||
int tokCount = json_createFromString(testMapStr0, &parsedData);
|
||||
ASSERT(tokCount > 0);
|
||||
|
||||
char *str = STRDUP("/tmp/json-XXXXXX");
|
||||
int fd = mkstemp(str);
|
||||
ASSERT(fd > 0);
|
||||
FREE(str);
|
||||
|
||||
json_serialize(parsedData, fd, /*pretty:*/false);
|
||||
json_destroy(&parsedData);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
json_createFromFD(fd, &parsedData);
|
||||
|
||||
test_json_map_0(parsedData);
|
||||
|
||||
TEMP_FAILURE_RETRY(close(fd));
|
||||
|
||||
json_destroy(&parsedData);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST test_json_serialization_pretty() {
|
||||
|
||||
const char *testMapStr0 = get_sample_json_1();
|
||||
|
||||
JSON_ref parsedData = NULL;
|
||||
int tokCount = json_createFromString(testMapStr0, &parsedData);
|
||||
ASSERT(tokCount > 0);
|
||||
|
||||
char *str = STRDUP("/tmp/json-pretty-XXXXXX");
|
||||
int fd = mkstemp(str);
|
||||
ASSERT(fd > 0);
|
||||
FREE(str);
|
||||
|
||||
json_serialize(parsedData, fd, /*pretty:*/true);
|
||||
json_destroy(&parsedData);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
json_createFromFD(fd, &parsedData);
|
||||
|
||||
do {
|
||||
long lVal;
|
||||
float fVal;
|
||||
char *val;
|
||||
|
||||
json_mapParseLongValue(parsedData, "intKey2", &lVal, 10);
|
||||
ASSERT(lVal == 0);
|
||||
|
||||
json_mapCopyStringValue(parsedData, "key0", &val);
|
||||
ASSERT(strcmp(val, "a value zero") == 0);
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(parsedData, "key1", &val);
|
||||
ASSERT(strcmp(val, " \t ") == 0);
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(parsedData, "key2", &val);
|
||||
do {
|
||||
JSON_ref parsedSubData = NULL;
|
||||
int tokSubCount = json_createFromString(val, &parsedSubData);
|
||||
ASSERT(tokSubCount == 1);
|
||||
ASSERT(((JSON_s *)parsedSubData)->jsonTokens[0].type == JSMN_OBJECT);
|
||||
json_destroy(&parsedSubData);
|
||||
} while (0);
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(parsedData, "key3", &val);
|
||||
do {
|
||||
JSON_ref parsedSubData = NULL;
|
||||
int tokSubCount = json_createFromString(val, &parsedSubData);
|
||||
ASSERT(tokSubCount == 9);
|
||||
|
||||
char *subval;
|
||||
json_mapCopyStringValue(parsedSubData, "subkey0", &subval);
|
||||
ASSERT(strcmp(subval, "subval0") == 0);
|
||||
FREE(subval);
|
||||
|
||||
json_mapCopyStringValue(parsedSubData, "subkey1", &subval);
|
||||
do {
|
||||
JSON_ref parsedSubSubData = NULL;
|
||||
int tokSubSubCount = json_createFromString(subval, &parsedSubSubData);
|
||||
ASSERT(tokSubSubCount == 3);
|
||||
|
||||
char *subsubval;
|
||||
json_mapCopyStringValue(parsedSubSubData, "moar", &subsubval);
|
||||
ASSERT(strcmp(subsubval, "recursion") == 0);
|
||||
FREE(subsubval);
|
||||
|
||||
json_destroy(&parsedSubSubData);
|
||||
} while (0);
|
||||
FREE(subval);
|
||||
|
||||
json_mapCopyStringValue(parsedSubData, "subkey2", &subval);
|
||||
ASSERT(strcmp(subval, "line0 \n \tline1 \tline2") == 0);
|
||||
FREE(subval);
|
||||
|
||||
json_destroy(&parsedSubData);
|
||||
} while (0);
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(parsedData, "key4", &val);
|
||||
do {
|
||||
JSON_ref parsedSubData = NULL;
|
||||
int tokSubCount = json_createFromString(val, &parsedSubData);
|
||||
ASSERT(tokSubCount == 17);
|
||||
// TODO : subarray checks
|
||||
json_destroy(&parsedSubData);
|
||||
} while (0);
|
||||
FREE(val);
|
||||
|
||||
json_mapCopyStringValue(parsedData, "key5", &val);
|
||||
ASSERT(strcmp(val, "") == 0);
|
||||
FREE(val);
|
||||
|
||||
json_mapParseLongValue(parsedData, "intKey0", &lVal, 10);
|
||||
ASSERT(lVal == 42);
|
||||
|
||||
json_mapParseLongValue(parsedData, "intKey1", &lVal, 10);
|
||||
ASSERT(lVal == -101);
|
||||
|
||||
json_mapParseLongValue(parsedData, "intKey3", &lVal, 16);
|
||||
ASSERT(lVal == 0x2400);
|
||||
|
||||
json_mapParseLongValue(parsedData, "intKey4", &lVal, 2);
|
||||
ASSERT(lVal == 191);
|
||||
|
||||
json_mapParseLongValue(parsedData, "intKey4", &lVal, 10);
|
||||
ASSERT(lVal == 10111111);
|
||||
|
||||
json_mapParseFloatValue(parsedData, "floatKey0", &fVal);
|
||||
ASSERT(fVal == 0.f);
|
||||
|
||||
json_mapParseFloatValue(parsedData, "floatKey1", &fVal);
|
||||
ASSERT(fVal == -.0001220703125);
|
||||
|
||||
json_mapParseFloatValue(parsedData, "floatKey2", &fVal);
|
||||
ASSERT((long)(fVal*10000000) == 31415928);
|
||||
|
||||
json_mapParseFloatValue(parsedData, "floatKey3", &fVal);
|
||||
ASSERT((long)fVal == -310);
|
||||
} while (0);
|
||||
|
||||
TEMP_FAILURE_RETRY(close(fd));
|
||||
|
||||
json_destroy(&parsedData);
|
||||
PASS();
|
||||
}
|
||||
|
||||
@ -194,6 +355,9 @@ GREATEST_SUITE(test_suite_prefs) {
|
||||
|
||||
RUN_TESTp(test_json_map_1);
|
||||
|
||||
RUN_TESTp(test_json_serialization);
|
||||
RUN_TESTp(test_json_serialization_pretty);
|
||||
|
||||
// --------------------------------
|
||||
pthread_mutex_unlock(&interface_mutex);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "video/glhudmodel.h"
|
||||
#include "video/glnode.h"
|
||||
#include "json_parse_private.h"
|
||||
|
||||
#if !INTERFACE_TOUCH
|
||||
#error this is a touch interface module, possibly you mean to not compile this at all?
|
||||
@ -623,7 +624,7 @@ static void gltouchkbd_reshape(int w, int h, bool landscape) {
|
||||
}
|
||||
|
||||
static void gltouchkbd_setData(const char *jsonData) {
|
||||
JSON_s parsedData = { 0 };
|
||||
JSON_ref parsedData = NULL;
|
||||
int tokCount = json_createFromString(jsonData, &parsedData);
|
||||
|
||||
do {
|
||||
@ -631,8 +632,8 @@ static void gltouchkbd_setData(const char *jsonData) {
|
||||
break;
|
||||
}
|
||||
|
||||
json_mapParseFloatValue(&parsedData, PREF_PORTRAIT_HEIGHT_SCALE, &kbd.portraitHeightScale);
|
||||
json_mapParseFloatValue(&parsedData, PREF_PORTRAIT_POSITION_SCALE, &kbd.portraitPositionScale);
|
||||
json_mapParseFloatValue(parsedData, PREF_PORTRAIT_HEIGHT_SCALE, &kbd.portraitHeightScale);
|
||||
json_mapParseFloatValue(parsedData, PREF_PORTRAIT_POSITION_SCALE, &kbd.portraitPositionScale);
|
||||
|
||||
gltouchkbd_reshape(touchport.rawWidth, touchport.rawHeight, touchport.isLandscape);
|
||||
} while (0);
|
||||
@ -776,8 +777,9 @@ static void gltouchkbd_endCalibration(void) {
|
||||
}
|
||||
|
||||
static void gltouchkbd_loadAltKbd(const char *kbdPath) {
|
||||
JSON_s parsedData = { 0 };
|
||||
int tokCount = json_createFromFile(kbdPath, &parsedData);
|
||||
JSON_ref jsonRef = NULL;
|
||||
int tokCount = json_createFromFile(kbdPath, &jsonRef);
|
||||
JSON_s parsedData = (JSON_s)parsedData;
|
||||
|
||||
do {
|
||||
if (tokCount < 0) {
|
||||
|
@ -425,7 +425,7 @@ static void glvideo_reshape(int w, int h, bool landscape) {
|
||||
|
||||
#if INTERFACE_TOUCH
|
||||
static void glvideo_setData(const char *jsonData) {
|
||||
JSON_s parsedData = { 0 };
|
||||
JSON_ref parsedData = NULL;
|
||||
int tokCount = json_createFromString(jsonData, &parsedData);
|
||||
|
||||
do {
|
||||
@ -433,7 +433,7 @@ static void glvideo_setData(const char *jsonData) {
|
||||
break;
|
||||
}
|
||||
|
||||
json_mapParseFloatValue(&parsedData, PREF_PORTRAIT_POSITION_SCALE, &portraitPositionScale);
|
||||
json_mapParseFloatValue(parsedData, PREF_PORTRAIT_POSITION_SCALE, &portraitPositionScale);
|
||||
|
||||
glvideo_reshape(rawWidth, rawHeight, isLandscape);
|
||||
} while (0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user