// Regression test for issue #3: objects with more than 32 properties. #include #include #include #include "big.h" using namespace big_schema; static WeaselJsonStatus parseStrided(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 int failures = 0; #define CHECK(cond) \ do { \ if (!(cond)) { \ printf("FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \ ++failures; \ } \ } while (0) static void expectReject(const std::string &json, const char *what) { RootBuilder b; WeaselJsonStatus s = parseStrided(b, json); if (s == WeaselJson_REJECT) { printf("ok reject: %s\n", what); } else { printf("FAIL expected reject (%s) got status %d for: %s\n", what, s, json.c_str()); ++failures; } } static std::string all40() { std::string json = "{"; for (int i = 0; i < 40; ++i) { if (i) json += ","; json += "\"p" + std::to_string(i) + "\":\"v" + std::to_string(i) + "\""; } json += "}"; return json; } int main() { // All 40 required fields present -> accepted, values land in right slots. { RootBuilder b; std::string json = all40(); WeaselJsonStatus s = parseStrided(b, json); CHECK(s == WeaselJson_OK); if (s == WeaselJson_OK) { Root r = b.take(); CHECK(r.p0 == "v0"); CHECK(r.p31 == "v31"); CHECK(r.p32 == "v32"); CHECK(r.p39 == "v39"); printf("ok all 40 required fields accepted\n"); } } // Missing field p32 (index 32) must be detected, not aliased to bit 0. { std::string json = all40(); // Remove the p32 entry: find its substring and erase it. std::string entry = "\"p32\":\"v32\""; size_t pos = json.find(entry); assert(pos != std::string::npos); // Remove the trailing comma before it if present, or the leading comma // after it. if (pos > 0 && json[pos - 1] == ',') { json.erase(pos - 1, entry.size() + 1); } else if (pos + entry.size() < json.size() && json[pos + entry.size()] == ',') { json.erase(pos, entry.size() + 1); } else { json.erase(pos, entry.size()); } expectReject(json, "missing required field p32 (index 32)"); } // Missing p0 still rejected. { std::string json = all40(); std::string entry = "\"p0\":\"v0\""; size_t pos = json.find(entry); assert(pos != std::string::npos); if (json[pos + entry.size()] == ',') { json.erase(pos, entry.size() + 1); } else { json.erase(pos, entry.size()); } expectReject(json, "missing required field p0"); } // Duplicate keys p0 and p32 must both be detected. { std::string json = all40(); // Insert p32 again right after the existing p32 entry. std::string entry = "\"p32\":\"v32\""; size_t pos = json.find(entry); assert(pos != std::string::npos); json.insert(pos + entry.size(), ",\"p32\":\"dup\""); expectReject(json, "duplicate key p32 (index 32)"); } // Duplicate keys p0 and p31 cover boundary bits. { std::string json = all40(); std::string entry = "\"p0\":\"v0\""; size_t pos = json.find(entry); assert(pos != std::string::npos); json.insert(pos + entry.size(), ",\"p0\":\"dup\""); expectReject(json, "duplicate key p0"); } // Duplicate p31/p32 around the 32-bit boundary. { std::string json = all40(); std::string entry = "\"p31\":\"v31\""; size_t pos = json.find(entry); assert(pos != std::string::npos); json.insert(pos + entry.size(), ",\"p31\":\"dup\""); expectReject(json, "duplicate key p31"); } if (failures == 0) { printf("\nALL TESTS PASSED\n"); return 0; } printf("\n%d FAILURE(S)\n", failures); return 1; }