unit TestTasks; interface uses DUnitX.TestFramework, System.SysUtils, System.Classes, System.SyncObjs, Myc.Core.Tasks, Myc.Signals, Myc.Core.Signals, Myc.Core.Atomic; type [TestFixture] [IgnoreMemoryLeaks(true)] TMycTaskFactoryTests = class(TObject) private FFactory: IThreadPool; public [Setup] procedure Setup; [TearDown] procedure TearDown; [Test] procedure TestFactoryCreationAndTeardown; [Test] procedure TestWaitForAlreadySetState; [Test] procedure TestThreadInfoMethods; [Test] procedure TestExceptionPropagationFromJob; [Test] procedure TestRunJobAfterFactoryTeardown; [Test] procedure TestWaitForInWorkerThreadRaisesException; end; implementation { TMycTaskFactoryTests } procedure TMycTaskFactoryTests.Setup; begin FFactory := TMycTaskFactory.Create; end; procedure TMycTaskFactoryTests.TearDown; begin if Assigned(FFactory) then begin FFactory.Teardown; FFactory := nil; end; end; procedure TMycTaskFactoryTests.TestFactoryCreationAndTeardown; begin Assert.IsNotNull(FFactory, 'Factory should be created'); end; procedure TMycTaskFactoryTests.TestWaitForAlreadySetState; var alreadySetLatch: TLatch.ILatch; startTime, endTime: Cardinal; begin // TMycLatch.CreateLatch(0) will return TMycLatch.Null alreadySetLatch := TLatch.CreateLatch(0); // Changed from Signals.CreateLatch Assert.IsTrue(alreadySetLatch.State.IsSet, 'Latch should be initially set'); startTime := TThread.GetTickCount; FFactory.WaitFor(alreadySetLatch.State); endTime := TThread.GetTickCount; Assert.IsTrue((endTime - startTime) < 50, 'WaitFor on an already set state should not block significantly'); end; procedure TMycTaskFactoryTests.TestThreadInfoMethods; var inMainThreadInJob: Boolean; inWorkerThreadInJob: Boolean; jobDoneLatch: TLatch.ILatch; begin inMainThreadInJob := True; inWorkerThreadInJob := False; jobDoneLatch := TLatch.CreateLatch(1); // Changed from Signals.CreateLatch Assert.IsTrue(FFactory.InMainThread, 'Test method itself should be in main thread'); Assert.IsFalse(FFactory.InWorkerThread, 'Test method itself should not be in a factory worker thread'); FFactory.EnqueueJob( procedure begin inMainThreadInJob := FFactory.InMainThread; inWorkerThreadInJob := FFactory.InWorkerThread; jobDoneLatch.Notify; end ); FFactory.WaitFor(jobDoneLatch.State); Assert.IsFalse(inMainThreadInJob, 'Job executed by factory should not be in main thread'); Assert.IsTrue(inWorkerThreadInJob, 'Job executed by factory should be in a worker thread'); end; procedure TMycTaskFactoryTests.TestExceptionPropagationFromJob; var jobDoneLatch: TLatch.ILatch; begin jobDoneLatch := TLatch.CreateLatch(1); FFactory.EnqueueJob( procedure begin try raise TMycTaskFactory.ETaskException.Create('Test Exception From Job'); finally jobDoneLatch.Notify; end; end ); Assert.WillRaise( procedure begin FFactory.WaitFor(jobDoneLatch.State); end, TMycTaskFactory.ETaskException, 'WaitFor should re-raise the exception from the job' ); var noExceptionRaised: Boolean := True; try (FFactory as TMycTaskFactory).HandleException; except noExceptionRaised := False; end; Assert.IsTrue(noExceptionRaised, 'FException should be cleared after HandleException'); end; procedure TMycTaskFactoryTests.TestRunJobAfterFactoryTeardown; begin FFactory.Teardown; Assert.WillRaise( procedure begin FFactory.EnqueueJob(procedure begin end); end, TMycTaskFactory.ETaskException, 'Running a job on a torn-down factory should raise ETaskException' ); end; procedure TMycTaskFactoryTests.TestWaitForInWorkerThreadRaisesException; var exceptionCaughtInJob: Boolean; jobDoneLatch: TLatch.ILatch; dummyStateToWaitFor: TState.IState; begin exceptionCaughtInJob := False; jobDoneLatch := TLatch.CreateLatch(1); dummyStateToWaitFor := TLatch.CreateLatch(1).State; FFactory.EnqueueJob( procedure begin try FFactory.WaitFor(dummyStateToWaitFor); except on E: TMycTaskFactory.ETaskException do begin exceptionCaughtInJob := True; end; end; jobDoneLatch.Notify; end ); FFactory.WaitFor(jobDoneLatch.State); Assert.IsTrue(exceptionCaughtInJob, 'WaitFor called within a worker thread job should raise ETaskException'); end; initialization TDUnitX.RegisterTestFixture(TMycTaskFactoryTests); end.