renamed some units, added TMycAtomicStack
This commit is contained in:
@@ -0,0 +1,368 @@
|
||||
unit TestStack;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
DUnitX.TestFramework;
|
||||
|
||||
type
|
||||
// Helper record type for testing generic capabilities
|
||||
TTestRecord = record
|
||||
ID: Integer;
|
||||
Name: string;
|
||||
Value: Double;
|
||||
end;
|
||||
|
||||
[TestFixture]
|
||||
TMycTestStackTests = class(TObject) // Changed class name for clarity
|
||||
public
|
||||
// Setup and TearDown are often not strictly necessary for tests
|
||||
// involving managed records as local variables, as their
|
||||
// Initialize/Finalize are handled automatically.
|
||||
[Setup]
|
||||
procedure Setup;
|
||||
[TearDown]
|
||||
procedure TearDown;
|
||||
|
||||
// --- Tests for TMycAtomicStack<Integer> ---
|
||||
[Test]
|
||||
procedure TestInteger_PopOnEmpty_ReturnsDefault;
|
||||
[Test]
|
||||
procedure TestInteger_TryPopOnEmpty_ReturnsFalseAndDefault;
|
||||
[Test]
|
||||
procedure TestInteger_PushOne_PopOne_CorrectValue;
|
||||
[Test]
|
||||
procedure TestInteger_PushThree_PopThree_LIFO_Order;
|
||||
[Test]
|
||||
procedure TestInteger_TryPopWithItems_ReturnsTrueAndCorrectValue;
|
||||
[Test]
|
||||
procedure TestInteger_PushPopMixed_MaintainsIntegrity;
|
||||
[Test]
|
||||
procedure TestInteger_StressTest_ManyItems;
|
||||
|
||||
// --- Tests for TMycAtomicStack<string> ---
|
||||
[Test]
|
||||
procedure TestString_PopOnEmpty_ReturnsDefault;
|
||||
[Test]
|
||||
procedure TestString_TryPopOnEmpty_ReturnsFalseAndDefault;
|
||||
[Test]
|
||||
procedure TestString_PushOne_PopOne_CorrectValue;
|
||||
[Test]
|
||||
procedure TestString_PushThree_PopThree_LIFO_Order;
|
||||
[Test]
|
||||
procedure TestString_HandleEmptyAndNilStrings;
|
||||
|
||||
// --- Tests for TMycAtomicStack<TTestRecord> ---
|
||||
[Test]
|
||||
procedure TestRecord_PopOnEmpty_ReturnsDefault;
|
||||
[Test]
|
||||
procedure TestRecord_TryPopOnEmpty_ReturnsFalseAndDefault;
|
||||
[Test]
|
||||
procedure TestRecord_PushOne_PopOne_CorrectValue;
|
||||
[Test]
|
||||
procedure TestRecord_PushThree_PopThree_LIFO_Order;
|
||||
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils, // For Default() if not implicitly available via DUnitX/Generics
|
||||
Myc.Core.Atomic; // The unit containing TMycAtomicStack
|
||||
|
||||
procedure TMycTestStackTests.Setup;
|
||||
begin
|
||||
// No specific setup needed per test if stack is local variable in methods.
|
||||
end;
|
||||
|
||||
procedure TMycTestStackTests.TearDown;
|
||||
begin
|
||||
// No specific teardown needed per test.
|
||||
end;
|
||||
|
||||
// --- Helper Methods ---
|
||||
|
||||
function AreRecordsEqual(const Rec1, Rec2: TTestRecord): Boolean;
|
||||
begin
|
||||
Result := (Rec1.ID = Rec2.ID) and (Rec1.Name = Rec2.Name) and (Rec1.Value = Rec2.Value);
|
||||
end;
|
||||
|
||||
function TestRecordToString(const Rec: TTestRecord): string;
|
||||
begin
|
||||
Result := Format('ID: %d, Name: "%s", Value: %f', [Rec.ID, Rec.Name, Rec.Value]);
|
||||
end;
|
||||
|
||||
// --- Tests for TMycAtomicStack<Integer> ---
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestInteger_PopOnEmpty_ReturnsDefault;
|
||||
var
|
||||
stack: TMycAtomicStack<Integer>;
|
||||
value: Integer;
|
||||
begin
|
||||
// Initialize is called automatically for managed record 'stack'
|
||||
value := stack.Pop;
|
||||
Assert.AreEqual(Default(Integer), value, 'Pop on empty integer stack should return Default(Integer).');
|
||||
// Finalize is called automatically when 'stack' goes out of scope
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestInteger_TryPopOnEmpty_ReturnsFalseAndDefault;
|
||||
var
|
||||
stack: TMycAtomicStack<Integer>;
|
||||
value: Integer;
|
||||
success: Boolean;
|
||||
begin
|
||||
value := 123; // Non-default initial value to check if TryPop modifies it
|
||||
success := stack.TryPop(value);
|
||||
Assert.IsFalse(success, 'TryPop on empty integer stack should return False.');
|
||||
Assert.AreEqual(Default(Integer), value, 'Item from TryPop on empty integer stack should be Default(Integer).');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestInteger_PushOne_PopOne_CorrectValue;
|
||||
var
|
||||
stack: TMycAtomicStack<Integer>;
|
||||
pushedValue: Integer;
|
||||
poppedValue: Integer;
|
||||
success: Boolean;
|
||||
begin
|
||||
pushedValue := 100;
|
||||
stack.Push(pushedValue);
|
||||
|
||||
poppedValue := stack.Pop;
|
||||
Assert.AreEqual(pushedValue, poppedValue, 'Popped value does not match pushed value.');
|
||||
|
||||
// Stack should be empty now
|
||||
success := stack.TryPop(poppedValue);
|
||||
Assert.IsFalse(success, 'Stack should be empty after popping the only item.');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestInteger_PushThree_PopThree_LIFO_Order;
|
||||
var
|
||||
stack: TMycAtomicStack<Integer>;
|
||||
val1, val2, val3: Integer;
|
||||
begin
|
||||
val1 := 1;
|
||||
val2 := 2;
|
||||
val3 := 3;
|
||||
|
||||
stack.Push(val1);
|
||||
stack.Push(val2);
|
||||
stack.Push(val3);
|
||||
|
||||
Assert.AreEqual(val3, stack.Pop, '1st Pop: Expected val3 (LIFO).');
|
||||
Assert.AreEqual(val2, stack.Pop, '2nd Pop: Expected val2 (LIFO).');
|
||||
Assert.AreEqual(val1, stack.Pop, '3rd Pop: Expected val1 (LIFO).');
|
||||
|
||||
Assert.IsFalse(stack.TryPop(val1), 'Stack should be empty after popping all items.');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestInteger_TryPopWithItems_ReturnsTrueAndCorrectValue;
|
||||
var
|
||||
stack: TMycAtomicStack<Integer>;
|
||||
pushedValue: Integer;
|
||||
poppedValue: Integer;
|
||||
success: Boolean;
|
||||
begin
|
||||
pushedValue := 77;
|
||||
stack.Push(pushedValue);
|
||||
|
||||
success := stack.TryPop(poppedValue);
|
||||
Assert.IsTrue(success, 'TryPop should return True when stack is not empty.');
|
||||
Assert.AreEqual(pushedValue, poppedValue, 'TryPop: Popped value does not match pushed value.');
|
||||
|
||||
success := stack.TryPop(poppedValue);
|
||||
Assert.IsFalse(success, 'Stack should be empty after TryPop on the only item.');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestInteger_PushPopMixed_MaintainsIntegrity;
|
||||
var
|
||||
stack: TMycAtomicStack<Integer>;
|
||||
value: Integer;
|
||||
begin
|
||||
stack.Push(10);
|
||||
stack.Push(20);
|
||||
Assert.AreEqual(20, stack.Pop, 'Pop 20'); // Stack: 10
|
||||
stack.Push(30); // Stack: 10, 30
|
||||
Assert.AreEqual(30, stack.Pop, 'Pop 30'); // Stack: 10
|
||||
stack.Push(40); // Stack: 10, 40
|
||||
Assert.AreEqual(40, stack.Pop, 'Pop 40'); // Stack: 10
|
||||
Assert.AreEqual(10, stack.Pop, 'Pop 10'); // Stack: empty
|
||||
|
||||
Assert.IsFalse(stack.TryPop(value), 'Stack should be empty after all operations.');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestInteger_StressTest_ManyItems;
|
||||
var
|
||||
stack: TMycAtomicStack<Integer>;
|
||||
i: Integer;
|
||||
count: Integer;
|
||||
begin
|
||||
count := 10000;
|
||||
for i := 1 to count do
|
||||
begin
|
||||
stack.Push(i);
|
||||
end;
|
||||
|
||||
for i := count downto 1 do
|
||||
begin
|
||||
Assert.AreEqual(i, stack.Pop, Format('Stress test: Popped value mismatch for item %d.', [i]));
|
||||
end;
|
||||
|
||||
Assert.IsFalse(stack.TryPop(i), 'Stack should be empty after stress test.');
|
||||
end;
|
||||
|
||||
|
||||
// --- Tests for TMycAtomicStack<string> ---
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestString_PopOnEmpty_ReturnsDefault;
|
||||
var
|
||||
stack: TMycAtomicStack<string>;
|
||||
value: string;
|
||||
begin
|
||||
value := stack.Pop;
|
||||
Assert.AreEqual(Default(string), value, 'Pop on empty string stack should return Default(string) (nil).');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestString_TryPopOnEmpty_ReturnsFalseAndDefault;
|
||||
var
|
||||
stack: TMycAtomicStack<string>;
|
||||
value: string;
|
||||
success: Boolean;
|
||||
begin
|
||||
value := 'not nil';
|
||||
success := stack.TryPop(value);
|
||||
Assert.IsFalse(success, 'TryPop on empty string stack should return False.');
|
||||
Assert.AreEqual(Default(string), value, 'Item from TryPop on empty string stack should be Default(string) (nil).');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestString_PushOne_PopOne_CorrectValue;
|
||||
var
|
||||
stack: TMycAtomicStack<string>;
|
||||
pushedValue: string;
|
||||
poppedValue: string;
|
||||
begin
|
||||
pushedValue := 'Hello Delphi';
|
||||
stack.Push(pushedValue);
|
||||
|
||||
poppedValue := stack.Pop;
|
||||
Assert.AreEqual(pushedValue, poppedValue, 'String Pop: Popped value does not match pushed value.');
|
||||
Assert.IsFalse(stack.TryPop(poppedValue), 'Stack should be empty.');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestString_PushThree_PopThree_LIFO_Order;
|
||||
var
|
||||
stack: TMycAtomicStack<string>;
|
||||
s1, s2, s3: string;
|
||||
begin
|
||||
s1 := 'first';
|
||||
s2 := 'second';
|
||||
s3 := 'third';
|
||||
|
||||
stack.Push(s1);
|
||||
stack.Push(s2);
|
||||
stack.Push(s3);
|
||||
|
||||
Assert.AreEqual(s3, stack.Pop, 'String LIFO: Expected s3.');
|
||||
Assert.AreEqual(s2, stack.Pop, 'String LIFO: Expected s2.');
|
||||
Assert.AreEqual(s1, stack.Pop, 'String LIFO: Expected s1.');
|
||||
Assert.IsFalse(stack.TryPop(s1), 'Stack should be empty.');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestString_HandleEmptyAndNilStrings;
|
||||
var
|
||||
stack: TMycAtomicStack<string>;
|
||||
poppedValue: string;
|
||||
begin
|
||||
stack.Push(''); // Empty string
|
||||
stack.Push(Default(string)); // Nil string
|
||||
stack.Push('actual string');
|
||||
|
||||
Assert.AreEqual('actual string', stack.Pop, 'Pop "actual string"');
|
||||
Assert.AreEqual(Default(string), stack.Pop, 'Pop nil string');
|
||||
Assert.AreEqual('', stack.Pop, 'Pop empty string');
|
||||
Assert.IsFalse(stack.TryPop(poppedValue), 'Stack should be empty.');
|
||||
end;
|
||||
|
||||
// --- Tests for TMycAtomicStack<TTestRecord> ---
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestRecord_PopOnEmpty_ReturnsDefault;
|
||||
var
|
||||
stack: TMycAtomicStack<TTestRecord>;
|
||||
value: TTestRecord;
|
||||
begin
|
||||
value := stack.Pop;
|
||||
Assert.IsTrue(AreRecordsEqual(Default(TTestRecord), value),
|
||||
Format('Pop on empty record stack should return Default(TTestRecord). Got %s', [TestRecordToString(value)]));
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestRecord_TryPopOnEmpty_ReturnsFalseAndDefault;
|
||||
var
|
||||
stack: TMycAtomicStack<TTestRecord>;
|
||||
value: TTestRecord;
|
||||
success: Boolean;
|
||||
begin
|
||||
value.ID := -1; // Non-default
|
||||
success := stack.TryPop(value);
|
||||
Assert.IsFalse(success, 'TryPop on empty record stack should return False.');
|
||||
Assert.IsTrue(AreRecordsEqual(Default(TTestRecord), value),
|
||||
Format('Item from TryPop on empty record stack should be Default(TTestRecord). Got %s', [TestRecordToString(value)]));
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestRecord_PushOne_PopOne_CorrectValue;
|
||||
var
|
||||
stack: TMycAtomicStack<TTestRecord>;
|
||||
pushedValue: TTestRecord;
|
||||
poppedValue: TTestRecord;
|
||||
begin
|
||||
pushedValue.ID := 1;
|
||||
pushedValue.Name := 'Test Record 1';
|
||||
pushedValue.Value := 3.14;
|
||||
stack.Push(pushedValue);
|
||||
|
||||
poppedValue := stack.Pop;
|
||||
Assert.IsTrue(AreRecordsEqual(pushedValue, poppedValue),
|
||||
Format('Record Pop: Popped value (%s) does not match pushed value (%s).', [TestRecordToString(poppedValue), TestRecordToString(pushedValue)]));
|
||||
Assert.IsFalse(stack.TryPop(poppedValue), 'Stack should be empty.');
|
||||
end;
|
||||
|
||||
[Test]
|
||||
procedure TMycTestStackTests.TestRecord_PushThree_PopThree_LIFO_Order;
|
||||
var
|
||||
stack: TMycAtomicStack<TTestRecord>;
|
||||
r1, r2, r3: TTestRecord;
|
||||
popped: TTestRecord;
|
||||
begin
|
||||
r1.ID := 1; r1.Name := 'R1'; r1.Value := 1.0;
|
||||
r2.ID := 2; r2.Name := 'R2'; r2.Value := 2.0;
|
||||
r3.ID := 3; r3.Name := 'R3'; r3.Value := 3.0;
|
||||
|
||||
stack.Push(r1);
|
||||
stack.Push(r2);
|
||||
stack.Push(r3);
|
||||
|
||||
popped := stack.Pop;
|
||||
Assert.IsTrue(AreRecordsEqual(r3, popped), Format('Record LIFO: Expected r3, got %s', [TestRecordToString(popped)]));
|
||||
popped := stack.Pop;
|
||||
Assert.IsTrue(AreRecordsEqual(r2, popped), Format('Record LIFO: Expected r2, got %s', [TestRecordToString(popped)]));
|
||||
popped := stack.Pop;
|
||||
Assert.IsTrue(AreRecordsEqual(r1, popped), Format('Record LIFO: Expected r1, got %s', [TestRecordToString(popped)]));
|
||||
Assert.IsFalse(stack.TryPop(popped), 'Stack should be empty.');
|
||||
end;
|
||||
|
||||
initialization
|
||||
TDUnitX.RegisterTestFixture(TMycTestStackTests);
|
||||
end.
|
||||
Reference in New Issue
Block a user