diff --git a/common/jinja/runtime.cpp b/common/jinja/runtime.cpp index b02992529..49354c7c9 100644 --- a/common/jinja/runtime.cpp +++ b/common/jinja/runtime.cpp @@ -167,6 +167,12 @@ value binary_expression::execute_impl(context & ctx) { } throw std::runtime_error("Cannot perform operation " + op.value + " on undefined values"); } else if (is_val(left_val) || is_val(right_val)) { + if (!is_val(right_val) && (op.value == "in" || op.value == "not in")) { + // case: none in {'low': 1} + // A null left operand is looked up like any other value. + bool member = test_is_in(); + return mk_val(op.value == "in" ? member : !member); + } if (op.value == "+" || op.value == "~") { value res = mk_val(); if (workaround_concat_null_with_str(res)) { diff --git a/tests/test-jinja.cpp b/tests/test-jinja.cpp index 974a3f9dd..ab551d7b3 100644 --- a/tests/test-jinja.cpp +++ b/tests/test-jinja.cpp @@ -374,6 +374,24 @@ static void test_expressions(testing & t) { "42" ); + test_template(t, "none in object", + "{{ x in {'low': 1, 'high': 2} }}", + {{"x", nullptr}}, + "False" + ); + + test_template(t, "none not in object", + "{{ x not in {'low': 1, 'high': 2} }}", + {{"x", nullptr}}, + "True" + ); + + test_template(t, "none in array", + "{{ x in [1, none, 3] }}", + {{"x", nullptr}}, + "True" + ); + test_template(t, "dot notation", "{{ user.name }}", {{"user", {{"name", "Bob"}}}},