Skip to content

Commit cb742c9

Browse files
authored
jinja : fix undefined keys and attributes and int/float as bool (#18924)
* fix undefined keys and attributes * add falsy tests * as_bool for integers and floats * more falsy/truthy tests * --typo
1 parent 9f8c160 commit cb742c9

3 files changed

Lines changed: 86 additions & 2 deletions

File tree

common/jinja/runtime.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ value member_expression::execute_impl(context & ctx) {
805805
} else if (is_val<value_string>(property)) {
806806
auto key = property->as_string().str();
807807
JJ_DEBUG("Accessing %s built-in '%s'", is_val<value_array>(object) ? "array" : "string", key.c_str());
808-
val = try_builtin_func(ctx, key, object);
808+
val = try_builtin_func(ctx, key, object, true);
809809
} else {
810810
throw std::runtime_error("Cannot access property with non-string/non-number: got " + property->type());
811811
}
@@ -814,7 +814,7 @@ value member_expression::execute_impl(context & ctx) {
814814
throw std::runtime_error("Cannot access property with non-string: got " + property->type());
815815
}
816816
auto key = property->as_string().str();
817-
val = try_builtin_func(ctx, key, object);
817+
val = try_builtin_func(ctx, key, object, true);
818818
}
819819

820820
if (ctx.is_get_stats && val && object && property) {

common/jinja/value.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ struct value_int_t : public value_t {
203203
virtual int64_t as_int() const override { return val_int; }
204204
virtual double as_float() const override { return static_cast<double>(val_int); }
205205
virtual string as_string() const override { return std::to_string(val_int); }
206+
virtual bool as_bool() const override {
207+
return val_int != 0;
208+
}
206209
virtual const func_builtins & get_builtins() const override;
207210
};
208211
using value_int = std::shared_ptr<value_int_t>;
@@ -219,6 +222,9 @@ struct value_float_t : public value_t {
219222
if (out.back() == '.') out.push_back('0'); // leave one zero if no decimals
220223
return out;
221224
}
225+
virtual bool as_bool() const override {
226+
return val_flt != 0.0;
227+
}
222228
virtual const func_builtins & get_builtins() const override;
223229
};
224230
using value_float = std::shared_ptr<value_float_t>;

tests/test-jinja.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,84 @@ static void test_conditionals(testing & t) {
191191
json::object(),
192192
"yes"
193193
);
194+
195+
test_template(t, "is undefined falsy",
196+
"{{ 'yes' if not y else 'no' }}",
197+
json::object(),
198+
"yes"
199+
);
200+
201+
test_template(t, "is undefined attribute falsy",
202+
"{{ 'yes' if not y.x else 'no' }}",
203+
{{"y", true}},
204+
"yes"
205+
);
206+
207+
test_template(t, "is undefined key falsy",
208+
"{{ 'yes' if not y['x'] else 'no' }}",
209+
{{"y", {{}}}},
210+
"yes"
211+
);
212+
213+
test_template(t, "is empty array falsy",
214+
"{{ 'yes' if not y else 'no' }}",
215+
{{"y", json::array()}},
216+
"yes"
217+
);
218+
219+
test_template(t, "is empty object falsy",
220+
"{{ 'yes' if not y else 'no' }}",
221+
{{"y", json::object()}},
222+
"yes"
223+
);
224+
225+
test_template(t, "is empty string falsy",
226+
"{{ 'yes' if not y else 'no' }}",
227+
{{"y", ""}},
228+
"yes"
229+
);
230+
231+
test_template(t, "is 0 falsy",
232+
"{{ 'yes' if not y else 'no' }}",
233+
{{"y", 0}},
234+
"yes"
235+
);
236+
237+
test_template(t, "is 0.0 falsy",
238+
"{{ 'yes' if not y else 'no' }}",
239+
{{"y", 0.0}},
240+
"yes"
241+
);
242+
243+
test_template(t, "is non-empty array truthy",
244+
"{{ 'yes' if y else 'no' }}",
245+
{{"y", json::array({""})}},
246+
"yes"
247+
);
248+
249+
test_template(t, "is non-empty object truthy",
250+
"{{ 'yes' if y else 'no' }}",
251+
{{"y", {"x", false}}},
252+
"yes"
253+
);
254+
255+
test_template(t, "is non-empty string truthy",
256+
"{{ 'yes' if y else 'no' }}",
257+
{{"y", "0"}},
258+
"yes"
259+
);
260+
261+
test_template(t, "is 1 truthy",
262+
"{{ 'yes' if y else 'no' }}",
263+
{{"y", 1}},
264+
"yes"
265+
);
266+
267+
test_template(t, "is 1.0 truthy",
268+
"{{ 'yes' if y else 'no' }}",
269+
{{"y", 1.0}},
270+
"yes"
271+
);
194272
}
195273

196274
static void test_loops(testing & t) {

0 commit comments

Comments
 (0)