diff --git a/Test/AST/Test.Myc.Ast.RTL.DateTime.pas b/Test/AST/Test.Myc.Ast.RTL.DateTime.pas new file mode 100644 index 0000000..4a965ab --- /dev/null +++ b/Test/AST/Test.Myc.Ast.RTL.DateTime.pas @@ -0,0 +1,160 @@ +unit Test.Myc.Ast.RTL.DateTime; + +interface + +uses + DUnitX.TestFramework, + System.SysUtils, + System.DateUtils, + System.Math, + Myc.Ast.Environment, + Myc.Ast.Script, + Myc.Data.Value, + Myc.Data.Scalar; + +type + [TestFixture] + [IgnoreMemoryLeaks] + TTestRtlDateTime = class + private + FEnv: TAstEnvironment; + public + [Setup] + procedure Setup; + [Teardown] + procedure Teardown; + + [Test] + procedure Test_Constructor_FixedDate; + + [Test] + procedure Test_Constructor_Now; + + [Test] + [TestCase('Later', '2025,1,1,2024,1,1,True')] + [TestCase('Earlier', '2020,1,1,2021,1,1,False')] + procedure Test_GreaterThan(Y1, M1, D1, Y2, M2, D2: Integer; ExpectTrue: Boolean); + + [Test] + procedure Test_Equality; + + [Test] + procedure Test_DateTime_Is_Truthy; + + [Test] + procedure Test_Round_DateTime; + end; + +implementation + +procedure TTestRtlDateTime.Setup; +begin + // Creates a fresh environment with all RTL functions registered + // (including Date, Now, True, False) + FEnv := TAstEnvironment.Construct(nil); +end; + +procedure TTestRtlDateTime.Teardown; +begin + // Environment is a record (interface wrapper), automatic cleanup +end; + +procedure TTestRtlDateTime.Test_Constructor_FixedDate; +var + Res: TDataValue; + Expected: TDateTime; +begin + // Act + Res := FEnv.Run(TAstScript.Parse('(Date 2025 11 24)')); + + // Assert + Assert.AreEqual(TDataValueKind.vkScalar, Res.Kind, 'Result should be scalar'); + Assert.AreEqual(TScalar.TKind.DateTime, Res.AsScalar.Kind, 'Scalar kind should be DateTime'); + + Expected := EncodeDate(2025, 11, 24); + Assert.AreEqual(Expected, Res.AsScalar.Value.AsDouble, 0.0001, 'Date value mismatch'); +end; + +procedure TTestRtlDateTime.Test_Constructor_Now; +var + Res: TDataValue; + Before, After: TDateTime; +begin + Before := System.SysUtils.Now; + // Allow small window for execution time + Sleep(1); + + // Act + Res := FEnv.Run(TAstScript.Parse('(Now)')); + + After := System.SysUtils.Now; + + // Assert + Assert.AreEqual(TScalar.TKind.DateTime, Res.AsScalar.Kind); + + // Check if result is within the time window + Assert.IsTrue(Res.AsScalar.Value.AsDouble >= Before); + Assert.IsTrue(Res.AsScalar.Value.AsDouble <= After); +end; + +procedure TTestRtlDateTime.Test_GreaterThan(Y1, M1, D1, Y2, M2, D2: Integer; ExpectTrue: Boolean); +var + Script: string; + Res: TDataValue; +begin + // (> (Date y1 m1 d1) (Date y2 m2 d2)) + Script := Format('(> (Date %d %d %d) (Date %d %d %d))', [Y1, M1, D1, Y2, M2, D2]); + + Res := FEnv.Run(TAstScript.Parse(Script)); + + Assert.AreEqual(TScalar.TKind.Boolean, Res.AsScalar.Kind); + + if ExpectTrue then + Assert.AreEqual(Int64(1), Res.AsScalar.Value.AsInt64, 'Expected True') + else + Assert.AreEqual(Int64(0), Res.AsScalar.Value.AsInt64, 'Expected False'); +end; + +procedure TTestRtlDateTime.Test_Equality; +var + Res: TDataValue; +begin + // (= (Date 2023 10 10) (Date 2023 10 10)) + Res := FEnv.Run(TAstScript.Parse('(= (Date 2023 10 10) (Date 2023 10 10))')); + + Assert.AreEqual(TScalar.TKind.Boolean, Res.AsScalar.Kind); + Assert.AreEqual(Int64(1), Res.AsScalar.Value.AsInt64); +end; + +procedure TTestRtlDateTime.Test_DateTime_Is_Truthy; +var + Res: TDataValue; +begin + // (if (Date 2023 1 1) "yes" "no") + // Checks if IsTruthy correctly handles TKind.DateTime + Res := FEnv.Run(TAstScript.Parse('(if (Date 2023 1 1) "yes" "no")')); + + Assert.AreEqual(TDataValueKind.vkText, Res.Kind); + Assert.AreEqual('yes', Res.AsText); +end; + +procedure TTestRtlDateTime.Test_Round_DateTime; +var + Res: TDataValue; + InputDate: TDateTime; + Expected: Int64; +begin + // Ensure RTL Round handles DateTime as float + // (Round (Date 2023 11 24)) + // Date creates a TDateTime (Double) with 0.0 time fraction, so Round should return the truncation. + + InputDate := EncodeDate(2023, 11, 24); + Expected := System.Round(InputDate); + + Res := FEnv.Run(TAstScript.Parse('(Round (Date 2023 11 24))')); + + Assert.AreEqual(TScalar.TKind.Ordinal, Res.AsScalar.Kind); + Assert.AreEqual(Expected, Res.AsScalar.Value.AsInt64); +end; + +end. diff --git a/Test/MycTests.dpr b/Test/MycTests.dpr index 2d02ed7..cb9e4ed 100644 --- a/Test/MycTests.dpr +++ b/Test/MycTests.dpr @@ -30,7 +30,8 @@ uses Test.Myc.Ast.Scope in 'AST\Test.Myc.Ast.Scope.pas', Test.Myc.Ast.RTL in 'AST\Test.Myc.Ast.RTL.pas', Test.Myc.Ast.Script in 'AST\Test.Myc.Ast.Script.pas', - Test.Myc.Ast.Compiler.Macros in 'AST\Test.Myc.Ast.Compiler.Macros.pas'; + Test.Myc.Ast.Compiler.Macros in 'AST\Test.Myc.Ast.Compiler.Macros.pas', + Test.Myc.Ast.RTL.DateTime in 'AST\Test.Myc.Ast.RTL.DateTime.pas'; { keep comment here to protect the following conditional from being removed by the IDE when adding a unit } {$IFNDEF TESTINSIGHT} diff --git a/Test/MycTests.dproj b/Test/MycTests.dproj index e71df19..b5bb002 100644 --- a/Test/MycTests.dproj +++ b/Test/MycTests.dproj @@ -132,6 +132,7 @@ $(PreBuildEvent)]]> + Base