1#![feature(box_syntax, box_patterns)]2#![feature(type_alias_impl_trait)]3#![feature(debug_non_exhaustive)]4#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]5mod ctx;6mod dynamic;7mod evaluate;8mod obj;9mod val;1011pub use ctx::*;12pub use dynamic::*;13pub use evaluate::*;14use jsonnet_parser::*;15pub use obj::*;16pub use val::*;1718rc_fn_helper!(19 Binding,20 binding,21 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val22);23rc_fn_helper!(24 LazyBinding,25 lazy_binding,26 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> LazyVal27);28rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);29rc_fn_helper!(30 FunctionDefault,31 function_default,32 dyn Fn(Context, Expr) -> Val33);3435#[cfg(test)]36pub mod tests {37 use super::{evaluate, Context, Val};38 use jsonnet_parser::*;3940 macro_rules! eval {41 ($str: expr) => {42 evaluate(Context::new(), &parse($str).unwrap())43 };44 }4546 macro_rules! eval_stdlib {47 ($str: expr) => {{48 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";49 evaluate(Context::new(), &parse(&(std + $str)).unwrap())50 }};51 }5253 macro_rules! assert_eval {54 ($str: expr) => {55 assert_eq!(56 evaluate(Context::new(), &parse($str).unwrap()),57 Val::Literal(LiteralType::True)58 )59 };60 }61 macro_rules! assert_json {62 ($str: expr, $out: expr) => {63 assert_eq!(64 format!("{}", evaluate(Context::new(), &parse($str).unwrap())),65 $out66 )67 };68 }69 macro_rules! assert_json_stdlib {70 ($str: expr, $out: expr) => {71 assert_eq!(72 format!("{}", eval_stdlib!($str)),73 $out74 )75 };76 }77 macro_rules! assert_eval_neg {78 ($str: expr) => {79 assert_eq!(80 evaluate(Context::new(), &parse($str).unwrap()),81 Val::Literal(LiteralType::False)82 )83 };84 }8586 87 #[test]88 fn equality_operator() {89 assert_eval!("2 == 2");90 assert_eval_neg!("2 != 2");91 assert_eval!("2 != 3");92 assert_eval_neg!("2 == 3");93 assert_eval!("'Hello' == 'Hello'");94 assert_eval_neg!("'Hello' != 'Hello'");95 assert_eval!("'Hello' != 'World'");96 assert_eval_neg!("'Hello' == 'World'");97 }9899 #[test]100 fn math_evaluation() {101 assert_eval!("2 + 2 * 2 == 6");102 assert_eval!("3 + (2 + 2 * 2) == 9");103 }104105 #[test]106 fn string_concat() {107 assert_eval!("'Hello' + 'World' == 'HelloWorld'");108 assert_eval!("'Hello' * 3 == 'HelloHelloHello'");109 assert_eval!("'Hello' + 'World' * 3 == 'HelloWorldWorldWorld'");110 }111112 #[test]113 fn local() {114 assert_eval!("local a = 2; local b = 3; a + b == 5");115 assert_eval!("local a = 1, b = a + 1; a + b == 3");116 assert_eval!("local a = 1; local a = 2; a == 2");117 }118119 #[test]120 fn object_lazyness() {121 assert_json!("local a = {a:error 'test'}; {}", r#"{}"#);122 }123124 #[test]125 fn object_inheritance() {126 assert_json!("{a: self.b} + {b:3}", r#"{"a":3,"b":3}"#);127 }128129 #[test]130 fn test_object() {131 assert_json!("{a:2}", r#"{"a":2}"#);132 assert_json!("{a:2+2}", r#"{"a":4}"#);133 assert_json!("{a:2}+{b:2}", r#"{"a":2,"b":2}"#);134 assert_json!("{b:3}+{b:2}", r#"{"b":2}"#);135 assert_json!("{b:3}+{b+:2}", r#"{"b":5}"#);136 assert_json!("local test='a'; {[test]:2}", r#"{"a":2}"#);137 assert_json!(138 r#"139 {140 name: "Alice",141 welcome: "Hello " + self.name + "!",142 }143 "#,144 r#"{"name":"Alice","welcome":"Hello Alice!"}"#145 );146 assert_json!(147 r#"148 {149 name: "Alice",150 welcome: "Hello " + self.name + "!",151 } + {152 name: "Bob"153 }154 "#,155 r#"{"name":"Bob","welcome":"Hello Bob!"}"#156 );157 }158159 #[test]160 fn functions() {161 assert_json!(r#"local a = function(b, c = 2) b + c; a(2)"#, "4");162 assert_json!(163 r#"local a = function(b, c = "Dear") b + c + d, d = "World"; a("Hello")"#,164 r#""HelloDearWorld""#165 );166 }167168 #[test]169 fn local_methods() {170 assert_json!(r#"local a(b, c = 2) = b + c; a(2)"#, "4");171 assert_json!(172 r#"local a(b, c = "Dear") = b + c + d, d = "World"; a("Hello")"#,173 r#""HelloDearWorld""#174 );175 }176177 #[test]178 fn object_locals() {179 assert_json!(r#"{local a = 3, b: a}"#, r#"{"b":3}"#);180 assert_json!(r#"{local a = 3, local c = a, b: c}"#, r#"{"b":3}"#);181 assert_json!(182 r#"{local a = function (b) {[b]:4}, test: a("test")}"#,183 r#"{"test":{"test":4}}"#184 );185 }186187 #[test]188 fn direct_self() {189 println!(190 "{:#?}",191 eval!(192 r#"193 {194 local me = self,195 a: 3,196 b(): me.a,197 }198 "#199 )200 );201 }202203 #[test]204 fn indirect_self() {205 206 207 eval_stdlib!(208 r#"{209 local me = self,210 a: 3,211 b: me.a,212 }.b"#213 );214 }215216 217 #[test]218 fn std_assert_ok() {219 eval_stdlib!("std.assertEqual(4.5 << 2, 16)");220 }221222 #[test]223 #[should_panic]224 fn std_assert_failure() {225 eval_stdlib!("std.assertEqual(4.5 << 2, 15)");226 }227228 #[test]229 fn string_is_string() {230 assert_eq!(231 eval_stdlib!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),232 Val::Literal(LiteralType::False)233 );234 }235236 #[test]237 fn base64_works() {238 assert_json_stdlib!(r#"std.base64("test")"#, r#""dGVzdA==""#);239 }240}