aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2025-10-27 08:43:22 +0100
committerBenoit Germain <benoit.germain@ubisoft.com>2025-10-27 08:43:22 +0100
commit5e5bcf37450d07f7f2812255bbd1df35d8e6ce75 (patch)
tree14cac4a19d4e35b60f0a56c948f45b158881daa5
parent3b4848ca1c4ea40d0e052cdc81bb9f66ce882a8a (diff)
downloadlanes-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.hpp1
-rw-r--r--src/intercopycontext.cpp23
-rw-r--r--tests/lanes_as_upvalue.lua2
-rw-r--r--unit_tests/UnitTests.vcxproj1
-rw-r--r--unit_tests/UnitTests.vcxproj.filters3
-rw-r--r--unit_tests/legacy_tests.cpp3
-rw-r--r--unit_tests/misc_tests.cpp9
-rw-r--r--unit_tests/scripts/misc/verbose_errors.lua34
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)
10local res, err = pcall( g) 10local res, err = pcall( g)
11print( "Generating lane yielded: ", tostring( res), tostring( err)) 11assert(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)
33MAKE_TEST_CASE(irayo_closure) 33MAKE_TEST_CASE(irayo_closure)
34MAKE_TEST_CASE(irayo_recursive) 34MAKE_TEST_CASE(irayo_recursive)
35MAKE_TEST_CASE(keeper) 35MAKE_TEST_CASE(keeper)
36//MAKE_TEST_CASE(linda_perf) 36MAKE_TEST_CASE(lanes_as_upvalue)
37// MAKE_TEST_CASE(linda_perf)
37MAKE_TEST_CASE(manual_register) 38MAKE_TEST_CASE(manual_register)
38MAKE_TEST_CASE(nameof) 39MAKE_TEST_CASE(nameof)
39MAKE_TEST_CASE(objects) 40MAKE_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
202MAKE_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 @@
1local fixture = require "fixture" -- require fixture before lanes so that it is not registered and will cause transfer errors
2local lanes = require("lanes").configure{verbose_errors = true}
3local l = lanes.linda{name = "my linda"}
4
5
6local 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
27end
28
29do_test("bob")
30do_test(true)
31do_test(false)
32do_test(42)
33do_test(42.44)
34do_test(lanes.null)