#include "zeroerr/assert.h" #include "zeroerr/unittest.h" #include "common/SquirrelBinding.h" #include #include #include #include #include using eve::Diagnostic; using eve::DiagnosticCode; using eve::Result; using eve::Value; TEST_CASE("squirrel_binding.value_round_trip_preserves_nested_value") { ssq::VM vm(1024, ssq::Libs::ALL); Value::Array items; items.emplace_back(Value::Object{{"enabled", true}, {"label", "nested"}}); items.emplace_back(std::int64_t{9}); const Value original(Value::Object{ {"name", "round-trip"}, {"items", Value(std::move(items))}, {"ratio", 1.25}, }); auto pushed = eve::script::pushValue(vm.getHandle(), original); REQUIRE(pushed.ok()); auto restored = eve::script::valueFromSquirrel(vm.getHandle(), -1); REQUIRE(restored.ok()); CHECK(restored.value() == original); sq_pop(vm.getHandle(), 1); } TEST_CASE("squirrel_binding.value_rejects_non_finite_numbers_with_path_and_source") { ssq::VM vm(1024, ssq::Libs::ALL); const auto top = sq_gettop(vm.getHandle()); sq_newarray(vm.getHandle(), 0); sq_pushfloat(vm.getHandle(), std::numeric_limits::infinity()); REQUIRE(SQ_SUCCEEDED(sq_arrayappend(vm.getHandle(), -2))); auto result = eve::script::valueFromSquirrel(vm.getHandle(), -1); CHECK(!result.ok()); REQUIRE(result.error() != nullptr); CHECK(static_cast(result.error()->code()) == static_cast(DiagnosticCode::InvalidArgument)); CHECK(result.error()->path() == "$[0]"); CHECK(result.error()->source() == "squirrel.binding"); sq_settop(vm.getHandle(), top); } TEST_CASE("squirrel_binding.value_enforces_depth_limit") { ssq::VM vm(1024, ssq::Libs::ALL); const auto top = sq_gettop(vm.getHandle()); sq_newarray(vm.getHandle(), 0); sq_newarray(vm.getHandle(), 0); REQUIRE(SQ_SUCCEEDED(sq_arrayappend(vm.getHandle(), -2))); eve::script::SquirrelValueOptions options; options.maxDepth = 1; auto result = eve::script::valueFromSquirrel(vm.getHandle(), -1, options); CHECK(!result.ok()); REQUIRE(result.error() != nullptr); CHECK(result.error()->path() == "$[0]"); sq_settop(vm.getHandle(), top); } TEST_CASE("squirrel_binding.result_projection_and_explicit_ignore_are_uniform") { ssq::VM vm(1024, ssq::Libs::ALL); ssq::Table eve = vm.addTable("eve"); eve::script::exposeResultBindings(eve); auto projected = eve::script::projectResult(vm.getHandle(), Result::failure(Diagnostic::error(DiagnosticCode::NotFound, "missing value", "payload.name", {}, "test.source")), [](int value) { return Value(static_cast(value)); }); CHECK(!projected.find("ok").toBool()); CHECK(projected.find("checked").toBool()); CHECK(projected.find("hasValue").toBool() == false); auto diagnostics = projected.find("diagnostics").toArray(); REQUIRE(diagnostics.size() == 1u); const auto diagnostic = diagnostics.get(0); CHECK(diagnostic.find("path").toString() == "payload.name"); CHECK(diagnostic.find("source").toString() == "test.source"); eve.set("target", projected); vm.run(vm.compileSource("ignored <- eve.result.ignore(eve.target, \"optional feature\");\n", "result-ignore-test.nut")); CHECK(vm.find("ignored").toBool()); CHECK(projected.find("ignored").toBool()); CHECK(projected.find("ignoreReason").toString() == "optional feature"); CHECK(eve::script::ignoreResult(projected, "second explicit observation")); }