chat: refactor handling supports_string_content / supports_typed_content (#27130)
* better supports_string_content cap detect * test: add "skip" * messages_inp_normalizer
This commit is contained in:
+49
-2
@@ -10,6 +10,7 @@
|
||||
#include "jinja/parser.h"
|
||||
#include "jinja/lexer.h"
|
||||
#include "jinja/utils.h"
|
||||
#include "jinja/caps.h"
|
||||
|
||||
#include "testing.h"
|
||||
|
||||
@@ -33,6 +34,7 @@ static void test_array_methods(testing & t);
|
||||
static void test_object_methods(testing & t);
|
||||
static void test_hasher(testing & t);
|
||||
static void test_stats(testing & t);
|
||||
static void test_caps(testing & t);
|
||||
static void test_string_parts(testing & t);
|
||||
static void test_fuzzing(testing & t);
|
||||
|
||||
@@ -73,6 +75,7 @@ int main(int argc, char *argv[]) {
|
||||
if (!g_python_mode) {
|
||||
t.test("hasher", test_hasher);
|
||||
t.test("stats", test_stats);
|
||||
t.test("caps", test_caps);
|
||||
t.test("string parts", test_string_parts);
|
||||
t.test("fuzzing", test_fuzzing);
|
||||
}
|
||||
@@ -2059,6 +2062,51 @@ static void test_stats(testing & t) {
|
||||
});
|
||||
}
|
||||
|
||||
static void test_caps(testing & t) {
|
||||
static auto get_caps = [](const std::string & tmpl) -> jinja::caps {
|
||||
jinja::lexer lexer;
|
||||
auto lexer_res = lexer.tokenize(tmpl);
|
||||
|
||||
jinja::program prog = jinja::parse_from_tokens(lexer_res);
|
||||
|
||||
return jinja::caps_get(prog);
|
||||
};
|
||||
|
||||
t.test("string content", [](testing & t) {
|
||||
auto caps = get_caps(
|
||||
"{% for message in messages %}"
|
||||
"{{ message['role'] + ': ' + message['content'] }}"
|
||||
"{% endfor %}"
|
||||
);
|
||||
t.assert_true("supports string content", caps.supports_string_content);
|
||||
t.assert_true("does not support typed content", !caps.supports_typed_content);
|
||||
});
|
||||
|
||||
t.test("typed content, raises on string", [](testing & t) {
|
||||
// 'selectattr' is not a String filter, so it throws
|
||||
auto caps = get_caps(
|
||||
"{% for message in messages %}"
|
||||
"{% for content in message['content'] | selectattr('type', 'equalto', 'text') %}"
|
||||
"{{ content['text'] }}"
|
||||
"{% endfor %}"
|
||||
"{% endfor %}"
|
||||
);
|
||||
t.assert_true("does not support string content", !caps.supports_string_content);
|
||||
t.assert_true("supports typed content", caps.supports_typed_content);
|
||||
});
|
||||
|
||||
t.test("typed content, silently drops string", [](testing & t) {
|
||||
// no throw here, but content[0]['text'] is undefined for a string (MiniMax-M1 case)
|
||||
auto caps = get_caps(
|
||||
"{% for message in messages %}"
|
||||
"{{ message['content'][0]['text'] }}"
|
||||
"{% endfor %}"
|
||||
);
|
||||
t.assert_true("does not support string content", !caps.supports_string_content);
|
||||
t.assert_true("supports typed content", caps.supports_typed_content);
|
||||
});
|
||||
}
|
||||
|
||||
static void test_string_parts(testing & t) {
|
||||
static auto render = [](const std::string & tmpl, const json & vars) -> jinja::string {
|
||||
jinja::lexer lexer;
|
||||
@@ -2116,8 +2164,7 @@ static void test_template_cpp(testing & t, const std::string & name, const std::
|
||||
t.log("Actual : " + json(rendered).dump());
|
||||
}
|
||||
} catch (const jinja::not_implemented_exception & e) {
|
||||
// TODO @ngxson : remove this when the test framework supports skipping tests
|
||||
t.log("Skipped: " + std::string(e.what()));
|
||||
t.skip(e.what());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+28
-3
@@ -21,6 +21,11 @@ struct testing {
|
||||
int failures = 0;
|
||||
int unnamed = 0;
|
||||
int exceptions = 0;
|
||||
int skipped = 0;
|
||||
|
||||
// set by skip(), read by the innermost test()
|
||||
bool skip_current = false;
|
||||
std::string skip_reason;
|
||||
|
||||
static constexpr std::size_t status_column = 80;
|
||||
|
||||
@@ -78,7 +83,12 @@ struct testing {
|
||||
}
|
||||
}
|
||||
|
||||
void print_result(const std::string &label, int new_failures, int new_assertions, const std::string &extra = "") const {
|
||||
void skip(const std::string &reason = "") {
|
||||
skip_current = true;
|
||||
skip_reason = reason;
|
||||
}
|
||||
|
||||
void print_result(const std::string &label, int new_failures, int new_assertions, const std::string &extra = "", bool was_skipped = false) const {
|
||||
std::string line = indent() + label;
|
||||
|
||||
std::string details;
|
||||
@@ -101,7 +111,7 @@ struct testing {
|
||||
line += " (" + details + ")";
|
||||
}
|
||||
|
||||
std::string status = (new_failures == 0) ? "[PASS]" : "[FAIL]";
|
||||
std::string status = new_failures != 0 ? "[FAIL]" : (was_skipped ? "[SKIP]" : "[PASS]");
|
||||
|
||||
if (line.size() + 1 < status_column) {
|
||||
line.append(status_column - line.size(), ' ');
|
||||
@@ -126,12 +136,26 @@ struct testing {
|
||||
int before_failures = failures;
|
||||
int before_assertions = assertions;
|
||||
|
||||
// do not let a skipped subtest also mark its parent as skipped
|
||||
bool outer_skip = skip_current;
|
||||
std::string outer_skip_reason = skip_reason;
|
||||
skip_current = false;
|
||||
skip_reason.clear();
|
||||
|
||||
run_with_exceptions([&] { f(*this); }, "test");
|
||||
|
||||
int new_failures = failures - before_failures;
|
||||
int new_assertions = assertions - before_assertions;
|
||||
|
||||
print_result(name, new_failures, new_assertions);
|
||||
bool was_skipped = skip_current && new_failures == 0;
|
||||
if (was_skipped) {
|
||||
++skipped;
|
||||
}
|
||||
|
||||
print_result(name, new_failures, new_assertions, was_skipped ? skip_reason : "", was_skipped);
|
||||
|
||||
skip_current = outer_skip;
|
||||
skip_reason = outer_skip_reason;
|
||||
|
||||
stack.pop_back();
|
||||
}
|
||||
@@ -238,6 +262,7 @@ struct testing {
|
||||
out << "assertions : " << assertions << "\n";
|
||||
out << "failures : " << failures << "\n";
|
||||
out << "exceptions : " << exceptions << "\n";
|
||||
out << "skipped : " << skipped << "\n";
|
||||
return failures == 0 ? 0 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user