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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#![cfg(test)]
extern crate test_generator;
use bumpalo::Bump;
use jsonata_rs::{ArrayFlags, JsonAta, Value};
use std::fs;
use std::path;
include!(concat!(env!("OUT_DIR"), "/generated_tests.rs"));
fn test_case(resource: &str) {
let arena = Bump::new();
let test_jsonata = JsonAta::new(
&fs::read_to_string(path::Path::new(resource)).unwrap(),
&arena,
)
.unwrap();
let test = test_jsonata.evaluate(None, None).unwrap();
let test = Value::wrap_in_array_if_needed(&arena, test, ArrayFlags::empty());
for case in test.members() {
let timelimit = &case["timelimit"];
let timelimit = if timelimit.is_integer() {
Some(timelimit.as_usize())
} else {
None
};
let depth = &case["depth"];
let depth = if depth.is_integer() {
Some(depth.as_usize())
} else {
None
};
let expr = &case["expr"];
let expr_file = &case["expr-file"];
let expr = if expr.is_string() {
expr.as_str().to_string()
} else if expr_file.is_string() {
fs::read_to_string(
path::Path::new(resource)
.parent()
.unwrap()
.join(expr_file.as_str().to_string()),
)
.unwrap()
} else {
panic!("No expression")
};
eprintln!("EXPR: {expr}");
let data = &case["data"];
let dataset = &case["dataset"];
let data = if dataset.is_string() {
let dataset = format!("tests/testsuite/datasets/{}.json", dataset.as_str());
fs::read_to_string(&dataset).unwrap()
} else if data.is_undefined() {
"".to_string()
} else {
data.serialize(false)
};
let jsonata = JsonAta::new(&expr, &arena);
match jsonata {
Ok(jsonata) => {
if case["bindings"].is_object() {
for (key, value) in case["bindings"].entries() {
jsonata.assign_var(key, value);
}
}
let data = if data.is_empty() {
None
} else {
Some(data.as_str())
};
let result = jsonata.evaluate_timeboxed(data, depth, timelimit);
match result {
Ok(result) => {
let expected_result = &case["result"];
if case["undefinedResult"] == true {
assert!(result.is_undefined());
} else if case["unordered"] == true {
// Some test cases specify that the expected array result can be unordered
// because the order is implementation dependent. To implement that here
// we do a pretty bad O(n^2) just to see if the test passes.
assert!(expected_result.is_array());
assert!(result.is_array());
for expected_member in expected_result.members() {
let mut found = false;
for member in result.members() {
if member == expected_member {
found = true;
break;
}
}
assert!(found);
}
} else if case["result_re"].is_string() {
// Ability to define a regular expression to match the result. This strategy is useful
// to validate the result of an expression that's not deterministic (like the $millis() function).
let regex_pattern =
regress::Regex::with_flags(case["result_re"].as_str().as_ref(), "")
.expect("Should have a valid regex expression");
assert!(
regex_pattern.find(&result.as_str()).is_some(),
"Value: {result:?}, did not match expected result_re",
);
} else {
eprintln!("RESULT: {}", result);
assert_eq!(expected_result, result);
}
}
Err(error) => {
eprintln!("ERROR: {}", error);
let expected_code = if !case["error"].is_undefined() {
&case["error"]["code"]
} else {
&case["code"]
};
assert_eq!(*expected_code, error.code());
}
}
}
Err(error) => {
eprintln!("{}", error);
let code = if !case["error"].is_undefined() {
&case["error"]["code"]
} else {
&case["code"]
};
assert_eq!(*code, error.code());
}
}
}
}