From f72b4368d92953d04d0a5ffddf675c3a96e06e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sigbj=C3=B8rn=20Skj=C3=A6ret?= Date: Sun, 18 Jan 2026 21:04:50 +0100 Subject: [PATCH 1/5] fix undefined keys and attributes --- common/jinja/runtime.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/jinja/runtime.cpp b/common/jinja/runtime.cpp index d8ef2790809..e3e4ebf1ec2 100644 --- a/common/jinja/runtime.cpp +++ b/common/jinja/runtime.cpp @@ -805,7 +805,7 @@ value member_expression::execute_impl(context & ctx) { } else if (is_val(property)) { auto key = property->as_string().str(); JJ_DEBUG("Accessing %s built-in '%s'", is_val(object) ? "array" : "string", key.c_str()); - val = try_builtin_func(ctx, key, object); + val = try_builtin_func(ctx, key, object, true); } else { throw std::runtime_error("Cannot access property with non-string/non-number: got " + property->type()); } @@ -814,7 +814,7 @@ value member_expression::execute_impl(context & ctx) { throw std::runtime_error("Cannot access property with non-string: got " + property->type()); } auto key = property->as_string().str(); - val = try_builtin_func(ctx, key, object); + val = try_builtin_func(ctx, key, object, true); } if (ctx.is_get_stats && val && object && property) { From 4c0e1011a777819226208e70cadbd83a14bca945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sigbj=C3=B8rn=20Skj=C3=A6ret?= Date: Sun, 18 Jan 2026 21:06:38 +0100 Subject: [PATCH 2/5] add falsy tests --- tests/test-jinja.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/test-jinja.cpp b/tests/test-jinja.cpp index 13818381ed1..3fc1c880f16 100644 --- a/tests/test-jinja.cpp +++ b/tests/test-jinja.cpp @@ -191,6 +191,42 @@ static void test_conditionals(testing & t) { json::object(), "yes" ); + + test_template(t, "is undefined falsy", + "{{ 'yes' if not y else 'no' }}", + json::object(), + "yes" + ); + + test_template(t, "is undefined attribute falsy", + "{{ 'yes' if not y.x else 'no' }}", + {{"y", true}}, + "yes" + ); + + test_template(t, "is undefined key falsy", + "{{ 'yes' if not y['x'] else 'no' }}", + {{"y", {{}}}}, + "yes" + ); + + test_template(t, "is empty array falsy", + "{{ 'yes' if not y else 'no' }}", + {{"y", json::array()}}, + "yes" + ); + + test_template(t, "is empty object falsy", + "{{ 'yes' if not y else 'no' }}", + {{"y", json::object()}}, + "yes" + ); + + test_template(t, "is empty string falsy", + "{{ 'yes' if not y else 'no' }}", + {{"y", ""}}, + "yes" + ); } static void test_loops(testing & t) { From a19fc88af39ddbf48a125f3e5bd0beec4933f0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sigbj=C3=B8rn=20Skj=C3=A6ret?= Date: Mon, 19 Jan 2026 08:59:04 +0100 Subject: [PATCH 3/5] as_bool for integers and floats --- common/jinja/value.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/jinja/value.h b/common/jinja/value.h index 4e916919b3f..7bd0202cea8 100644 --- a/common/jinja/value.h +++ b/common/jinja/value.h @@ -203,6 +203,9 @@ struct value_int_t : public value_t { virtual int64_t as_int() const override { return val_int; } virtual double as_float() const override { return static_cast(val_int); } virtual string as_string() const override { return std::to_string(val_int); } + virtual bool as_bool() const override { + return val_int != 0; + } virtual const func_builtins & get_builtins() const override; }; using value_int = std::shared_ptr; @@ -219,6 +222,9 @@ struct value_float_t : public value_t { if (out.back() == '.') out.push_back('0'); // leave one zero if no decimals return out; } + virtual bool as_bool() const override { + return val_flt != 0.0; + } virtual const func_builtins & get_builtins() const override; }; using value_float = std::shared_ptr; From 58789800b3b9e6f2e6de0e8405af8aaa105f98c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sigbj=C3=B8rn=20Skj=C3=A6ret?= Date: Mon, 19 Jan 2026 09:01:43 +0100 Subject: [PATCH 4/5] more falsy/truthy tests --- tests/test-jinja.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/test-jinja.cpp b/tests/test-jinja.cpp index 3fc1c880f16..72bafdd899e 100644 --- a/tests/test-jinja.cpp +++ b/tests/test-jinja.cpp @@ -227,6 +227,48 @@ static void test_conditionals(testing & t) { {{"y", ""}}, "yes" ); + + test_template(t, "is 0 falsy", + "{{ 'yes' if not y else 'no' }}", + {{"y", 0}}, + "yes" + ); + + test_template(t, "is 0.0 falsy", + "{{ 'yes' if not y else 'no' }}", + {{"y", 0.0}}, + "yes" + ); + + test_template(t, "is non-empty array truthy", + "{{ 'yes' if y else 'no' }}", + {{"y", json::array({""})}}, + "yes" + ); + + test_template(t, "is non-empty object truthy", + "{{ 'yes' if y else 'no' }}", + {{"y", {"x", false}}}, + "yes" + ); + + test_template(t, "is non-empty string truthy", + "{{ 'yes' if y else 'no' }}", + {{"y", "0"}}, + "yes" + ); + + test_template(t, "is 1 truthy", + "{{ 'yes' if y else 'no' }}", + {{"y", 1}}, + "yes" + ); + + test_template(t, "is 1.0 thruthy", + "{{ 'yes' if y else 'no' }}", + {{"y", 1.0}}, + "yes" + ); } static void test_loops(testing & t) { From 5a8e47ffaf4241c9ea8fe83814f33191a8cde5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sigbj=C3=B8rn=20Skj=C3=A6ret?= Date: Mon, 19 Jan 2026 09:20:26 +0100 Subject: [PATCH 5/5] --typo [no ci] --- tests/test-jinja.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-jinja.cpp b/tests/test-jinja.cpp index 72bafdd899e..99630ecb3b8 100644 --- a/tests/test-jinja.cpp +++ b/tests/test-jinja.cpp @@ -264,7 +264,7 @@ static void test_conditionals(testing & t) { "yes" ); - test_template(t, "is 1.0 thruthy", + test_template(t, "is 1.0 truthy", "{{ 'yes' if y else 'no' }}", {{"y", 1.0}}, "yes"