Fixed unit tests

This commit is contained in:
Michael Schimmel
2025-09-29 12:18:44 +02:00
parent 2b34046efc
commit 18904f17d1
4 changed files with 97 additions and 38 deletions
+51
View File
@@ -38,6 +38,10 @@ type
[Test]
procedure Test_CaptureFromGlobalScope;
[Test]
procedure Test_ClosureCaptureWithParentScopeReallocation;
end;
implementation
@@ -236,4 +240,51 @@ begin
Assert.AreEqual<Int64>(100, resultValue.AsScalar.Value.AsInt64, 'Should be able to access variables from the parent scope.');
end;
procedure TInterpreterScopeTests.Test_ClosureCaptureWithParentScopeReallocation;
var
rootScope: IExecutionScope;
parentScope: IExecutionScope;
lambdaScope: IExecutionScope;
addressOfX_from_lambda: TResolvedAddress;
addressOfX_in_parent: TResolvedAddress;
capturedCell: IValueCell;
valueFromClosure: TDataValue;
begin
// 1. Setup scopes: root -> parent -> lambda
rootScope := TScope.CreateScope(nil, nil, nil);
parentScope := TScope.CreateScope(rootScope, nil, nil);
lambdaScope := TScope.CreateScope(parentScope, nil, nil);
// 2. Define a variable 'x' in the parent scope. It will be at slot 0.
parentScope.Define('x', 10);
addressOfX_in_parent := TResolvedAddress.Create(akLocalOrParent, 0, 0);
Assert.AreEqual(Int64(10), parentScope[addressOfX_in_parent].AsScalar.Value.AsInt64);
// 3. From the lambda's perspective, 'x' is one level up (ScopeDepth=1) at slot 0.
addressOfX_from_lambda := TResolvedAddress.Create(akLocalOrParent, 1, 0);
// 4. Capture 'x' into a value cell, simulating a closure.
// This creates the buggy TValueRef that holds a direct reference to the parent's internal array.
capturedCell := lambdaScope.Capture(addressOfX_from_lambda);
Assert.AreEqual(Int64(10), capturedCell.Value.AsScalar.Value.AsInt64, 'Initial captured value should be correct');
// 5. Trigger the bug: Define another variable in the parent scope.
// This forces a SetLength on the internal FValues array, which may cause a reallocation.
parentScope.Define('y', 20);
// 6. Update the original variable 'x' in the parent scope to a new value.
parentScope[addressOfX_in_parent] := 99;
Assert.AreEqual(Int64(99), parentScope[addressOfX_in_parent].AsScalar.Value.AsInt64, 'Value in parent scope should be updated');
// 7. Read the value from the captured cell again.
// The test will fail here. The captured cell still points to the old, orphaned memory block
// where the value of x is still 10, not the new value 99.
valueFromClosure := capturedCell.Value;
Assert.AreEqual(
Int64(99),
valueFromClosure.AsScalar.Value.AsInt64,
'The captured cell must reflect changes in the parent scope after reallocation'
);
end;
end.