Repository navigation
Expand file tree
/
Copy pathsmoke.cpp
More file actions
131 lines (112 loc) · 4.7 KB
/
Copy pathsmoke.cpp
File metadata and controls
131 lines (112 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Smoke test for the new Value-based implementation.
// Verifies the foundation compiles and basic primitives work before
// the full corpus runner lands.
#include <iostream>
#include <cassert>
#include "value_io.hpp"
#include "voxgig_struct.hpp"
using namespace voxgig::structlib;
#define CHECK(expr) \
do { \
if (!(expr)) { \
std::cerr << "FAIL: " << #expr << " at " << __LINE__ << "\n"; \
ok = false; \
} \
} while (0)
int main() {
bool ok = true;
// Sentinels.
CHECK(SKIP() == SKIP());
CHECK(DELETE_V() == DELETE_V());
CHECK(SKIP() != DELETE_V());
CHECK(is_skip(SKIP()));
CHECK(is_delete(DELETE_V()));
// Predicates.
CHECK(isnode(jm({"a", 1})));
CHECK(isnode(jt({1, 2, 3})));
CHECK(!isnode(Value(1)));
CHECK(ismap(jm({})));
CHECK(islist(jt({})));
CHECK(iskey(Value("a")));
CHECK(iskey(Value(0)));
CHECK(!iskey(Value("")));
CHECK(isempty(Value::undef()));
CHECK(isempty(Value(nullptr)));
CHECK(isempty(Value("")));
CHECK(isempty(jm({})));
CHECK(isempty(jt({})));
CHECK(!isempty(Value("a")));
// typify.
CHECK(typify(Value::undef()) == T_noval);
CHECK(typify(Value(nullptr)) == (T_scalar | T_null));
CHECK(typify(Value(true)) == (T_scalar | T_boolean));
CHECK(typify(Value(int64_t(1))) == (T_scalar | T_number | T_integer));
CHECK(typify(Value(1.5)) == (T_scalar | T_number | T_decimal));
CHECK(typify(Value("a")) == (T_scalar | T_string));
CHECK(typify(jt({})) == (T_node | T_list));
CHECK(typify(jm({})) == (T_node | T_map));
// typename.
CHECK(typename_str(typify(Value("a"))) == "string");
CHECK(typename_str(typify(jm({}))) == "map");
CHECK(typename_str(typify(jt({}))) == "list");
// getprop / setprop.
Value m = jm({"a", 1, "b", 2});
CHECK(getprop(m, Value("a")) == Value(int64_t(1)));
CHECK(getprop(m, Value("missing")) == Value::undef());
CHECK(getprop(m, Value("missing"), Value("alt")) == Value("alt"));
setprop(m, Value("c"), Value(3));
CHECK(getprop(m, Value("c")) == Value(int64_t(3)));
// Reference stability: copy of m sees the mutation.
Value m2 = m;
setprop(m2, Value("d"), Value(4));
CHECK(getprop(m, Value("d")) == Value(int64_t(4)));
// Clone breaks the reference.
Value m3 = clone(m);
setprop(m3, Value("e"), Value(5));
CHECK(getprop(m, Value("e")) == Value::undef());
// keysof returns alphabetically sorted keys (matches TS canonical
// Object.keys(val).sort()).
Value ord = jm({"z", 1, "a", 2, "m", 3});
auto ks = keysof(ord);
CHECK(ks.size() == 3);
CHECK(ks[0] == "a");
CHECK(ks[1] == "m");
CHECK(ks[2] == "z");
// Sentinel survives clone.
Value sk = SKIP();
Value sk_clone = clone(sk);
CHECK(is_skip(sk_clone));
CHECK(sk == sk_clone);
// pad / stringify / pathify smoke.
CHECK(pad(Value("a"), 3, "_") == "a__");
CHECK(pad(Value("abc"), -5, "_") == "__abc");
CHECK(stringify(Value(int64_t(1))) == "1");
CHECK(stringify(Value("hi")) == "hi");
CHECK(pathify(jt({"a", "b"}), 0, 0) == "a.b");
CHECK(pathify(jt({}), 0, 0) == "<root>");
// walk identity.
Value tree = jm({"a", jm({"b", "B"})});
Value walked = walk_v(tree, [](const Value&, const Value& v, const Value&,
const std::vector<std::string>&) { return v; });
CHECK(walked == tree);
// merge.
Value merged = merge_v(jt({jm({"a", 1, "b", 2}), jm({"b", 3, "c", 4})}));
CHECK(getprop(merged, Value("a")) == Value(int64_t(1)));
CHECK(getprop(merged, Value("b")) == Value(int64_t(3)));
CHECK(getprop(merged, Value("c")) == Value(int64_t(4)));
// parse_json: malformed input, or anything after the value, gives undef.
for (const char* bad : {"{\"id\": \"x01\", \"title\": ", "[1, 2] trailing", "{} {}", "[1, 2",
"[1 2]", "[1,]", "{\"a\" 1}", "{\"a\": 1,}", "{1: 2}", "nul", "01", "1.",
"-", "1e+", "\"open", "\"a\\x\"", "\"tab\there\""}) {
if (!parse_json(bad).is_undef()) {
std::cerr << "FAIL: parse_json accepted " << bad << "\n";
ok = false;
}
}
Value whole = parse_json(" {\"a\": [0, -2.5e3, true, null, \"\\u00e9\"]}\n");
Value items = getprop(whole, Value("a"));
CHECK(getprop(items, Value(1)) == Value(-2500.0));
CHECK(getprop(items, Value(4)) == Value("\xc3\xa9"));
std::cout << (ok ? "smoke OK" : "smoke FAILED") << "\n";
return ok ? 0 : 1;
}