Repository: ggerganov/llama.cpp
File: tests/test-jinja.cpp (C++)

Code before:
    t.test("non-existing variables", [&](testing & t) {
        for (int i = 0; i < num_iterations; ++i) {
            std::string var = random_string(rng, 20);
            std::string tmpl = "{{ " + var + " }}";
            json vars = json::object(); // empty context
            t.assert_true("should not crash", fuzz_test_template(tmpl, vars));
        }
    });

    t.test("non-existing nested attributes", [&](testing & t) {
        for (int i = 0; i < num_iterations; ++i) {
            std::string var1 = var_names[choice_dist(rng) % var_names.size()];
            std::string var2 = random_string(rng, 10);
            std::string var3 = random_string(rng, 10);
            std::string tmpl = "{{ " + var1 + "." + var2 + "." + var3 + " }}";
            json vars = {{var1, {{"other", 123}}}};
            t.assert_true("should not crash", fuzz_test_template(tmpl, vars));
        }
    });

    t.test("invalid filter arguments", [&](testing & t) {
        for (int i = 0; i < num_iterations; ++i) {
            std::string filter = filters[choice_dist(rng) % filters.size()];
            int val = int_dist(rng);
            std::string tmpl = "{{ " + std::to_string(val) + " | " + filter + " }}";
            json vars = json::object();
            t.assert_true("should not crash", fuzz_test_template(tmpl, vars));
        }
    });

    t.test("chained filters on various types", [&](testing & t) {
        for (int i = 0; i < num_iterations; ++i) {
            std::string f1 = filters[choice_dist(rng) % filters.size()];
            std::string f2 = filters[choice_dist(rng) % filters.size()];
            std::string var = var_names[choice_dist(rng) % var_names.size()];
            std::string tmpl = "{{ " + var + " | " + f1 + " | " + f2 + " }}";
            json vars = {
                {"x", 42},
                {"y", "hello"},
                {"arr", json::array({1, 2, 3})},
                {"obj", {{"a", 1}, {"b", 2}}},
                {"items", json::array({"a", "b", "c"})}
            };
            t.assert_true("should not crash", fuzz_test_template(tmpl, vars));
        }
    });

    t.test("invalid builtin calls", [&](testing & t) {
        for (int i = 0; i < num_iterations; ++i) {
            std::string builtin = builtins[choice_dist(rng) % builtins.size()];
            std::string arg;

Review comment (suggestion):
```suggestion
import jinja2
import jinja2.ext as jinja2_ext
import json
import sys
from datetime import datetime
from jinja2.sandbox import ImmutableSandboxedEnvironment

tmpl = json.loads(sys.argv[1])
vars_json = json.loads(sys.argv[2])

env = ImmutableSandboxedEnvironment(
    trim_blocks=True,
    lstrip_blocks=True,
    extensions=[jinja2_ext.loopcontrols],
)
environment.filters["tojson"] = lambda x, ensure_ascii=False, indent=None, separators=None, sort_keys=False: json.dumps(x, ensure_ascii=ensure_ascii, indent=indent, separators=separators, sort_keys=sort_keys)
environment.globals["strftime_now"] = lambda format: datetime.now().strftime(format)
environment.globals["raise_exception"] = lambda message: raise jinja2.exceptions.TemplateError(message)
template = env.from_string(tmpl)
```

Code after:
// note: we use SandboxedEnvironment instead of ImmutableSandboxedEnvironment to allow usage of in-place array methods like append() and pop()
static std::string py_script = R"(
import jinja2
import jinja2.ext as jinja2_ext
import json
import sys
from datetime import datetime
from jinja2.sandbox import SandboxedEnvironment

tmpl = json.loads(sys.argv[1])
vars_json = json.loads(sys.argv[2])

env = SandboxedEnvironment(
    trim_blocks=True,
    lstrip_blocks=True,
    extensions=[jinja2_ext.loopcontrols],
)

def raise_exception(message):
    raise jinja2.exceptions.TemplateError(message)

env.filters["tojson"] = lambda x, ensure_ascii=False, indent=None, separators=None, sort_keys=False: json.dumps(x, ensure_ascii=ensure_ascii, indent=indent, separators=separators, sort_keys=sort_keys)
env.globals["strftime_now"] = lambda format: datetime.now().strftime(format)
env.globals["raise_exception"] = raise_exception

template = env.from_string(tmpl)
result = template.render(**vars_json)
print(result, end='')
)";

static void test_template_py(testing & t, const std::string & name, const std::string & tmpl, const json & vars, const std::string & expect) {
    t.test(name, [&tmpl, &vars, &expect](testing & t) {
        // Prepare arguments
        std::string tmpl_json = json(tmpl).dump();
        std::string vars_json = vars.dump();

#ifdef _WIN32
        const char * python_executable = "python.exe";
#else
        const char * python_executable = "python3";
#endif

        const char * command_line[] = {python_executable, "-c", py_script.c_str(), tmpl_json.c_str(), vars_json.c_str(), NULL};

        struct subprocess_s subprocess;
        int options = subprocess_option_combined_stdout_stderr
                    | subprocess_option_no_window
                    | subprocess_option_inherit_environment
                    | subprocess_option_search_user_path;
        int result = subprocess_create(command_line, options, &subprocess);