Pipes and test scripts
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
unit Test.Myc.Ast.Integration;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
System.IOUtils,
|
||||
System.TypInfo,
|
||||
System.Generics.Collections,
|
||||
DUnitX.TestFramework,
|
||||
// Core
|
||||
Myc.Data.Value,
|
||||
Myc.Ast.Environment,
|
||||
Myc.Ast.Script,
|
||||
Myc.Ast.Nodes; // For Exception handling
|
||||
|
||||
type
|
||||
[TestFixture]
|
||||
TTestIntegration = class
|
||||
private
|
||||
const
|
||||
TEST_DIR = 'T:\Myc\Test\Scripts';
|
||||
|
||||
procedure RunSingleScript(const FileName: string);
|
||||
function ParseKind(const KindStr: string): TDataValueKind;
|
||||
public
|
||||
[Setup]
|
||||
procedure Setup;
|
||||
|
||||
[Test]
|
||||
[IgnoreMemoryLeaks]
|
||||
procedure RunAllFileBasedTests;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TTestIntegration }
|
||||
|
||||
procedure TTestIntegration.Setup;
|
||||
begin
|
||||
// Ensure the directory exists to avoid immediate crash
|
||||
if not TDirectory.Exists(TEST_DIR) then
|
||||
ForceDirectories(TEST_DIR);
|
||||
end;
|
||||
|
||||
function TTestIntegration.ParseKind(const KindStr: string): TDataValueKind;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
// Uses RTTI/TypInfo to convert string 'vkScalar' to enum TDataValueKind.vkScalar
|
||||
I := GetEnumValue(TypeInfo(TDataValueKind), KindStr);
|
||||
if I < 0 then
|
||||
raise Exception.CreateFmt('Unknown TDataValueKind in test header: %s', [KindStr]);
|
||||
Result := TDataValueKind(I);
|
||||
end;
|
||||
|
||||
procedure TTestIntegration.RunSingleScript(const FileName: string);
|
||||
var
|
||||
Lines: TArray<string>;
|
||||
ScriptSource: TStringBuilder;
|
||||
ExpectedOutput, ExpectedSignature: string; // <-- Neu
|
||||
ExpectedTypeStr: string;
|
||||
ExpectedType: TDataValueKind;
|
||||
HasExpectation: Boolean;
|
||||
Line: string;
|
||||
|
||||
Env: TAstEnvironment;
|
||||
ResultValue: TDataValue;
|
||||
|
||||
// AST Variablen für die Analyse
|
||||
RootNode, BoundNode, SpecializedNode: IAstNode;
|
||||
ActualSignature: string;
|
||||
begin
|
||||
Lines := TFile.ReadAllLines(FileName);
|
||||
ScriptSource := TStringBuilder.Create;
|
||||
try
|
||||
ExpectedOutput := '';
|
||||
ExpectedSignature := ''; // <-- Init
|
||||
ExpectedTypeStr := '';
|
||||
ExpectedType := TDataValueKind.vkVoid;
|
||||
HasExpectation := False;
|
||||
|
||||
// 1. Parsing (angepasst für SIGNATURE)
|
||||
for Line in Lines do
|
||||
begin
|
||||
if Line.Trim.StartsWith(';; EXPECT:') then
|
||||
begin
|
||||
ExpectedOutput := Line.Substring(10).Trim;
|
||||
HasExpectation := True;
|
||||
end
|
||||
else if Line.Trim.StartsWith(';; TYPE:') then
|
||||
begin
|
||||
ExpectedTypeStr := Line.Substring(8).Trim;
|
||||
ExpectedType := ParseKind(ExpectedTypeStr);
|
||||
end
|
||||
else if Line.Trim.StartsWith(';; SIGNATURE:') then // <-- Neu
|
||||
begin
|
||||
ExpectedSignature := Line.Substring(13).Trim;
|
||||
end
|
||||
else
|
||||
begin
|
||||
ScriptSource.AppendLine(Line);
|
||||
end;
|
||||
end;
|
||||
|
||||
if not HasExpectation then
|
||||
Assert.Fail('Test file missing ";; EXPECT:" tag: ' + FileName);
|
||||
|
||||
// 2. Environment Setup
|
||||
Env := TAstEnvironment.Construct(nil);
|
||||
Env.SetStandardMode;
|
||||
|
||||
// 3. Parse AST
|
||||
RootNode := TAstScript.Parse(ScriptSource.ToString);
|
||||
|
||||
// --- SIGNATURE CHECK START ---
|
||||
if ExpectedSignature <> '' then
|
||||
begin
|
||||
try
|
||||
// Wir simulieren die Pipeline bis zum Type-Check
|
||||
// Hinweis: Env.Bind führt intern oft schon Namensauflösung und TypeCheck durch.
|
||||
// Env.Specialize löst generische Aufrufe auf und finalisiert Typen.
|
||||
|
||||
// A. Bind (Namensauflösung & TypeCheck)
|
||||
// Wir übergeben einen Dummy-Log, oder nil wenn erlaubt
|
||||
BoundNode := Env.Bind(RootNode, [], nil);
|
||||
|
||||
// B. Specialize (Optimierung & finale Typisierung)
|
||||
SpecializedNode := Env.Specialize(BoundNode);
|
||||
|
||||
// C. Typ extrahieren
|
||||
if SpecializedNode.IsTyped then
|
||||
begin
|
||||
ActualSignature := SpecializedNode.AsTypedNode.StaticType.ToString;
|
||||
|
||||
Assert
|
||||
.AreEqual(ExpectedSignature, ActualSignature, Format('File: %s - Signature Mismatch', [ExtractFileName(FileName)]));
|
||||
end
|
||||
else
|
||||
begin
|
||||
Assert.Fail(Format('File: %s - Root node is not typed, cannot check signature.', [ExtractFileName(FileName)]));
|
||||
end;
|
||||
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
Assert.Fail(Format('File: %s - Compilation/TypeCheck failed: %s', [ExtractFileName(FileName), E.Message]));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
// --- SIGNATURE CHECK END ---
|
||||
|
||||
try
|
||||
// 4. Run Execution (Value Check)
|
||||
// Wir nutzen hier wieder RootNode (oder SpecializedNode, falls Env.Run damit umgehen kann),
|
||||
// um sicherzustellen, dass die Ausführung sauber durchläuft.
|
||||
ResultValue := Env.Run(RootNode);
|
||||
|
||||
// 5. Verify Type
|
||||
if ExpectedTypeStr <> '' then
|
||||
begin
|
||||
Assert.AreEqual(ExpectedType, ResultValue.Kind, Format('File: %s - Result Type Mismatch', [ExtractFileName(FileName)]));
|
||||
end;
|
||||
|
||||
// 6. Verify Output Value
|
||||
Assert.AreEqual(ExpectedOutput, ResultValue.ToString, Format('File: %s - Result Value Mismatch', [ExtractFileName(FileName)]));
|
||||
|
||||
except
|
||||
on E: EAssertionFailed do
|
||||
raise;
|
||||
on E: Exception do
|
||||
Assert.Fail(Format('File: %s - Exception during execution: %s', [ExtractFileName(FileName), E.Message]));
|
||||
end;
|
||||
|
||||
finally
|
||||
ScriptSource.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestIntegration.RunAllFileBasedTests;
|
||||
var
|
||||
Files: TArray<string>;
|
||||
FileName: string;
|
||||
Failures: TStringBuilder;
|
||||
begin
|
||||
Files := TDirectory.GetFiles(TEST_DIR, '*.txt');
|
||||
|
||||
if Length(Files) = 0 then
|
||||
Exit; // Silent exit if no files found (success, effectively)
|
||||
|
||||
Failures := TStringBuilder.Create;
|
||||
try
|
||||
for FileName in Files do
|
||||
begin
|
||||
try
|
||||
RunSingleScript(FileName);
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
Failures.AppendLine(Format('[FAIL] %s: %s', [ExtractFileName(FileName), E.Message]));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Only fail if errors were collected
|
||||
if Failures.Length > 0 then
|
||||
Assert.Fail('One or more integration scripts failed:' + SLineBreak + Failures.ToString);
|
||||
|
||||
finally
|
||||
Failures.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
Reference in New Issue
Block a user