Skip to content

Commit 3d99a41

Browse files
committed
add BireducibleSuite
1 parent 4d46a41 commit 3d99a41

File tree

1 file changed

+214
-0
lines changed

1 file changed

+214
-0
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*
2+
* Copyright (c) 2015 Typelevel
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
5+
* this software and associated documentation files (the "Software"), to deal in
6+
* the Software without restriction, including without limitation the rights to
7+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8+
* the Software, and to permit persons to whom the Software is furnished to do so,
9+
* subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
package cats
23+
package tests
24+
25+
import cats.data.Ior
26+
import cats.data.NonEmptyList
27+
import cats.laws.discipline.arbitrary._
28+
import cats.syntax.reducible._
29+
import org.scalacheck.Prop
30+
31+
class BireducibleSuite extends CatsSuite {
32+
import BireducibleSuite._
33+
34+
// Bireducible.bireduceLeft tests
35+
//
36+
property("Bireducible.bireduceLeft[IorNel]") {
37+
Prop.forAll { (testee: NonEmptyList[String Ior List[Byte]]) =>
38+
val expected = testee.reduce
39+
val obtained = Bireducible.bireduceLeft(IorNel(testee))(_ + _, _ ::: _)
40+
41+
assertEquals(obtained, expected)
42+
}
43+
}
44+
property("Bireducible.bireduceLeft[NelIor]") {
45+
Prop.forAll { (testee: NonEmptyList[List[Char]] Ior NonEmptyList[String]) =>
46+
val expected = testee.bimap(_.reduce, _.reduce)
47+
val obtained = Bireducible.bireduceLeft(NelIor(testee))(_ ::: _, _ + _)
48+
49+
assertEquals(obtained, expected)
50+
}
51+
}
52+
// Bireducible.bireduceRight tests
53+
//
54+
property("Bireducible.bireduceRight[IorNel]") {
55+
Prop.forAll { (testee: NonEmptyList[String Ior List[Char]]) =>
56+
val expected = testee.reduce
57+
val obtained =
58+
Bireducible
59+
.bireduceRight(IorNel(testee))(
60+
(a, ea) => ea.map(a + _),
61+
(b, eb) => eb.map(b ::: _)
62+
)
63+
.value
64+
65+
assertEquals(obtained, expected)
66+
}
67+
}
68+
property("Bireducible.bireduceRight[NelIor]") {
69+
Prop.forAll { (testee: NonEmptyList[List[Byte]] Ior NonEmptyList[String]) =>
70+
val expected = testee.bimap(_.reduce, _.reduce)
71+
val obtained =
72+
Bireducible
73+
.bireduceRight(NelIor(testee))(
74+
(a, ea) => ea.map(a ::: _),
75+
(b, eb) => eb.map(b + _)
76+
)
77+
.value
78+
79+
assertEquals(obtained, expected)
80+
}
81+
}
82+
// Bireducible.bireduceMap tests
83+
//
84+
property("Bireducible.bireduceMap[IorNel]") {
85+
Prop.forAll { (testee: NonEmptyList[String Ior String]) =>
86+
val expected = testee.map(_.merge).reduce
87+
val obtained = Bireducible.bireduceMap(IorNel(testee))(identity, identity)
88+
89+
assertNoDiff(obtained, expected)
90+
}
91+
}
92+
property("Bireducible.bireduceMap[NelIor]") {
93+
Prop.forAll { (testee: NonEmptyList[String] Ior NonEmptyList[String]) =>
94+
val expected = testee.bimap(_.reduce, _.reduce).merge
95+
val obtained = Bireducible.bireduceMap(NelIor(testee))(identity, identity)
96+
97+
assertNoDiff(obtained, expected)
98+
}
99+
}
100+
// Bireducible.bireduce tests
101+
//
102+
property("Bireducible.bireduce[IorNel]") {
103+
Prop.forAll { (testee: NonEmptyList[List[Byte] Ior List[Char]]) =>
104+
val expected = testee.reduce
105+
val obtained = Bireducible.bireduce(IorNel(testee))
106+
107+
assertEquals(obtained, expected)
108+
}
109+
}
110+
property("Bireducible.bireduce[NelIor]") {
111+
Prop.forAll { (testee: NonEmptyList[List[Char]] Ior NonEmptyList[List[Byte]]) =>
112+
val expected = testee.bimap(_.reduce, _.reduce)
113+
val obtained = Bireducible.bireduce(NelIor(testee))
114+
115+
assertEquals(obtained, expected)
116+
}
117+
}
118+
}
119+
120+
object BireducibleSuite {
121+
122+
/** `Bireducible` that can be collapsed row by row.
123+
*/
124+
final case class IorNel[A, B](value: NonEmptyList[A Ior B]) extends AnyVal
125+
126+
/** `Bireducible` that can be collapsed by collapsing one of the columns followed by the other one.
127+
*/
128+
final case class NelIor[A, B](value: NonEmptyList[A] Ior NonEmptyList[B]) extends AnyVal
129+
130+
implicit val testIorNelBireducible: Bireducible[IorNel] = new Bireducible[IorNel] {
131+
132+
override def bifoldLeft[A, B, C](fab: IorNel[A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C = ???
133+
134+
override def bifoldRight[A, B, C](fab: IorNel[A, B], c: Eval[C])(
135+
f: (A, Eval[C]) => Eval[C],
136+
g: (B, Eval[C]) => Eval[C]
137+
): Eval[C] = ???
138+
139+
override def bireduceLeftTo[A, B, C](fab: IorNel[A, B])(
140+
ma: A => C,
141+
mb: B => C
142+
)(
143+
mca: (C, A) => C,
144+
mcb: (C, B) => C
145+
): C = {
146+
fab.value.reduceLeftTo { ab =>
147+
ab.fold(ma, mb, (a, b) => mcb(ma(a), b))
148+
} { (c, ab) =>
149+
ab.fold(mca(c, _), mcb(c, _), (a, b) => mcb(mca(c, a), b))
150+
}
151+
}
152+
153+
override def bireduceRightTo[A, B, C](
154+
fab: IorNel[A, B]
155+
)(
156+
ma: A => Eval[C],
157+
mb: B => Eval[C]
158+
)(
159+
mac: (A, Eval[C]) => Eval[C],
160+
mbc: (B, Eval[C]) => Eval[C]
161+
): Eval[C] =
162+
fab.value.reduceRightTo { ab =>
163+
// Enforcing `.value` here because this parameter is defined as `A => B`.
164+
// TODO: consider making `reduceRightTo` to take `A => Eval[B]` to improve its composability.
165+
ab.fold(ma, mb, (a, b) => mbc(b, ma(a))).value
166+
} { (ab, ec) =>
167+
ab.fold(a => mac(a, ec), b => mbc(b, ec), (a, b) => mbc(b, mac(a, ec)))
168+
}
169+
}
170+
171+
implicit val testNelIorBireducible: Bireducible[NelIor] = new Bireducible[NelIor] {
172+
173+
override def bifoldLeft[A, B, C](fab: NelIor[A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C = ???
174+
175+
override def bifoldRight[A, B, C](fab: NelIor[A, B], c: Eval[C])(
176+
f: (A, Eval[C]) => Eval[C],
177+
g: (B, Eval[C]) => Eval[C]
178+
): Eval[C] = ???
179+
180+
override def bireduceLeftTo[A, B, C](fab: NelIor[A, B])(
181+
ma: A => C,
182+
mb: B => C
183+
)(
184+
mca: (C, A) => C,
185+
mcb: (C, B) => C
186+
): C =
187+
fab.value.fold(
188+
_.reduceLeftTo(ma)(mca),
189+
_.reduceLeftTo(mb)(mcb),
190+
{ (as, bs) =>
191+
val ca = as.reduceLeftTo(ma)(mca)
192+
val cb = bs.foldLeft(ca)(mcb)
193+
cb
194+
}
195+
)
196+
197+
override def bireduceRightTo[A, B, C](fab: NelIor[A, B])(
198+
ma: A => Eval[C],
199+
mb: B => Eval[C]
200+
)(
201+
mac: (A, Eval[C]) => Eval[C],
202+
mbc: (B, Eval[C]) => Eval[C]
203+
): Eval[C] =
204+
fab.value.fold(
205+
_.reduceRightTo(ma(_).value)(mac),
206+
_.reduceRightTo(mb(_).value)(mbc),
207+
{ (as, bs) =>
208+
val ca = as.reduceRightTo(ma(_).value)(mac)
209+
val cb = bs.foldRight(ca)(mbc)
210+
cb
211+
}
212+
)
213+
}
214+
}

0 commit comments

Comments
 (0)