1+ -- As the name implies, finds the last occurrence of the given needle
2+ local function findLast ( haystack , needle )
3+ local lastPos = string.find ( haystack , needle , nil , true )
4+ local nextPos = lastPos and string.find ( haystack , needle , lastPos + 1 , true )
5+ while nextPos ~= nil do
6+ lastPos = nextPos
7+ nextPos = string.find ( haystack , needle , lastPos + 1 , true )
8+ end
9+
10+ return lastPos
11+ end
12+
13+ -- Removes ( and ) without breaking stuff hopefully
14+ -- This means you can do crazy stuff like expect( test123(test456(test789(123))) ) which will be stripped to just test123
15+ local function removeBraces ( line )
16+ local findStartPos = findLast ( line , " (" )
17+ while findStartPos do
18+ local findEndPos = string.find ( line , " )" , findStartPos + 1 )
19+ if not findEndPos then break end
20+
21+ line = string .Trim ( line :sub ( 0 , findStartPos - 1 ) .. line :sub ( findEndPos + 1 ) )
22+
23+ findStartPos = findLast ( line , " (" )
24+ end
25+
26+ return line
27+ end
28+
29+
30+ --[[
31+ Name recovery function for expect( test.123 )
32+ to retrieve 123 so that functions like errWith will work properly if given directly the function that will error
33+
34+ This is mainly required due to Lua losing track of the caller function resulting in '?' inside an error message
35+ you could always wrap it like this to workaround this issue: local testFunc = function(...) test.123(...) end
36+ Using which this entire stuff would not be necessary, as then the function you pass to pcall will not be the one erroring.
37+ and since you call your function inside of it, Lua still knows the name of it, causing errWith to work properly.
38+ ]]
39+ local function GetExpectationSubjectName ( additionalShift )
40+ additionalShift = additionalShift or 0
41+ -- We gotta figure out the caller name as its lost when we get called as it isn't kept track off
42+ local ourDebugInfo = debug.getinfo ( 2 + additionalShift , " n" ) -- Makes copy-pasting this easier (also allows us to move this somewhere else later)
43+ local callerDebugInfo = debug.getinfo ( 3 + additionalShift , " Sln" ) -- 3 = caller, 2 = expect.errWith or such, 1 = us
44+ if callerDebugInfo and ourDebugInfo and ourDebugInfo .name ~= " " and callerDebugInfo .currentline ~= 1 then
45+ -- ToDo: Cache the file content to reduce filesystem usage (Could quickly escalate, slowing everything down immensely)
46+ local fileHandle = file .Open ( callerDebugInfo .short_src , " rb" , " GAME" ) --[[ @as File]]
47+ if fileHandle then
48+ -- Skipping to our current line
49+ for _ = 1 , callerDebugInfo .currentline - 1 do
50+ fileHandle :ReadLine ()
51+ end
52+ local line = string .Trim ( fileHandle :ReadLine () )
53+ fileHandle :Close () -- No longer need our handle
54+
55+ -- Remove expected
56+ local _ , findPos = string.find ( line , " expect" )
57+ if findPos then
58+ line = string .Trim ( line :sub ( findPos + 1 ) )
59+ end
60+
61+ -- Remove everything after "errWith" including itself
62+ findPos = string.find ( line , ourDebugInfo .name )
63+ if findPos then
64+ line = string .Trim ( line :sub ( 0 , findPos - 1 ) )
65+ end
66+
67+ -- First remove the left over . from ".errWith" as we only removed errWith
68+ findPos = findLast ( line , " ." )
69+ if findPos then
70+ line = string .Trim ( line :sub ( 0 , findPos - 1 ) )
71+ end
72+
73+ -- Now remove the ".to"
74+ findPos = findLast ( line , " ." )
75+ if findPos then
76+ line = string .Trim ( line :sub ( 0 , findPos - 1 ) )
77+ end
78+
79+ -- Remove leftover "(" wrapping
80+ if line :StartsWith ( " (" ) then
81+ line = string .Trim ( line :sub ( 2 ) )
82+ end
83+
84+ -- Remove leftover ")" wrapping
85+ if line :EndsWith ( " )" ) then
86+ line = string .Trim ( line :sub ( 0 , line :len () - 1 ) )
87+ end
88+
89+ line = removeBraces ( line )
90+
91+ -- Now, finally remove the the rest in case it had arguments like expect( test123, 123 )
92+ findPos = string.find ( line , " ," )
93+ if findPos then
94+ line = string .Trim ( line :sub ( 0 , findPos - 1 ) )
95+ end
96+
97+ findPos = findLast ( line , " ." )
98+ if findPos then
99+ line = string .Trim ( line :sub ( findPos + 1 ) )
100+ end
101+
102+ findPos = findLast ( line , " :" )
103+ if findPos then
104+ line = string .Trim ( line :sub ( findPos + 1 ) )
105+ end
106+
107+ return line
108+ end
109+ end
110+
111+ return " ?"
112+ end
113+
114+ local function DoPCallWithSubject ( subject , ... )
115+ local callerName = GetExpectationSubjectName ( 1 ) -- 1 since this function also shifts things again
116+
117+ __GLUA_RUN = {} -- To not conflict and to avoid setting up an entire fenv
118+ local callSubject = callerName ~= " ?" and CompileString ( [[ __GLUA_RUN.]] .. callerName .. [[ ( ... )]] , " " , false ) or subject
119+ -- Instead of doing __GLUA_RUN_callerName, we do __GLUA_RUN.callerName
120+ -- so that the name won't be modified in the resulting error messsage as it ignores the table name
121+ __GLUA_RUN [callerName ] = subject
122+
123+ local success , err = pcall ( callSubject , ... )
124+ __GLUA_RUN = nil -- Cleanup :^
125+
126+ -- This can exist because of the use of CompileString, so nuke it
127+ if err and err :StartsWith ( " :1: " ) then
128+ err = err :sub ( 5 )
129+ end
130+
131+ return success , err
132+ end
133+
134+ return DoPCallWithSubject
0 commit comments