diff --git a/common/jinja/value.cpp b/common/jinja/value.cpp index cd6a36956cea..847d2a9d6b36 100644 --- a/common/jinja/value.cpp +++ b/common/jinja/value.cpp @@ -1077,8 +1077,7 @@ const func_builtins & value_array_t::get_builtins() const { value val_reverse = args.get_kwarg_or_pos("reverse", 1); value val_case = args.get_kwarg_or_pos("case_sensitive", 2); value attribute = args.get_kwarg_or_pos("attribute", 3); - // FIXME: sorting is currently always case sensitive - //const bool case_sensitive = val_case->as_bool(); // undefined == false + const bool case_sensitive = val_case->as_bool(); // undefined == false const bool reverse = val_reverse->as_bool(); // undefined == false const bool attr_is_int = is_val(attribute); const int64_t attr_int = attr_is_int ? attribute->as_int() : 0; @@ -1097,6 +1096,11 @@ const func_builtins & value_array_t::get_builtins() const { throw raised_exception("sort: unsupported object attribute comparison between " + a->type() + " and " + b->type()); } } + if (!case_sensitive && is_val(val_a) && is_val(val_b)) { + const std::string sa = val_a->as_string().lowercase().str(); + const std::string sb = val_b->as_string().lowercase().str(); + return reverse ? (sa > sb) : (sa < sb); + } return value_compare(val_a, val_b, reverse ? value_compare_op::gt : value_compare_op::lt); }); return is_val(val) ? mk_val(std::move(arr)) : mk_val(std::move(arr)); @@ -1194,17 +1198,19 @@ const func_builtins & value_object_t::get_builtins() const { value val_case = args.get_kwarg_or_pos("case_sensitive", 1); value val_by = args.get_kwarg_or_pos("by", 2); value val_reverse = args.get_kwarg_or_pos("reverse", 3); - // FIXME: sorting is currently always case sensitive - //const bool case_sensitive = val_case->as_bool(); // undefined == false + const bool case_sensitive = val_case->as_bool(); // undefined == false const bool reverse = val_reverse->as_bool(); // undefined == false const bool by_value = is_val(val_by) && val_by->as_string().str() == "value" ? true : false; auto result = mk_val(val_input); // copy std::sort(result->val_obj.begin(), result->val_obj.end(), [&](const auto & a, const auto & b) { - if (by_value) { - return value_compare(a.second, b.second, reverse ? value_compare_op::gt : value_compare_op::lt); - } else { - return value_compare(a.first, b.first, reverse ? value_compare_op::gt : value_compare_op::lt); + value val_a = by_value ? a.second : a.first; + value val_b = by_value ? b.second : b.first; + if (!case_sensitive && is_val(val_a) && is_val(val_b)) { + const std::string sa = val_a->as_string().lowercase().str(); + const std::string sb = val_b->as_string().lowercase().str(); + return reverse ? (sa > sb) : (sa < sb); } + return value_compare(val_a, val_b, reverse ? value_compare_op::gt : value_compare_op::lt); }); return result; }}, diff --git a/tests/test-jinja.cpp b/tests/test-jinja.cpp index 81bbcd55a46e..1f546d7a70ea 100644 --- a/tests/test-jinja.cpp +++ b/tests/test-jinja.cpp @@ -657,6 +657,18 @@ static void test_filters(testing & t) { "xyz" ); + test_template(t, "sort case_sensitive=false", + "{{ items|sort(case_sensitive=false)|join(',') }}", + {{"items", json::array({"Banana", "apple", "Cherry", "date"})}}, + "apple,Banana,Cherry,date" + ); + + test_template(t, "sort case_sensitive=true", + "{{ items|sort(case_sensitive=true)|join(',') }}", + {{"items", json::array({"Banana", "apple", "Cherry", "date"})}}, + "Banana,Cherry,apple,date" + ); + test_template(t, "join", "{{ items|join(', ') }}", {{"items", json::array({"a", "b", "c"})}}, @@ -1755,6 +1767,12 @@ static void test_object_methods(testing & t) { "A=1 B=2 a=1 b=2 c=3 " ); + test_template(t, "dictsort case insensitive", + "{% for k, v in obj|dictsort(case_sensitive=false) %}{{ k }}={{ v }} {% endfor %}", + {{"obj", {{"Banana", 1}, {"apple", 2}, {"Cherry", 3}}}}, + "apple=2 Banana=1 Cherry=3 " + ); + test_template(t, "object|tojson", "{{ obj|tojson }}", {{"obj", {{"name", "test"}, {"value", 42}}}},