Skip to content

Commit a554f4e

Browse files
authored
Merge pull request #14 from softwaremill/restructure-source-tests
Extract some Source test cases to separate classes
2 parents 8efe299 + 56c824a commit a554f4e

5 files changed

+226
-185
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package ox.channels
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should.Matchers
5+
import ox.*
6+
7+
class SourceOpsFactoryMethodsTest extends AnyFlatSpec with Matchers {
8+
9+
behavior of "Source factory methods"
10+
11+
it should "create a source from a fork" in {
12+
scoped {
13+
val f = fork(1)
14+
val c = Source.fromFork(f)
15+
c.toList shouldBe List(1)
16+
}
17+
}
18+
19+
it should "create an iterating source" in {
20+
scoped {
21+
val c = Source.iterate(1)(_ + 1)
22+
c.take(3).toList shouldBe List(1, 2, 3)
23+
}
24+
}
25+
26+
it should "unfold a function" in {
27+
scoped {
28+
val c = Source.unfold(0)(i => if i < 3 then Some((i, i + 1)) else None)
29+
c.toList shouldBe List(0, 1, 2)
30+
}
31+
}
32+
33+
it should "produce a range" in {
34+
scoped {
35+
Source.range(1, 5, 1).toList shouldBe List(1, 2, 3, 4, 5)
36+
Source.range(1, 5, 2).toList shouldBe List(1, 3, 5)
37+
Source.range(1, 11, 3).toList shouldBe List(1, 4, 7, 10)
38+
}
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package ox.channels
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should.Matchers
5+
import ox.*
6+
7+
class SourceOpsForeachTest extends AnyFlatSpec with Matchers {
8+
9+
behavior of "Source.foreach"
10+
11+
it should "iterate over a source" in {
12+
val c = Channel[Int](10)
13+
c.send(1)
14+
c.send(2)
15+
c.send(3)
16+
c.done()
17+
18+
var r: List[Int] = Nil
19+
c.foreach(v => r = v :: r)
20+
21+
r shouldBe List(3, 2, 1)
22+
}
23+
24+
it should "iterate over a source using for-syntax" in {
25+
val c = Channel[Int](10)
26+
c.send(1)
27+
c.send(2)
28+
c.send(3)
29+
c.done()
30+
31+
var r: List[Int] = Nil
32+
for {
33+
v <- c
34+
} r = v :: r
35+
36+
r shouldBe List(3, 2, 1)
37+
}
38+
39+
it should "convert source to a list" in {
40+
val c = Channel[Int](10)
41+
c.send(1)
42+
c.send(2)
43+
c.send(3)
44+
c.done()
45+
46+
c.toList shouldBe List(1, 2, 3)
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package ox.channels
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should.Matchers
5+
import ox.*
6+
7+
class SourceOpsMapTest extends AnyFlatSpec with Matchers {
8+
9+
behavior of "Source.map"
10+
11+
it should "map over a source" in {
12+
scoped {
13+
val c = Channel[Int]()
14+
fork {
15+
c.send(1)
16+
c.send(2)
17+
c.send(3)
18+
c.done()
19+
}
20+
21+
val s = c.map(_ * 10)
22+
23+
s.receive() shouldBe 10
24+
s.receive() shouldBe 20
25+
s.receive() shouldBe 30
26+
s.receive() shouldBe ChannelClosed.Done
27+
}
28+
}
29+
30+
it should "map over a source (stress test)" in {
31+
// this demonstrated a race condition where a cell was added by select to the waiting list by T1, completed by T2,
32+
// which then subsequently completed the stream; only then T1 wakes up, and checks if no new elements have been added
33+
for (_ <- 1 to 100000) {
34+
scoped {
35+
val c = Channel[Int]()
36+
fork {
37+
c.send(1)
38+
c.done()
39+
}
40+
41+
val s = c.map(_ * 10)
42+
43+
s.receive() shouldBe 10
44+
s.receive() shouldBe ChannelClosed.Done
45+
}
46+
}
47+
}
48+
49+
it should "map over a source using for-syntax" in {
50+
scoped {
51+
val c = Channel[Int]()
52+
fork {
53+
c.send(1)
54+
c.send(2)
55+
c.send(3)
56+
c.done()
57+
}
58+
59+
val s = for {
60+
v <- c
61+
} yield v * 2
62+
63+
s.receive() shouldBe 2
64+
s.receive() shouldBe 4
65+
s.receive() shouldBe 6
66+
s.receive() shouldBe ChannelClosed.Done
67+
}
68+
}
69+
}

core/src/test/scala/ox/channels/SourceOpsTest.scala

-185
Original file line numberDiff line numberDiff line change
@@ -11,161 +11,6 @@ import scala.concurrent.duration.DurationInt
1111
import scala.jdk.CollectionConverters.*
1212

1313
class SourceOpsTest extends AnyFlatSpec with Matchers with Eventually {
14-
it should "map over a source" in {
15-
scoped {
16-
val c = Channel[Int]()
17-
fork {
18-
c.send(1)
19-
c.send(2)
20-
c.send(3)
21-
c.done()
22-
}
23-
24-
val s = c.map(_ * 10)
25-
26-
s.receive() shouldBe 10
27-
s.receive() shouldBe 20
28-
s.receive() shouldBe 30
29-
s.receive() shouldBe ChannelClosed.Done
30-
}
31-
}
32-
33-
it should "map over a source (stress test)" in {
34-
// this demonstrated a race condition where a cell was added by select to the waiting list by T1, completed by T2,
35-
// which then subsequently completed the stream; only then T1 wakes up, and checks if no new elements have been added
36-
for (_ <- 1 to 100000) {
37-
scoped {
38-
val c = Channel[Int]()
39-
fork {
40-
c.send(1)
41-
c.done()
42-
}
43-
44-
val s = c.map(_ * 10)
45-
46-
s.receive() shouldBe 10
47-
s.receive() shouldBe ChannelClosed.Done
48-
}
49-
}
50-
}
51-
52-
it should "map over a source using for-syntax" in {
53-
scoped {
54-
val c = Channel[Int]()
55-
fork {
56-
c.send(1)
57-
c.send(2)
58-
c.send(3)
59-
c.done()
60-
}
61-
62-
val s = for {
63-
v <- c
64-
} yield v * 2
65-
66-
s.receive() shouldBe 2
67-
s.receive() shouldBe 4
68-
s.receive() shouldBe 6
69-
s.receive() shouldBe ChannelClosed.Done
70-
}
71-
}
72-
73-
it should "iterate over a source" in {
74-
val c = Channel[Int](10)
75-
c.send(1)
76-
c.send(2)
77-
c.send(3)
78-
c.done()
79-
80-
var r: List[Int] = Nil
81-
c.foreach(v => r = v :: r)
82-
83-
r shouldBe List(3, 2, 1)
84-
}
85-
86-
it should "iterate over a source using for-syntax" in {
87-
val c = Channel[Int](10)
88-
c.send(1)
89-
c.send(2)
90-
c.send(3)
91-
c.done()
92-
93-
var r: List[Int] = Nil
94-
for {
95-
v <- c
96-
} r = v :: r
97-
98-
r shouldBe List(3, 2, 1)
99-
}
100-
101-
it should "convert source to a list" in {
102-
val c = Channel[Int](10)
103-
c.send(1)
104-
c.send(2)
105-
c.send(3)
106-
c.done()
107-
108-
c.toList shouldBe List(1, 2, 3)
109-
}
110-
111-
it should "transform a source using a simple map" in {
112-
val c = Channel[Int](10)
113-
c.send(1)
114-
c.send(2)
115-
c.send(3)
116-
c.done()
117-
118-
scoped {
119-
c.transform(_.map(_ * 2)).toList shouldBe List(2, 4, 6)
120-
}
121-
}
122-
123-
it should "transform a source using a complex chain of operations" in {
124-
val c = Channel[Int](10)
125-
c.send(1)
126-
c.send(2)
127-
c.send(3)
128-
c.send(4)
129-
c.done()
130-
131-
scoped {
132-
c.transform(_.drop(2).flatMap(i => List(i, i + 1, i + 2)).filter(_ % 2 == 0)).toList shouldBe List(4, 4, 6)
133-
}
134-
}
135-
136-
it should "transform an infinite source" in {
137-
val c = Channel[Int]()
138-
scoped {
139-
fork {
140-
var i = 0
141-
while true do
142-
c.send(i)
143-
i += 1
144-
}
145-
146-
val s = c.transform(_.filter(_ % 2 == 0).flatMap(i => List(i, i + 1)))
147-
s.receive() shouldBe 0
148-
s.receive() shouldBe 1
149-
s.receive() shouldBe 2
150-
}
151-
}
152-
153-
it should "transform an infinite source (stress test)" in {
154-
for (_ <- 1 to 1000) { // this nicely demonstrated two race conditions
155-
val c = Channel[Int]()
156-
scoped {
157-
fork {
158-
var i = 0
159-
while true do
160-
c.send(i)
161-
i += 1
162-
}
163-
164-
val s = c.transform(x => x)
165-
s.receive() shouldBe 0
166-
}
167-
}
168-
}
16914

17015
it should "tick regularly" in {
17116
scoped {
@@ -231,28 +76,6 @@ class SourceOpsTest extends AnyFlatSpec with Matchers with Eventually {
23176
}
23277
}
23378

234-
it should "create a source from a fork" in {
235-
scoped {
236-
val f = fork(1)
237-
val c = Source.fromFork(f)
238-
c.toList shouldBe List(1)
239-
}
240-
}
241-
242-
it should "create an iterating source" in {
243-
scoped {
244-
val c = Source.iterate(1)(_ + 1)
245-
c.take(3).toList shouldBe List(1, 2, 3)
246-
}
247-
}
248-
249-
it should "unfold a function" in {
250-
scoped {
251-
val c = Source.unfold(0)(i => if i < 3 then Some((i, i + 1)) else None)
252-
c.toList shouldBe List(0, 1, 2)
253-
}
254-
}
255-
25679
it should "concatenate sources" in {
25780
scoped {
25881
val s1 = Source.fromValues("a", "b", "c")
@@ -264,12 +87,4 @@ class SourceOpsTest extends AnyFlatSpec with Matchers with Eventually {
26487
s.toList shouldBe List("a", "b", "c", "d", "e", "f", "g", "h", "i")
26588
}
26689
}
267-
268-
it should "produce a range" in {
269-
scoped {
270-
Source.range(1, 5, 1).toList shouldBe List(1, 2, 3, 4, 5)
271-
Source.range(1, 5, 2).toList shouldBe List(1, 3, 5)
272-
Source.range(1, 11, 3).toList shouldBe List(1, 4, 7, 10)
273-
}
274-
}
27590
}

0 commit comments

Comments
 (0)