// Regression test for issue #13: nullable root types. #include #include #include #include "nullable_array.h" #include "nullable_object.h" #include "nullable_string.h" static int failures = 0; #define CHECK(cond) \ do { \ if (!(cond)) { \ printf("FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \ ++failures; \ } \ } while (0) static WeaselJsonStatus parseStrided(nullable_object::RootBuilder &b, std::string in) { for (size_t i = 0; i < in.size(); ++i) { char c = in[i]; WeaselJsonStatus s = b.feed(&c, 1); if (s != WeaselJson_AGAIN) return s; } return b.finish(); } static WeaselJsonStatus parseStrided(nullable_string::RootBuilder &b, std::string in) { for (size_t i = 0; i < in.size(); ++i) { char c = in[i]; WeaselJsonStatus s = b.feed(&c, 1); if (s != WeaselJson_AGAIN) return s; } return b.finish(); } static WeaselJsonStatus parseStrided(nullable_array::RootBuilder &b, std::string in) { for (size_t i = 0; i < in.size(); ++i) { char c = in[i]; WeaselJsonStatus s = b.feed(&c, 1); if (s != WeaselJson_AGAIN) return s; } return b.finish(); } static void expectReject(nullable_object::RootBuilder &b, std::string in, const char *what) { WeaselJsonStatus s = parseStrided(b, in); if (s == WeaselJson_REJECT) { printf("ok reject: %s\n", what); } else { printf("FAIL expected reject (%s) got status %d for: %s\n", what, s, in.c_str()); ++failures; } } static void expectReject(nullable_array::RootBuilder &b, std::string in, const char *what) { WeaselJsonStatus s = parseStrided(b, in); if (s == WeaselJson_REJECT) { printf("ok reject: %s\n", what); } else { printf("FAIL expected reject (%s) got status %d for: %s\n", what, s, in.c_str()); ++failures; } } int main() { // ---- nullable root object: valid document ---- { nullable_object::RootBuilder b; WeaselJsonStatus s = parseStrided(b, R"({"x":"hello"})"); CHECK(s == WeaselJson_OK); if (s == WeaselJson_OK) { nullable_object::Root r = b.take(); CHECK(r.has_value()); CHECK(r->x == "hello"); printf("ok nullable root object accepts object\n"); } } // ---- nullable root object: null document ---- { nullable_object::RootBuilder b; WeaselJsonStatus s = parseStrided(b, "null"); CHECK(s == WeaselJson_OK); if (s == WeaselJson_OK) { nullable_object::Root r = b.take(); CHECK(!r.has_value()); printf("ok nullable root object accepts null\n"); } } // ---- nullable root object: schema checks still run ---- { nullable_object::RootBuilder b; expectReject(b, R"({"x":"hello","extra":1})", "unknown key in strict nullable root object"); } { nullable_object::RootBuilder b; expectReject(b, R"({})", "missing required field in nullable root object"); } // ---- nullable root string: valid value ---- { nullable_string::RootBuilder b; WeaselJsonStatus s = parseStrided(b, R"("hello")"); CHECK(s == WeaselJson_OK); if (s == WeaselJson_OK) { nullable_string::Root r = b.take(); CHECK(r.has_value()); CHECK(*r == "hello"); printf("ok nullable root string accepts string\n"); } } // ---- nullable root string: null value ---- { nullable_string::RootBuilder b; WeaselJsonStatus s = parseStrided(b, "null"); CHECK(s == WeaselJson_OK); if (s == WeaselJson_OK) { nullable_string::Root r = b.take(); CHECK(!r.has_value()); printf("ok nullable root string accepts null\n"); } } // ---- nullable root array: valid value ---- { nullable_array::RootBuilder b; WeaselJsonStatus s = parseStrided(b, "[1,2,3]"); CHECK(s == WeaselJson_OK); if (s == WeaselJson_OK) { nullable_array::Root r = b.take(); CHECK(r.has_value()); CHECK(r->size() == 3); CHECK((*r)[0] == 1 && (*r)[1] == 2 && (*r)[2] == 3); printf("ok nullable root array accepts array\n"); } } // ---- nullable root array: null value ---- { nullable_array::RootBuilder b; WeaselJsonStatus s = parseStrided(b, "null"); CHECK(s == WeaselJson_OK); if (s == WeaselJson_OK) { nullable_array::Root r = b.take(); CHECK(!r.has_value()); printf("ok nullable root array accepts null\n"); } } // ---- nullable root object: scalar values rejected ---- { nullable_object::RootBuilder b; expectReject(b, "true", "boolean where nullable object expected (root)"); } { nullable_object::RootBuilder b; expectReject(b, "123", "number where nullable object expected (root)"); } { nullable_object::RootBuilder b; expectReject(b, R"("hi")", "string where nullable object expected (root)"); } // ---- nullable root array: scalar values rejected ---- { nullable_array::RootBuilder b; expectReject(b, "true", "boolean where nullable array expected (root)"); } { nullable_array::RootBuilder b; expectReject(b, "123", "number where nullable array expected (root)"); } { nullable_array::RootBuilder b; expectReject(b, R"("hi")", "string where nullable array expected (root)"); } if (failures == 0) { printf("\nALL TESTS PASSED\n"); return 0; } printf("\n%d FAILURE(S)\n", failures); return 1; }