Skip to content

Commit c336ee8

Browse files
committed
Restore global error forwarding and document Linux test setup
1 parent 3a0ac43 commit c336ee8

File tree

7 files changed

+332
-32
lines changed

7 files changed

+332
-32
lines changed

AGENTS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ If you need more control or the Makefile doesn't meet your needs:
7373
/Applications/tool4d.app/Contents/MacOS/tool4d --project $(PWD)/testing/Project/testing.4DProject --skip-onstartup --dataless --startup-method "test" --user-param "format=junit"
7474
```
7575

76+
### Linux setup notes
77+
78+
- See [docs/running-tests-linux.md](docs/running-tests-linux.md) for a step-by-step walkthrough of provisioning the experimental Linux build of **tool4d**.
79+
- Running `make test` on Linux installs the required system libraries (`libc++1`, `uuid-runtime`, `libfreeimage3`, `xdg-user-dirs`, `libtinfo5`, `libncurses5`) and downloads `tool4d` to `/opt/tool4d` before executing the suite.
80+
- Use `make tool4d` when you only need to bootstrap the runtime without immediately running the tests.
81+
- After installation you can invoke `/opt/tool4d/tool4d --project ... --user-param "excludeTags=no-linux"` directly for manual, headless runs.
82+
7683
### Test Filtering Parameters
7784

7885
```bash

testing/Project/Sources/Classes/TestRunner.4dm

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ Function _prepareErrorHandlingStorage()
3737
Else
3838
Storage:C1525.testErrorHandlerProcesses.clear()
3939
End if
40+
41+
Storage:C1525.testErrorHandlerForwarding:=New shared object:C1526(\
42+
"local"; New shared object:C1526; \
43+
"global"; New shared object:C1526(\
44+
"handler"; ""; \
45+
"shouldForward"; False:C215; \
46+
"installedProcess"; 0\
47+
)\
48+
)
4049
End use
4150

4251
Function _runInternal()
@@ -79,12 +88,21 @@ Function _installErrorHandler() : Object
7988
ON ERR CALL:C155("TestErrorHandler")
8089
End if
8190

82-
$currentProcess:=Current process:C322
83-
TestErrorHandlerRegisterProcess($currentProcess)
84-
8591
$previousGlobalHandler:=Method called on error:C704(1)
8692
$shouldInstallGlobal:=($previousGlobalHandler#"TestErrorHandler")
8793

94+
$currentProcess:=Current process:C322
95+
96+
var $registerOptions : Object
97+
$registerOptions:=New object:C1471(\
98+
"previousLocalHandler"; $previousErrorHandler; \
99+
"forwardLocal"; $shouldInstallLocal; \
100+
"previousGlobalHandler"; $previousGlobalHandler; \
101+
"forwardGlobal"; $shouldInstallGlobal\
102+
)
103+
104+
TestErrorHandlerRegisterProcess($currentProcess; $registerOptions)
105+
88106
If ($shouldInstallGlobal)
89107
ON ERR CALL:C155("TestErrorHandler"; 1)
90108
End if
@@ -105,7 +123,13 @@ Function _restoreErrorHandler($handlerState : Object)
105123

106124
var $processNumber : Integer
107125
$processNumber:=$handlerState.processNumber || Current process:C322
108-
TestErrorHandlerUnregister($processNumber)
126+
127+
var $unregisterOptions : Object
128+
$unregisterOptions:=New object:C1471(\
129+
"clearGlobal"; $handlerState.installedGlobalHandler\
130+
)
131+
132+
TestErrorHandlerUnregister($processNumber; $unregisterOptions)
109133

110134
var $restoreLocal : Boolean
111135
$restoreLocal:=($handlerState.installedLocalHandler#Null:C1517) ? $handlerState.installedLocalHandler : $handlerState.installedNewHandler

testing/Project/Sources/Classes/_ErrorHandlingTest.4dm

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@
22
Class constructor()
33

44
Function test_error_handler_initialization($t : cs:C1710.Testing)
5-
6-
// Verify that Storage.testErrors exists and can be initialized
7-
If (Storage:C1525.testErrors=Null:C1517)
8-
Use (Storage:C1525)
9-
Storage:C1525.testErrors:=New shared collection:C1527
10-
End use
11-
End if
12-
13-
$t.assert.isNotNull($t; Storage:C1525.testErrors; "Error storage should be initialized")
14-
$t.assert.areEqual($t; Is collection:K8:32; Value type:C1509(Storage:C1525.testErrors); "Error storage should be a collection")
5+
6+
var $runner : cs:C1710.TestRunner
7+
$runner:=cs:C1710.TestRunner.new()
8+
$runner._prepareErrorHandlingStorage()
9+
10+
// Verify that Storage.testErrors exists and can be initialized
11+
$t.assert.isNotNull($t; Storage:C1525.testErrors; "Error storage should be initialized")
12+
$t.assert.areEqual($t; Is collection:K8:32; Value type:C1509(Storage:C1525.testErrors); "Error storage should be a collection")
13+
14+
// Ensure forwarding state is set up
15+
$t.assert.isNotNull($t; Storage:C1525.testErrorHandlerForwarding; "Forwarding registry should be initialized")
16+
$t.assert.areEqual($t; Is object:K8:27; Value type:C1509(Storage:C1525.testErrorHandlerForwarding); "Forwarding registry should be an object")
17+
18+
Use (Storage:C1525.testErrorHandlerForwarding)
19+
$t.assert.isNotNull($t; Storage:C1525.testErrorHandlerForwarding.local; "Local forwarding map should exist")
20+
$t.assert.areEqual($t; Is object:K8:27; Value type:C1509(Storage:C1525.testErrorHandlerForwarding.local); "Local forwarding map should be an object")
21+
$t.assert.isNotNull($t; Storage:C1525.testErrorHandlerForwarding.global; "Global forwarding state should exist")
22+
$t.assert.areEqual($t; Is object:K8:27; Value type:C1509(Storage:C1525.testErrorHandlerForwarding.global); "Global forwarding state should be an object")
23+
End use
1524

1625
Function test_error_information_structure($t : cs:C1710.Testing)
1726

@@ -101,18 +110,66 @@ Function test_register_process_tracking($t : cs:C1710.Testing)
101110
var $processNumber : Integer
102111
$processNumber:=98765
103112

104-
TestErrorHandlerRegisterProcess($processNumber)
113+
var $registerOptions : Object
114+
$registerOptions:=New object:C1471(\
115+
"previousLocalHandler"; "LegacyLocalHandler"; \
116+
"forwardLocal"; True:C214; \
117+
"previousGlobalHandler"; "LegacyGlobalHandler"; \
118+
"forwardGlobal"; True:C214\
119+
)
120+
121+
TestErrorHandlerRegisterProcess($processNumber; $registerOptions)
105122

106123
Use (Storage:C1525.testErrorHandlerProcesses)
107124
$t.assert.isTrue($t; Storage:C1525.testErrorHandlerProcesses.indexOf($processNumber)>=0; "Should register process for local error tracking")
108125
End use
109126

110-
TestErrorHandlerUnregister($processNumber)
127+
Use (Storage:C1525.testErrorHandlerForwarding)
128+
var $localEntry : Object
129+
$localEntry:=Storage:C1525.testErrorHandlerForwarding.local[String:C10($processNumber)]
130+
$t.assert.isNotNull($t; $localEntry; "Should create local forwarding entry")
131+
If ($localEntry#Null:C1517)
132+
$t.assert.areEqual($t; "LegacyLocalHandler"; $localEntry.handler; "Should track previous local handler")
133+
$t.assert.isTrue($t; $localEntry.shouldForward; "Local forwarding should be enabled")
134+
End if
135+
136+
var $globalState : Object
137+
$globalState:=Storage:C1525.testErrorHandlerForwarding.global
138+
$t.assert.isNotNull($t; $globalState; "Should maintain global forwarding state")
139+
If ($globalState#Null:C1517)
140+
$t.assert.areEqual($t; "LegacyGlobalHandler"; $globalState.handler; "Should track previous global handler")
141+
$t.assert.isTrue($t; $globalState.shouldForward; "Global forwarding should be enabled")
142+
$t.assert.areEqual($t; $processNumber; $globalState.installedProcess; "Should record installing process")
143+
End if
144+
End use
145+
146+
var $unregisterOptions : Object
147+
$unregisterOptions:=New object:C1471(\
148+
"clearGlobal"; True:C214\
149+
)
150+
151+
TestErrorHandlerUnregister($processNumber; $unregisterOptions)
111152

112153
Use (Storage:C1525.testErrorHandlerProcesses)
113154
$t.assert.isFalse($t; Storage:C1525.testErrorHandlerProcesses.indexOf($processNumber)>=0; "Should remove process from tracking after unregister")
114155
End use
115156

157+
Use (Storage:C1525.testErrorHandlerForwarding)
158+
var $localEntryAfter : Object
159+
$localEntryAfter:=Storage:C1525.testErrorHandlerForwarding.local[String:C10($processNumber)]
160+
If ($localEntryAfter#Null:C1517)
161+
$t.assert.areEqual($t; ""; $localEntryAfter.handler; "Local handler reference should be cleared on unregister")
162+
$t.assert.isFalse($t; $localEntryAfter.shouldForward; "Local forwarding should be disabled on unregister")
163+
End if
164+
165+
var $globalStateAfter : Object
166+
$globalStateAfter:=Storage:C1525.testErrorHandlerForwarding.global
167+
If ($globalStateAfter#Null:C1517)
168+
$t.assert.isFalse($t; $globalStateAfter.shouldForward; "Global forwarding should be disabled after unregister")
169+
$t.assert.areEqual($t; 0; $globalStateAfter.installedProcess; "Global installer should reset after unregister")
170+
End if
171+
End use
172+
116173
Function test_testing_context_properties($t : cs:C1710.Testing)
117174

118175
// Verify the testing context has expected properties

testing/Project/Sources/Methods/ParallelTestWorker.4dm

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ Case of
2424
$previousErrorHandler:=Method called on error:C704
2525
$shouldInstallHandler:=($previousErrorHandler#"TestErrorHandler")
2626

27+
var $registerOptions : Object
28+
$registerOptions:=New object:C1471(\
29+
"previousLocalHandler"; $previousErrorHandler; \
30+
"forwardLocal"; $shouldInstallHandler; \
31+
"previousGlobalHandler"; ""; \
32+
"forwardGlobal"; False:C215\
33+
)
34+
2735
var $handlerState : Object
2836
Use (Storage:C1525)
2937
If (Storage:C1525.parallelWorkerHandlerStates=Null:C1517)
@@ -49,7 +57,7 @@ Case of
4957
$handlerState.changed:=$shouldInstallHandler
5058
$handlerState.installed:=True:C214
5159
If (Not:C34($handlerState.registered))
52-
TestErrorHandlerRegisterProcess(Current process:C322)
60+
TestErrorHandlerRegisterProcess(Current process:C322; $registerOptions)
5361
$handlerState.registered:=True:C214
5462
End if
5563
End if

testing/Project/Sources/Methods/TestErrorHandler.4dm

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//%attributes = {}
22
// TestErrorHandler
33
// Global error handler for the testing framework
4-
// Captures runtime errors to prevent test interruption
4+
// Captures runtime errors, stores metadata, and forwards to previous handlers when necessary
55

66
var $errorCode : Integer
77
var $errorText : Text
@@ -10,28 +10,72 @@ var $errorLine : Integer
1010
var $processNumber : Integer
1111
var $isLocalProcess : Boolean
1212
var $context : Text
13+
var $previousHandler : Text
14+
var $shouldForward : Boolean
1315

1416
$errorCode:=Error
1517
$errorText:=Error method
1618
$errorMethod:=Error formula
1719
$errorLine:=Error line
1820
$processNumber:=Current process:C322
1921
$isLocalProcess:=False:C215
22+
$previousHandler:=""
23+
$shouldForward:=False:C215
2024

2125
If (Storage:C1525.testErrorHandlerProcesses#Null:C1517)
2226
Use (Storage:C1525.testErrorHandlerProcesses)
2327
$isLocalProcess:=(Storage:C1525.testErrorHandlerProcesses.indexOf($processNumber)>=0)
2428
End use
2529
End if
2630

31+
var $forwardingState : Object
32+
Use (Storage:C1525)
33+
$forwardingState:=Storage:C1525.testErrorHandlerForwarding
34+
End use
35+
36+
If ($forwardingState#Null:C1517)
37+
If ($isLocalProcess)
38+
var $localMap : Object
39+
Use ($forwardingState)
40+
$localMap:=$forwardingState.local
41+
End use
42+
43+
If ($localMap#Null:C1517)
44+
var $localEntry : Object
45+
Use ($localMap)
46+
$localEntry:=$localMap[String:C10($processNumber)]
47+
End use
48+
49+
If ($localEntry#Null:C1517)
50+
Use ($localEntry)
51+
$previousHandler:=$localEntry.handler || ""
52+
$shouldForward:=Bool:C1537($localEntry.shouldForward)
53+
End use
54+
End if
55+
End if
56+
Else
57+
var $globalState : Object
58+
Use ($forwardingState)
59+
$globalState:=$forwardingState.global
60+
End use
61+
62+
If ($globalState#Null:C1517)
63+
Use ($globalState)
64+
$previousHandler:=$globalState.handler || ""
65+
$shouldForward:=Bool:C1537($globalState.shouldForward)
66+
End use
67+
End if
68+
End if
69+
End if
70+
2771
$context:=Choose:C955($isLocalProcess; "local"; "global")
2872

2973
// Store error information in Storage for later retrieval
3074
If (Storage:C1525.testErrors=Null:C1517)
3175
Use (Storage:C1525)
3276
Storage:C1525.testErrors:=New shared collection:C1527
33-
End use
34-
End if
77+
End use
78+
End if
3579

3680
var $errorInfo : Object
3781
$errorInfo:=New object:C1471(\
@@ -49,4 +93,8 @@ Use (Storage:C1525.testErrors)
4993
Storage:C1525.testErrors.push(OB Copy:C1225($errorInfo; ck shared:K85:29))
5094
End use
5195

96+
If ($shouldForward) && ($previousHandler#"") && ($previousHandler#"TestErrorHandler")
97+
EXECUTE METHOD:C1007($previousHandler)
98+
End if
99+
52100
// Continue execution - don't interrupt the test

0 commit comments

Comments
 (0)