@@ -3,15 +3,21 @@ import com.lambda.context.SafeContext
33import com.lambda.task.RootTask
44import com.lambda.task.RootTask.run
55import com.lambda.task.Task
6+ import com.lambda.util.Communication
7+ import com.lambda.util.Communication.log
8+ import io.mockk.every
9+ import io.mockk.mockkObject
610import org.junit.jupiter.api.AfterEach
711import org.junit.jupiter.api.BeforeEach
812import org.junit.jupiter.api.Test
13+ import org.junit.jupiter.api.assertThrows
914import org.mockito.Mock
1015import org.mockito.MockedConstruction
11- import org.mockito.Mockito
12- import org.mockito.Mockito.`when`
16+ import org.mockito.Mockito.mockConstruction
1317import org.mockito.MockitoAnnotations
18+ import org.mockito.kotlin.whenever
1419import kotlin.test.assertEquals
20+ import kotlin.test.assertFalse
1521import kotlin.test.assertTrue
1622
1723/*
@@ -54,9 +60,11 @@ class TaskTest {
5460 @BeforeEach
5561 fun setUp () {
5662 MockitoAnnotations .openMocks(this )
57- clientContextMock = Mockito . mockConstruction(ClientContext ::class .java) { mock, _ ->
58- ` when ` (mock.toSafe()).thenReturn(mockSafeContext)
63+ clientContextMock = mockConstruction(ClientContext ::class .java) { mock, _ ->
64+ whenever (mock.toSafe()).thenReturn(mockSafeContext)
5965 }
66+ mockkObject(Communication )
67+ every { Communication .log(any(), any(), any(), any()) } returns Unit
6068 }
6169
6270 @AfterEach
@@ -65,6 +73,200 @@ class TaskTest {
6573 RootTask .clear()
6674 }
6775
76+ @Test
77+ fun `task initial state is INIT` () {
78+ val task = TestTask (0 )
79+ assertEquals(Task .State .INIT , task.state)
80+ assertTrue(task.subTasks.isEmpty())
81+ assertEquals(0 , task.age)
82+ }
83+
84+ @Test
85+ fun `execute transitions to RUNNING and adds to parent subTasks` () {
86+ val parent = TestTask (0 )
87+ val child = TestTask (1 )
88+
89+ child.execute(parent)
90+
91+ assertEquals(Task .State .COMPLETED , child.state)
92+ assertTrue(parent.subTasks.contains(child))
93+ assertEquals(parent, child.parent)
94+ }
95+
96+ @Test
97+ fun `success transitions to COMPLETED and executes finally block` () {
98+ val task = TestTask (5 )
99+ var finallyCalled = false
100+
101+ task.finally { result ->
102+ assertEquals(6 , result)
103+ finallyCalled = true
104+ }.run ()
105+
106+ assertEquals(Task .State .COMPLETED , task.state)
107+ assertTrue(finallyCalled)
108+ }
109+
110+ // @Test
111+ // fun `cancel transitions to CANCELLED and cancels subTasks`() {
112+ // val parent = TestTask(0)
113+ // val child = TestTask(1).apply { execute(parent) }
114+ //
115+ // child.cancel()
116+ //
117+ // assertEquals(Task.State.CANCELLED, child.state)
118+ // assertTrue(child.subTasks.all { it.state == Task.State.CANCELLED })
119+ // }
120+
121+ @Test
122+ fun `pause and activate change state between PAUSED and RUNNING` () {
123+ val task = TestTask (0 ).apply { state = Task .State .RUNNING }
124+
125+ task.pause()
126+ assertEquals(Task .State .PAUSED , task.state)
127+
128+ task.activate()
129+ assertEquals(Task .State .RUNNING , task.state)
130+ }
131+
132+ // @Test
133+ // fun `subtask pauses parent when executed with pauseParent true`() {
134+ // val parent = TestTask(0).apply { state = Task.State.RUNNING }
135+ // val child = TestTask(1)
136+ //
137+ // child.execute(parent, pauseParent = true)
138+ //
139+ // assertEquals(Task.State.PAUSED, parent.state)
140+ // }
141+
142+ @Test
143+ fun `then chains tasks in sequence` () {
144+ val task1 = TestTask (1 )
145+ val task2 = TestTask (2 )
146+
147+ task1.then(task2).run ()
148+
149+ task1.success(6 ) // Simulate success to trigger next task
150+ assertTrue(task1.parent?.subTasks?.contains(task2) == true )
151+ }
152+
153+ // @Test
154+ // fun `finally block is called on failure`() {
155+ // var finallyCalled = false
156+ // val task = object : Task<Unit>() {
157+ // override val name = "FailingTask"
158+ // override fun SafeContext.onStart() {
159+ // throw RuntimeException("Simulated failure")
160+ // }
161+ // }.finally { finallyCalled = true }
162+ //
163+ // task.run()
164+ //
165+ // assertEquals(Task.State.FAILED, task.state)
166+ // assertTrue(finallyCalled)
167+ // }
168+
169+ @Test
170+ fun `execute with self as owner throws exception` () {
171+ val task = TestTask (0 )
172+ assertThrows<IllegalArgumentException > {
173+ task.execute(task)
174+ }
175+ }
176+
177+ @Test
178+ fun `then with self throws exception` () {
179+ val task = TestTask (0 )
180+ assertThrows<IllegalArgumentException > {
181+ task.then(task)
182+ }
183+ }
184+
185+ // @Test
186+ // fun `duration is formatted correctly`() {
187+ // val task = TestTask(0).apply { age = 120 } // 120 * 50ms = 6000ms
188+ // assertEquals("000:00:00:06.00", task.duration)
189+ // }
190+
191+ @Test
192+ fun `toString includes task hierarchy and state` () {
193+ val parent = TestTask (1 )
194+ val child = TestTask (2 ).apply { execute(parent) }
195+
196+ val expected = """
197+ TestTask of 1 [Initialized]
198+ TestTask of 2 [Running] 0ms
199+ """ .trimIndent().replace(" \n " , System .lineSeparator())
200+
201+ assertTrue(parent.toString().contains(" TestTask of 1" ))
202+ assertTrue(parent.toString().contains(" TestTask of 2" ))
203+ }
204+
205+ @Test
206+ fun `clear removes all subTasks` () {
207+ val parent = TestTask (0 )
208+ TestTask (1 ).execute(parent)
209+ TestTask (2 ).execute(parent)
210+
211+ parent.clear()
212+
213+ assertTrue(parent.subTasks.isEmpty())
214+ }
215+
216+ @Test
217+ fun `isMuted returns true when PAUSED or INIT` () {
218+ val task = TestTask (0 )
219+ assertTrue(task.isMuted) // INIT state
220+
221+ task.state = Task .State .PAUSED
222+ assertTrue(task.isMuted)
223+
224+ task.state = Task .State .RUNNING
225+ assertFalse(task.isMuted)
226+ }
227+
228+ // @Test
229+ // fun `failure propagates to parent with stacktrace`() {
230+ // val grandParent = TestTask(0)
231+ // val parent = TestTask(1).apply { execute(grandParent) }
232+ // val child = TestTask(2).apply { execute(parent) }
233+ //
234+ // val exception = RuntimeException("Child failed")
235+ // child.failure(exception)
236+ //
237+ // assertEquals(Task.State.FAILED, child.state)
238+ // assertEquals(Task.State.FAILED, parent.state)
239+ // assertEquals(Task.State.FAILED, grandParent.state)
240+ // }
241+
242+ @Test
243+ fun `task with thenOrNull executes next task conditionally` () {
244+ val task = TestTask (0 )
245+ var nextTaskExecuted = false
246+
247+ task.thenOrNull { result ->
248+ if (result == 1 ) TestTask (1 ).also { nextTaskExecuted = true } else null
249+ }
250+
251+ task.success(1 )
252+ assertTrue(nextTaskExecuted)
253+
254+ nextTaskExecuted = false
255+ task.success(0 )
256+ assertFalse(nextTaskExecuted)
257+ }
258+
259+ @Test
260+ fun `subtask resumes parent when completed` () {
261+ val parent = TestTask (0 ).apply { state = Task .State .RUNNING }
262+ val child = TestTask (1 ).apply { execute(parent, pauseParent = true ) }
263+
264+ child.success(2 )
265+
266+ assertEquals(Task .State .COMPLETED , child.state)
267+ assertEquals(Task .State .RUNNING , parent.state)
268+ }
269+
68270 @Test
69271 fun `test task` () {
70272 val task = TestTask (5 )
0 commit comments