diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2025-10-27 08:43:22 +0100 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2025-10-27 08:43:22 +0100 |
| commit | 5e5bcf37450d07f7f2812255bbd1df35d8e6ce75 (patch) | |
| tree | 14cac4a19d4e35b60f0a56c948f45b158881daa5 | |
| parent | 3b4848ca1c4ea40d0e052cdc81bb9f66ce882a8a (diff) | |
| download | lanes-5e5bcf37450d07f7f2812255bbd1df35d8e6ce75.tar.gz lanes-5e5bcf37450d07f7f2812255bbd1df35d8e6ce75.tar.bz2 lanes-5e5bcf37450d07f7f2812255bbd1df35d8e6ce75.zip | |
verbose_errors improvement
* Use std::format instead of sprintf for verbose errors when decoding table keys
* Add a unit test for the different table key types
| -rw-r--r-- | src/_pch.hpp | 1 | ||||
| -rw-r--r-- | src/intercopycontext.cpp | 23 | ||||
| -rw-r--r-- | tests/lanes_as_upvalue.lua | 2 | ||||
| -rw-r--r-- | unit_tests/UnitTests.vcxproj | 1 | ||||
| -rw-r--r-- | unit_tests/UnitTests.vcxproj.filters | 3 | ||||
| -rw-r--r-- | unit_tests/legacy_tests.cpp | 3 | ||||
| -rw-r--r-- | unit_tests/misc_tests.cpp | 9 | ||||
| -rw-r--r-- | unit_tests/scripts/misc/verbose_errors.lua | 34 |
8 files changed, 62 insertions, 14 deletions
diff --git a/src/_pch.hpp b/src/_pch.hpp index a77b7f5..38489b6 100644 --- a/src/_pch.hpp +++ b/src/_pch.hpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <concepts> | 8 | #include <concepts> |
| 9 | #include <condition_variable> | 9 | #include <condition_variable> |
| 10 | #include <cstring> | 10 | #include <cstring> |
| 11 | #include <format> | ||
| 11 | #include <functional> | 12 | #include <functional> |
| 12 | #include <iostream> | 13 | #include <iostream> |
| 13 | #ifndef __PROSPERO__ | 14 | #ifndef __PROSPERO__ |
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp index 61ce08f..0ccd619 100644 --- a/src/intercopycontext.cpp +++ b/src/intercopycontext.cpp | |||
| @@ -474,29 +474,28 @@ void InterCopyContext::interCopyKeyValuePair() const | |||
| 474 | // for debug purposes, let's try to build a useful name | 474 | // for debug purposes, let's try to build a useful name |
| 475 | if (luaW_type(L1, _key_i) == LuaType::STRING) { | 475 | if (luaW_type(L1, _key_i) == LuaType::STRING) { |
| 476 | std::string_view const _key{ luaW_tostring(L1, _key_i) }; | 476 | std::string_view const _key{ luaW_tostring(L1, _key_i) }; |
| 477 | size_t const _bufLen{ name.size() + _key.size() + 2 }; // +2 for separator dot and terminating 0 | 477 | _valPath = static_cast<char*>(alloca(name.size() + _key.size() + 2)); // +2 for separator dot and terminating 0 |
| 478 | _valPath = static_cast<char*>(alloca(_bufLen)); | 478 | *std::format_to(_valPath, "{}.{}", name, _key) = 0; |
| 479 | sprintf(_valPath, "%s." STRINGVIEW_FMT, name.data(), (int) _key.size(), _key.data()); | ||
| 480 | } | 479 | } |
| 481 | #if defined LUA_LNUM || LUA_VERSION_NUM >= 503 | 480 | #if defined LUA_LNUM || LUA_VERSION_NUM >= 503 |
| 482 | else if (lua_isinteger(L1, _key_i)) { | 481 | else if (lua_isinteger(L1, _key_i)) { |
| 483 | lua_Integer const key{ lua_tointeger(L1, _key_i) }; | 482 | lua_Integer const key{ lua_tointeger(L1, _key_i) }; |
| 484 | _valPath = (char*) alloca(name.size() + 32 + 3); // +3 for [] and terminating 0 | 483 | _valPath = static_cast<char*>(alloca(name.size() + 32 + 3)); // +3 for [] and terminating 0 |
| 485 | sprintf(_valPath, "%s[" LUA_INTEGER_FMT "]", name.data(), key); | 484 | *std::format_to(_valPath, "{}[{}]", name, key) = 0; |
| 486 | } | 485 | } |
| 487 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 | 486 | #endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 |
| 488 | else if (luaW_type(L1, _key_i) == LuaType::NUMBER) { | 487 | else if (luaW_type(L1, _key_i) == LuaType::NUMBER) { |
| 489 | lua_Number const key{ lua_tonumber(L1, _key_i) }; | 488 | lua_Number const key{ lua_tonumber(L1, _key_i) }; |
| 490 | _valPath = (char*) alloca(name.size() + 32 + 3); // +3 for [] and terminating 0 | 489 | _valPath = static_cast<char*>(alloca(name.size() + 32 + 3)); // +3 for [] and terminating 0 |
| 491 | sprintf(_valPath, "%s[" LUA_NUMBER_FMT "]", name.data(), key); | 490 | *std::format_to(_valPath, "{}[{}]", name, key) = 0; |
| 492 | } else if (luaW_type(L1, _key_i) == LuaType::LIGHTUSERDATA) { | 491 | } else if (luaW_type(L1, _key_i) == LuaType::LIGHTUSERDATA) { |
| 493 | void* const _key{ lua_touserdata(L1, _key_i) }; | 492 | void* const _key{ lua_touserdata(L1, _key_i) }; |
| 494 | _valPath = (char*) alloca(name.size() + 16 + 5); // +5 for [U:] and terminating 0 | 493 | _valPath = static_cast<char*>(alloca(name.size() + 16 + 5)); // +5 for [U:] and terminating 0 |
| 495 | sprintf(_valPath, "%s[U:%p]", name.data(), _key); | 494 | *std::format_to(_valPath, "{}[U:{}]", name, _key) = 0; |
| 496 | } else if (luaW_type(L1, _key_i) == LuaType::BOOLEAN) { | 495 | } else if (luaW_type(L1, _key_i) == LuaType::BOOLEAN) { |
| 497 | int const _key{ lua_toboolean(L1, _key_i) }; | 496 | int const _key{ lua_toboolean(L1, _key_i) }; |
| 498 | _valPath = (char*) alloca(name.size() + 8); // +8 for [], 'false' and terminating 0 | 497 | _valPath = static_cast<char*>(alloca(name.size() + 8)); // +8 for [], 'false' and terminating 0 |
| 499 | sprintf(_valPath, "%s[%s]", name.data(), _key ? "true" : "false"); | 498 | *std::format_to(_valPath, "{}[{}]", name, _key ? "true" : "false") = 0; |
| 500 | } | 499 | } |
| 501 | } | 500 | } |
| 502 | 501 | ||
| @@ -1430,7 +1429,7 @@ InterCopyResult InterCopyContext::interCopy(int const n_) const | |||
| 1430 | for (StackIndex _i{ (L1_i != 0) ? L1_i.value() : (_top_L1 - n_ + 1) }, _j{ 1 }; _j <= n_; ++_i, ++_j) { | 1429 | for (StackIndex _i{ (L1_i != 0) ? L1_i.value() : (_top_L1 - n_ + 1) }, _j{ 1 }; _j <= n_; ++_i, ++_j) { |
| 1431 | char _tmpBuf[16]; | 1430 | char _tmpBuf[16]; |
| 1432 | if (U->verboseErrors) { | 1431 | if (U->verboseErrors) { |
| 1433 | sprintf(_tmpBuf, "arg_%d", _j.value()); | 1432 | *std::format_to(_tmpBuf, "arg#{}", _j.value()) = 0; |
| 1434 | _c.name = _tmpBuf; | 1433 | _c.name = _tmpBuf; |
| 1435 | } | 1434 | } |
| 1436 | _c.L1_i = SourceIndex{ _i.value() }; | 1435 | _c.L1_i = SourceIndex{ _i.value() }; |
diff --git a/tests/lanes_as_upvalue.lua b/tests/lanes_as_upvalue.lua index beef22e..1c316e4 100644 --- a/tests/lanes_as_upvalue.lua +++ b/tests/lanes_as_upvalue.lua | |||
| @@ -8,4 +8,4 @@ local g = lanes.gen( "*", { name = 'auto', error_trace_level = "extended"}, foo) | |||
| 8 | 8 | ||
| 9 | -- this should raise an error as lanes.timer_lane is a Lane (a non-deep full userdata) | 9 | -- this should raise an error as lanes.timer_lane is a Lane (a non-deep full userdata) |
| 10 | local res, err = pcall( g) | 10 | local res, err = pcall( g) |
| 11 | print( "Generating lane yielded: ", tostring( res), tostring( err)) | 11 | assert(res == false and type(err) == "string", "got " .. tostring(res) .. " " .. tostring(err)) |
diff --git a/unit_tests/UnitTests.vcxproj b/unit_tests/UnitTests.vcxproj index 300eb9b..bb0a2af 100644 --- a/unit_tests/UnitTests.vcxproj +++ b/unit_tests/UnitTests.vcxproj | |||
| @@ -1163,6 +1163,7 @@ | |||
| 1163 | <None Include="scripts\linda\send_receive_tables.lua" /> | 1163 | <None Include="scripts\linda\send_receive_tables.lua" /> |
| 1164 | <None Include="scripts\linda\wake_period.lua" /> | 1164 | <None Include="scripts\linda\wake_period.lua" /> |
| 1165 | <None Include="scripts\misc\deeptest.lua" /> | 1165 | <None Include="scripts\misc\deeptest.lua" /> |
| 1166 | <None Include="scripts\misc\verbose_errors.lua" /> | ||
| 1166 | <None Include="scripts\_utils54.lua" /> | 1167 | <None Include="scripts\_utils54.lua" /> |
| 1167 | <None Include="UnitTests.makefile" /> | 1168 | <None Include="UnitTests.makefile" /> |
| 1168 | <None Include="scripts\coro\index_suspended.lua" /> | 1169 | <None Include="scripts\coro\index_suspended.lua" /> |
diff --git a/unit_tests/UnitTests.vcxproj.filters b/unit_tests/UnitTests.vcxproj.filters index 57d8918..9b3d023 100644 --- a/unit_tests/UnitTests.vcxproj.filters +++ b/unit_tests/UnitTests.vcxproj.filters | |||
| @@ -159,5 +159,8 @@ | |||
| 159 | <None Include="scripts\linda\send_receive_tables.lua"> | 159 | <None Include="scripts\linda\send_receive_tables.lua"> |
| 160 | <Filter>Scripts\linda</Filter> | 160 | <Filter>Scripts\linda</Filter> |
| 161 | </None> | 161 | </None> |
| 162 | <None Include="scripts\misc\verbose_errors.lua"> | ||
| 163 | <Filter>Scripts\misc</Filter> | ||
| 164 | </None> | ||
| 162 | </ItemGroup> | 165 | </ItemGroup> |
| 163 | </Project> \ No newline at end of file | 166 | </Project> \ No newline at end of file |
diff --git a/unit_tests/legacy_tests.cpp b/unit_tests/legacy_tests.cpp index 84581d2..d66937c 100644 --- a/unit_tests/legacy_tests.cpp +++ b/unit_tests/legacy_tests.cpp | |||
| @@ -33,7 +33,8 @@ MAKE_TEST_CASE(func_is_string) | |||
| 33 | MAKE_TEST_CASE(irayo_closure) | 33 | MAKE_TEST_CASE(irayo_closure) |
| 34 | MAKE_TEST_CASE(irayo_recursive) | 34 | MAKE_TEST_CASE(irayo_recursive) |
| 35 | MAKE_TEST_CASE(keeper) | 35 | MAKE_TEST_CASE(keeper) |
| 36 | //MAKE_TEST_CASE(linda_perf) | 36 | MAKE_TEST_CASE(lanes_as_upvalue) |
| 37 | // MAKE_TEST_CASE(linda_perf) | ||
| 37 | MAKE_TEST_CASE(manual_register) | 38 | MAKE_TEST_CASE(manual_register) |
| 38 | MAKE_TEST_CASE(nameof) | 39 | MAKE_TEST_CASE(nameof) |
| 39 | MAKE_TEST_CASE(objects) | 40 | MAKE_TEST_CASE(objects) |
diff --git a/unit_tests/misc_tests.cpp b/unit_tests/misc_tests.cpp index a2199aa..3848a75 100644 --- a/unit_tests/misc_tests.cpp +++ b/unit_tests/misc_tests.cpp | |||
| @@ -191,3 +191,12 @@ TEST_CASE("misc.convert_max_attempts.is_respected") | |||
| 191 | " l:send('k', t)" // send the table, it should raise an error because the converter retries too many times | 191 | " l:send('k', t)" // send the table, it should raise an error because the converter retries too many times |
| 192 | ); | 192 | ); |
| 193 | } | 193 | } |
| 194 | |||
| 195 | #define MAKE_TEST_CASE(DIR, FILE, CONDITION) \ | ||
| 196 | TEST_CASE("scripted_tests." #DIR "." #FILE) \ | ||
| 197 | { \ | ||
| 198 | FileRunner _runner(R"(.\unit_tests\scripts)"); \ | ||
| 199 | _runner.performTest(FileRunnerParam{ #DIR "/" #FILE, TestType::CONDITION }); \ | ||
| 200 | } | ||
| 201 | |||
| 202 | MAKE_TEST_CASE(misc, verbose_errors, AssertNoLuaError) | ||
diff --git a/unit_tests/scripts/misc/verbose_errors.lua b/unit_tests/scripts/misc/verbose_errors.lua new file mode 100644 index 0000000..40948ca --- /dev/null +++ b/unit_tests/scripts/misc/verbose_errors.lua | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | local fixture = require "fixture" -- require fixture before lanes so that it is not registered and will cause transfer errors | ||
| 2 | local lanes = require("lanes").configure{verbose_errors = true} | ||
| 3 | local l = lanes.linda{name = "my linda"} | ||
| 4 | |||
| 5 | |||
| 6 | local do_test = function(key_) | ||
| 7 | local t = {[key_] = fixture.newuserdata()} | ||
| 8 | local b, e = pcall(l.send, l, "k", t) | ||
| 9 | assert(b == false and type(e) == "string") | ||
| 10 | local t_key = type(key_) | ||
| 11 | if t_key == "string" then | ||
| 12 | local x, y = string.find(e, "arg#2." .. key_, 1, true) | ||
| 13 | assert(x and y, "got " .. e) | ||
| 14 | elseif t_key == "boolean" then | ||
| 15 | local x, y = string.find(e, "arg#2[" .. tostring(key_) .. "]", 1, true) | ||
| 16 | assert(x and y, "got " .. e) | ||
| 17 | elseif t_key == "number" then | ||
| 18 | local x, y = string.find(e, "arg#2[" .. key_ .. "]", 1, true) | ||
| 19 | assert(x and y, "got " .. e) | ||
| 20 | elseif t_key == "userdata" then | ||
| 21 | local t_name | ||
| 22 | -- light userdata is formatted by std::format, where the pointer is written as a lowercase hex literal | ||
| 23 | local expected = "arg#2[U:0x" .. string.lower(string.match(tostring(key_), "userdata: (%x+)")) .. "]" | ||
| 24 | local x, y = string.find(e, expected, 1, true) | ||
| 25 | assert(x and y, "expecting " .. expected .. " got " .. e) | ||
| 26 | end | ||
| 27 | end | ||
| 28 | |||
| 29 | do_test("bob") | ||
| 30 | do_test(true) | ||
| 31 | do_test(false) | ||
| 32 | do_test(42) | ||
| 33 | do_test(42.44) | ||
| 34 | do_test(lanes.null) | ||
