1#![feature(box_syntax, box_patterns)]2#![feature(type_alias_impl_trait)]3#![feature(debug_non_exhaustive)]45mod binding;6mod ctx;7mod dynamic;8mod evaluate;9mod obj;10mod val;1112pub use binding::*;13pub use ctx::*;14pub use dynamic::*;15pub use evaluate::*;16use jsonnet_parser::*;17pub use obj::*;18use std::fmt::Debug;19use std::rc::Rc;20pub use val::*;2122pub trait FunctionRhs: Debug {23 fn evaluate(&self, ctx: Context) -> Val;24}25dynamic_wrapper!(FunctionRhs, BoxedFunctionRhs);2627pub trait FunctionDefault: Debug {28 fn default(&self, ctx: Context, expr: Expr) -> Val;29}30dynamic_wrapper!(FunctionDefault, BoxedFunctionDefault);3132#[cfg(test)]33pub mod tests {34 use super::{evaluate, Context, Val};35 use jsonnet_parser::*;3637 38 39 40 41 42 macro_rules! assert_eval {43 ($str: expr) => {44 assert_eq!(45 evaluate(Context::new(), &parse($str).unwrap()),46 Val::Literal(LiteralType::True)47 )48 };49 }50 macro_rules! assert_json {51 ($str: expr, $out: expr) => {52 assert_eq!(53 format!("{}", evaluate(Context::new(), &parse($str).unwrap())),54 $out55 )56 };57 }58 macro_rules! assert_eval_neg {59 ($str: expr) => {60 assert_eq!(61 evaluate(Context::new(), &parse($str).unwrap()),62 Val::Literal(LiteralType::False)63 )64 };65 }6667 68 #[test]69 fn equality_operator() {70 assert_eval!("2 == 2");71 assert_eval_neg!("2 != 2");72 assert_eval!("2 != 3");73 assert_eval_neg!("2 == 3");74 assert_eval!("'Hello' == 'Hello'");75 assert_eval_neg!("'Hello' != 'Hello'");76 assert_eval!("'Hello' != 'World'");77 assert_eval_neg!("'Hello' == 'World'");78 }7980 #[test]81 fn math_evaluation() {82 assert_eval!("2 + 2 * 2 == 6");83 assert_eval!("3 + (2 + 2 * 2) == 9");84 }8586 #[test]87 fn string_concat() {88 assert_eval!("'Hello' + 'World' == 'HelloWorld'");89 assert_eval!("'Hello' * 3 == 'HelloHelloHello'");90 assert_eval!("'Hello' + 'World' * 3 == 'HelloWorldWorldWorld'");91 }9293 #[test]94 fn local() {95 assert_eval!("local a = 2; local b = 3; a + b == 5");96 assert_eval!("local a = 1, b = a + 1; a + b == 3");97 assert_eval!("local a = 1; local a = 2; a == 2");98 }99100 #[test]101 fn object_lazyness() {102 assert_json!("local a = {a:error 'test'}; {}", r#"{}"#);103 }104105 #[test]106 fn object_inheritance() {107 assert_json!("{a:self.b} + {b:3}", r#"{"a":3,"b":3}"#);108 }109110 #[test]111 fn test_object() {112 assert_json!("{a:2}", r#"{"a":2}"#);113 assert_json!("{a:2+2}", r#"{"a":4}"#);114 assert_json!("{a:2}+{b:2}", r#"{"a":2,"b":2}"#);115 assert_json!("{b:3}+{b:2}", r#"{"b":2}"#);116 assert_json!("{b:3}+{b+:2}", r#"{"b":5}"#);117 assert_json!("local test='a'; {[test]:2}", r#"{"a":2}"#);118 assert_json!(119 r#"120 {121 name: "Alice",122 welcome: "Hello " + self.name + "!",123 }124 "#,125 r#"{"name":"Alice","welcome":"Hello Alice!"}"#126 );127 assert_json!(128 r#"129 {130 name: "Alice",131 welcome: "Hello " + self.name + "!",132 } + {133 name: "Bob"134 }135 "#,136 r#"{"name":"Bob","welcome":"Hello Bob!"}"#137 );138 }139140 #[test]141 fn functions() {142 assert_json!(r#"local a = function(b, c = 2) b + c; a(2)"#, "4");143 assert_json!(144 r#"local a = function(b, c = "Dear") b + c + d, d = "World"; a("Hello")"#,145 r#""HelloDearWorld""#146 );147 }148149 #[test]150 fn local_methods() {151 assert_json!(r#"local a(b, c = 2) = b + c; a(2)"#, "4");152 assert_json!(153 r#"local a(b, c = "Dear") = b + c + d, d = "World"; a("Hello")"#,154 r#""HelloDearWorld""#155 );156 }157158 #[test]159 fn object_locals() {160 assert_json!(r#"{local a = 3, b: a}"#, r#"{"b":3}"#);161 assert_json!(r#"{local a = 3, local c = a, b: c}"#, r#"{"b":3}"#);162 assert_json!(163 r#"{local a = function (b) {[b]:4}, test: a("test")}"#,164 r#"{"test":{"test":4}}"#165 );166 }167168 169 #[test]170 fn std_assert_ok() {171 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";172 evaluate(173 Context::new(),174 &parse(&(std + "std.assertEqual(4.5 << 2, 16,)")).unwrap(),175 );176 }177178 #[test]179 #[should_panic]180 fn std_assert_failure() {181 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";182 evaluate(183 Context::new(),184 &parse(&(std + "std.assertEqual(4.5 << 2, 15,)")).unwrap(),185 );186 }187}