Skip to content

Commit 54eb8e1

Browse files
committed
add lifecycle component traits and tests
1 parent 248a4cf commit 54eb8e1

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.avsystem.commons
2+
package di
3+
4+
import monix.execution.atomic.{Atomic, AtomicBoolean, AtomicInt}
5+
import org.scalatest.funsuite.AsyncFunSuite
6+
7+
class LifeCycleComponentTest extends AsyncFunSuite with Components {
8+
9+
object init {
10+
val inits: AtomicInt = Atomic(0)
11+
val component: Component[InitializingComponent] = singleton {
12+
new InitializingComponent {
13+
override def init(): Unit = inits += 1
14+
}
15+
}
16+
}
17+
18+
object asyncInit {
19+
val inits: AtomicInt = Atomic(0)
20+
val component: Component[AsyncInitializingComponent] = singleton {
21+
new AsyncInitializingComponent {
22+
def init()(implicit ec: ExecutionContext): Future[Unit] = Future {
23+
inits += 1
24+
}(ec)
25+
}
26+
}
27+
}
28+
29+
object disposable {
30+
val destroyed: AtomicBoolean = Atomic(false)
31+
val component: Component[DisposableComponent] = singleton {
32+
new DisposableComponent {
33+
def destroy(): Unit = destroyed.set(true)
34+
}
35+
}
36+
}
37+
38+
39+
object asyncDisposable {
40+
val destroyed: AtomicBoolean = Atomic(false)
41+
val component: Component[AsyncDisposableComponent] = singleton {
42+
new AsyncDisposableComponent {
43+
def destroy()(implicit ec: ExecutionContext): Future[Unit] = Future {
44+
destroyed.set(true)
45+
}(ec)
46+
}
47+
}
48+
}
49+
50+
test("InitializingComponent singleton initializes once and returns same instance")(for {
51+
_ <- Future.unit
52+
_ = assert(init.inits.get() == 0)
53+
c1 <- init.component.init
54+
_ = assert(init.inits.get() == 1)
55+
c2 <- init.component.init
56+
_ = assert(init.inits.get() == 1)
57+
} yield assert(c1 eq c2))
58+
59+
test("AsyncInitializingComponent singleton initializes once and returns same instance")(for {
60+
_ <- Future.unit
61+
_ = assert(asyncInit.inits.get() == 0)
62+
c1 <- asyncInit.component.init
63+
_ = assert(asyncInit.inits.get() == 1)
64+
c2 <- asyncInit.component.init
65+
_ = assert(asyncInit.inits.get() == 1)
66+
} yield assert(c1 eq c2))
67+
68+
test("DisposableComponent destroy triggers side effect") {
69+
assert(!disposable.destroyed.get())
70+
disposable.component.destroy.map { _ =>
71+
assert(disposable.destroyed.get())
72+
}
73+
}
74+
75+
test("AsyncDisposableComponent destroy triggers side effect") {
76+
assert(!asyncDisposable.destroyed.get())
77+
asyncDisposable.component.destroy.map { _ =>
78+
assert(asyncDisposable.destroyed.get())
79+
}
80+
}
81+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.avsystem.commons
2+
package di
3+
4+
trait InitializingComponent {
5+
def init(): Unit
6+
final def initialized(): this.type = init().thenReturn(this)
7+
}
8+
9+
trait DisposableComponent {
10+
def destroy(): Unit
11+
}
12+
13+
trait AsyncInitializingComponent {
14+
def init()(implicit ec: ExecutionContext): Future[Unit]
15+
final def initialized()(implicit ec: ExecutionContext): Future[this.type] = init()(using ec).map[this.type](_ => this)(using ec)
16+
}
17+
18+
trait AsyncDisposableComponent {
19+
def destroy()(implicit ec: ExecutionContext): Future[Unit]
20+
}

0 commit comments

Comments
 (0)