Files
tinygltf/tests/tester_v3_json_c.c
2026-06-01 16:11:22 +09:00

166 lines
5.3 KiB
C

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define TINYGLTF_JSON_C_IMPLEMENTATION
#include "tinygltf_json_c.h"
static uint64_t dbl_bits(double v) {
uint64_t bits;
memcpy(&bits, &v, sizeof(bits));
return bits;
}
static double dbl_from_bits(uint64_t bits) {
double v;
memcpy(&v, &bits, sizeof(v));
return v;
}
static int check_stringify(const char *json, const char *expected) {
tg3json_value v;
const char *err = NULL;
char *out;
size_t out_len = 0;
int ok = 1;
if (!tg3json_parse(json, json + strlen(json), 128, &v, &err)) {
fprintf(stderr, "parse failed for %s at %td\n", json, err ? err - json : -1);
return 0;
}
out = tg3json_stringify(&v, &out_len);
if (!out || strcmp(out, expected) != 0) {
fprintf(stderr, "stringify(%s) = %s, expected %s\n",
json, out ? out : "(null)", expected);
ok = 0;
}
if (out) TINYGLTF_JSON_FREE(out);
tg3json_value_free(&v);
return ok;
}
static int check_parse_rejects(const char *json) {
tg3json_value v;
const char *err = NULL;
if (tg3json_parse(json, json + strlen(json), 128, &v, &err)) {
fprintf(stderr, "parse unexpectedly accepted %s\n", json);
tg3json_value_free(&v);
return 0;
}
return 1;
}
static int check_roundtrip(const char *json) {
tg3json_value a;
tg3json_value b;
const char *err = NULL;
char *out;
size_t out_len = 0;
int ok = 1;
if (!tg3json_parse(json, json + strlen(json), 128, &a, &err)) return 0;
out = tg3json_stringify(&a, &out_len);
if (!out || !tg3json_parse(out, out + out_len, 128, &b, &err)) {
ok = 0;
} else if (a.type != TG3JSON_REAL ||
!((b.type == TG3JSON_REAL && dbl_bits(a.u.real) == dbl_bits(b.u.real)) ||
(b.type == TG3JSON_INT && dbl_bits(a.u.real) == dbl_bits((double)b.u.integer)))) {
fprintf(stderr, "roundtrip changed bits: %s -> %s\n", json, out);
ok = 0;
}
if (out) TINYGLTF_JSON_FREE(out);
tg3json_value_free(&a);
tg3json_value_free(&b);
return ok;
}
static int check_parse_bits(const char *json, uint64_t expected_bits) {
tg3json_value v;
const char *err = NULL;
if (!tg3json_parse(json, json + strlen(json), 128, &v, &err)) {
fprintf(stderr, "parse failed for %s at %td\n", json, err ? err - json : -1);
return 0;
}
if (v.type != TG3JSON_REAL || dbl_bits(v.u.real) != expected_bits) {
fprintf(stderr, "parse bits mismatch: %s -> 0x%llx, expected 0x%llx\n",
json, (unsigned long long)(v.type == TG3JSON_REAL ? dbl_bits(v.u.real) : 0),
(unsigned long long)expected_bits);
tg3json_value_free(&v);
return 0;
}
tg3json_value_free(&v);
return 1;
}
static int check_parse_float32(void) {
static const char json[] = "0.10000000149011612";
tg3json_parse_options opts;
tg3json_value v;
const char *err = NULL;
double expected = (double)(float)0.10000000149011612;
memset(&opts, 0, sizeof(opts));
opts.parse_float32 = 1;
if (!tg3json_parse_n_opts(json, strlen(json), &opts, &v, &err)) {
fprintf(stderr, "parse_float32 parse failed\n");
return 0;
}
if (v.type != TG3JSON_REAL || dbl_bits(v.u.real) != dbl_bits(expected)) {
fprintf(stderr, "parse_float32 did not round through float\n");
tg3json_value_free(&v);
return 0;
}
tg3json_value_free(&v);
return 1;
}
static int check_nonfinite_stringifies_to_null(void) {
tg3json_value v;
char *out;
size_t len = 0;
int ok;
tg3json_value_init_real(&v, dbl_from_bits(0x7ff0000000000000ULL));
out = tg3json_stringify(&v, &len);
ok = out && strcmp(out, "null") == 0;
if (!ok) fprintf(stderr, "inf stringify = %s\n", out ? out : "(null)");
if (out) TINYGLTF_JSON_FREE(out);
tg3json_value_free(&v);
if (!ok) return 0;
tg3json_value_init_real(&v, dbl_from_bits(0x7ff8000000000001ULL));
out = tg3json_stringify(&v, &len);
ok = out && strcmp(out, "null") == 0;
if (!ok) fprintf(stderr, "nan stringify = %s\n", out ? out : "(null)");
if (out) TINYGLTF_JSON_FREE(out);
tg3json_value_free(&v);
return ok;
}
int main(void) {
int ok = 1;
ok = check_stringify("1.0", "1") && ok;
ok = check_stringify("-1.0", "-1") && ok;
ok = check_stringify("0.1", "0.1") && ok;
ok = check_stringify("0.0001", "0.0001") && ok;
ok = check_stringify("0.00001", "1e-5") && ok;
ok = check_stringify("1000000000000000.0", "1000000000000000") && ok;
ok = check_stringify("10000000000000000.0", "1e16") && ok;
ok = check_roundtrip("1.2345678901234567") && ok;
ok = check_roundtrip("2.2250738585072014e-308") && ok;
ok = check_roundtrip("5e-324") && ok;
ok = check_roundtrip("-5e-324") && ok;
ok = check_roundtrip("9007199254740993.0") && ok;
ok = check_parse_bits("1.23456789012345678901", 0x3ff3c0ca428c59fbULL) && ok;
ok = check_parse_bits("1.234567890123456789012345678901234567890e-100",
0x2b31482fe620c5d2ULL) && ok;
ok = check_parse_bits("1.7976931348623157e308", 0x7fefffffffffffffULL) && ok;
ok = check_parse_float32() && ok;
ok = check_nonfinite_stringifies_to_null() && ok;
ok = check_parse_rejects("+1") && ok;
ok = check_parse_rejects("01") && ok;
ok = check_parse_rejects("1.") && ok;
ok = check_parse_rejects("1e") && ok;
ok = check_parse_rejects("1e400") && ok;
ok = check_parse_rejects("-1e400") && ok;
ok = check_parse_rejects("1.7976931348623159e308") && ok;
ok = check_parse_rejects("[1,]") && ok;
return ok ? 0 : 1;
}