Fixed unit tests
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user