more tests
This commit is contained in:
parent
2a31c9a30c
commit
1cf25734a9
|
|
@ -385,14 +385,30 @@ const func_builtins & value_string_t::get_builtins() const {
|
|||
return input;
|
||||
}
|
||||
}},
|
||||
{"slice", [](const func_args & args) -> value {
|
||||
auto & input = args.args[0];
|
||||
if (!is_val<value_string>(input)) {
|
||||
throw raised_exception("slice() first argument must be a string");
|
||||
}
|
||||
if (args.args.size() < 1 || args.args.size() > 4) {
|
||||
throw raised_exception("slice() takes between 1 and 4 arguments");
|
||||
}
|
||||
int64_t start = is_val<value_int>(args.args[1]) ? args.args[1]->as_int() : 0;
|
||||
int64_t stop = is_val<value_int>(args.args[2]) ? args.args[2]->as_int() : -1;
|
||||
int64_t step = is_val<value_int>(args.args[3]) ? args.args[3]->as_int() : 1;
|
||||
if (step == 0) {
|
||||
throw raised_exception("slice step cannot be zero");
|
||||
}
|
||||
auto sliced = slice(input->as_string().str(), start, stop, step);
|
||||
auto res = mk_val<value_string>(sliced);
|
||||
res->val_str.mark_input_based_on(input->as_string());
|
||||
return res;
|
||||
}},
|
||||
{"indent", [](const func_args &) -> value {
|
||||
throw std::runtime_error("indent builtin not implemented");
|
||||
throw std::runtime_error("String indent builtin not implemented");
|
||||
}},
|
||||
{"join", [](const func_args &) -> value {
|
||||
throw std::runtime_error("join builtin not implemented");
|
||||
}},
|
||||
{"slice", [](const func_args &) -> value {
|
||||
throw std::runtime_error("slice builtin not implemented");
|
||||
throw std::runtime_error("String join builtin not implemented");
|
||||
}},
|
||||
};
|
||||
return builtins;
|
||||
|
|
@ -635,15 +651,21 @@ const func_builtins & value_object_t::get_builtins() const {
|
|||
|
||||
const func_builtins & value_null_t::get_builtins() const {
|
||||
static const func_builtins builtins = {
|
||||
{"list", [](const func_args &) -> value {
|
||||
{"list", [](const func_args & args) -> value {
|
||||
// fix for meetkai-functionary-medium-v3.1.jinja
|
||||
// TODO: hide under a flag?
|
||||
return mk_val<value_array>();
|
||||
if (args.ctx.wrk_around.none_has_builtins) {
|
||||
return mk_val<value_array>();
|
||||
} else {
|
||||
throw raised_exception("'list' builtin not supported for none type");
|
||||
}
|
||||
}},
|
||||
{"selectattr", [](const func_args &) -> value {
|
||||
{"selectattr", [](const func_args & args) -> value {
|
||||
// fix for meetkai-functionary-medium-v3.1.jinja
|
||||
// TODO: hide under a flag?
|
||||
return mk_val<value_array>();
|
||||
if (args.ctx.wrk_around.none_has_builtins) {
|
||||
return mk_val<value_array>();
|
||||
} else {
|
||||
throw raised_exception("'selectattr' builtin not supported for none type");
|
||||
}
|
||||
}},
|
||||
};
|
||||
return builtins;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,15 @@ value binary_expression::execute_impl(context & ctx) {
|
|||
// Special case: `anything in undefined` is `false` and `anything not in undefined` is `true`
|
||||
return mk_val<value_bool>(op.value == "not in");
|
||||
}
|
||||
if (ctx.wrk_around.string_plus_undefined_is_string && (op.value == "+" || op.value == "~")) {
|
||||
JJ_DEBUG("%s", "Workaround: treating undefined as empty string for string concatenation");
|
||||
auto left_str = left_val->is_undefined() ? string() : left_val->as_string();
|
||||
auto right_str = right_val->is_undefined() ? string() : right_val->as_string();
|
||||
auto output = left_str.append(right_str);
|
||||
auto res = mk_val<value_string>();
|
||||
res->val_str = std::move(output);
|
||||
return res;
|
||||
}
|
||||
throw std::runtime_error("Cannot perform operation " + op.value + " on undefined values");
|
||||
} else if (is_val<value_null>(left_val) || is_val<value_null>(right_val)) {
|
||||
throw std::runtime_error("Cannot perform operation on null values");
|
||||
|
|
@ -628,9 +637,12 @@ value member_expression::execute_impl(context & ctx) {
|
|||
} else if (is_val<value_array>(object) || is_val<value_string>(object)) {
|
||||
if (is_val<value_int>(property)) {
|
||||
int64_t index = property->as_int();
|
||||
JJ_DEBUG("Accessing %s index %lld", is_val<value_array>(object) ? "array" : "string", index);
|
||||
JJ_DEBUG("Accessing %s index %lld", object->type().c_str(), index);
|
||||
if (is_val<value_array>(object)) {
|
||||
auto & arr = object->as_array();
|
||||
if (index < 0) {
|
||||
index += static_cast<int64_t>(arr.size());
|
||||
}
|
||||
if (index >= 0 && index < static_cast<int64_t>(arr.size())) {
|
||||
val = arr[index];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "jinja-lexer.h"
|
||||
#include "jinja-value.h"
|
||||
#include "jinja-workaround.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -52,6 +53,8 @@ struct context {
|
|||
|
||||
std::time_t current_time; // for functions that need current time
|
||||
|
||||
workarounds wrk_around; // workarounds for non-standard jinja behavior
|
||||
|
||||
context() {
|
||||
var["true"] = mk_val<value_bool>(true);
|
||||
var["false"] = mk_val<value_bool>(false);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "jinja-value.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace jinja {
|
||||
|
||||
// containing workarounds for Jinja templates that rely on non-standard behavior
|
||||
|
||||
struct workarounds {
|
||||
// meetkai-functionary-medium-v3.1.jinja call filter on None type
|
||||
bool none_has_builtins = true;
|
||||
|
||||
// Olmo calls operation + between string and undefined
|
||||
bool string_plus_undefined_is_string = true;
|
||||
};
|
||||
|
||||
} // namespace jinja
|
||||
|
|
@ -28,11 +28,32 @@ int main(void) {
|
|||
|
||||
std::vector<std::string> failed_tests;
|
||||
|
||||
auto is_ignored_file = [](const std::string & filename) -> bool {
|
||||
std::vector<std::string> ignored_files = {
|
||||
"Apriel-",
|
||||
"Olmo-3-7B-Instruct-Heretic-GGUF",
|
||||
};
|
||||
for (const auto & ignored : ignored_files) {
|
||||
if (filename.find(ignored) != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// list all files in models/templates/ and run each
|
||||
size_t test_count = 0;
|
||||
std::string dir_path = "models/templates/";
|
||||
size_t skip_count = 0;
|
||||
//std::string dir_path = "models/templates/";
|
||||
std::string dir_path = "../test-jinja/templates/";
|
||||
for (const auto & entry : std::filesystem::directory_iterator(dir_path)) {
|
||||
if (entry.is_regular_file()) {
|
||||
if (is_ignored_file(entry.path().filename().string())) {
|
||||
std::cout << "=== SKIPPING TEMPLATE FILE: " << entry.path().string() << " ===\n";
|
||||
skip_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
test_count++;
|
||||
std::cout << "\n\n=== RUNNING TEMPLATE FILE: " << entry.path().string() << " ===\n";
|
||||
std::ifstream infile(entry.path());
|
||||
|
|
@ -43,6 +64,7 @@ int main(void) {
|
|||
std::cout << "Exception: " << e.what() << "\n";
|
||||
std::cout << "=== ERROR WITH TEMPLATE FILE: " << entry.path().string() << " ===\n";
|
||||
failed_tests.push_back(entry.path().string());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,6 +72,7 @@ int main(void) {
|
|||
std::cout << "\n\n=== TEST SUMMARY ===\n";
|
||||
std::cout << "Total tests run: " << test_count << "\n";
|
||||
std::cout << "Total failed tests: " << failed_tests.size() << "\n";
|
||||
std::cout << "Total skipped tests: " << skip_count << "\n";
|
||||
for (const auto & test : failed_tests) {
|
||||
std::cout << "FAILED TEST: " << test << "\n";
|
||||
}
|
||||
|
|
@ -92,6 +115,7 @@ void run(std::string contents) {
|
|||
],
|
||||
"bos_token": "<s>",
|
||||
"eos_token": "</s>",
|
||||
"tools": [],
|
||||
"functions": "",
|
||||
"datetime": ""
|
||||
})";
|
||||
|
|
|
|||
Loading…
Reference in New Issue