Skip to content

Commit

Permalink
Add tests for Merge Option-integrations, and Patcher Options and Opti…
Browse files Browse the repository at this point in the history
…on-integrations
  • Loading branch information
MateuszKubuszok committed Jan 16, 2025
1 parent 23b90ae commit 643a60b
Show file tree
Hide file tree
Showing 5 changed files with 587 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ private[compiletime] trait ChimneyExprsPlatform extends ChimneyExprs { this: Chi
optionalValue: Expr[integrations.OptionalValue[Optional, Value]],
optional: Expr[Optional],
optional2: Expr[Optional]
): Expr[Optional] = c.Expr[Optional](q"$optionalValue.fold($optional, $optional2)")
): Expr[Optional] = c.Expr[Optional](q"$optionalValue.orElse($optional, $optional2)")
}

object PartiallyBuildIterable extends PartiallyBuildIterableModule {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
package io.scalaland.chimney

import io.scalaland.chimney.dsl.*
import io.scalaland.chimney.fixtures.*

class PartialMergingIntegrationsSpec extends ChimneySpec {

import TotalTransformerIntegrationsSpec.*

group("setting .withFallback(fallbackValue)") {

test("should use only source Possible when no merging strategy is enabled") {
import merges.Nested

implicit val s2i: PartialTransformer[String, Int] = PartialTransformer.fromFunction[String, Int](_.toInt)

"10"
.intoPartial[Possible[Int]]
.withFallback(20)
.transform
.asOption ==> Some(Possible.Present(10))
Possible("10")
.intoPartial[Possible[Int]]
.withFallback(Possible(20))
.transform
.asOption ==> Some(Possible.Present(10))
Possible("10")
.intoPartial[Possible[Int]]
.withFallback(Possible.Nope: Possible[Int])
.transform
.asOption ==> Some(Possible.Present(10))
(Possible.Nope: Possible[String])
.intoPartial[Possible[Int]]
.withFallback(Possible(20))
.transform
.asOption ==> Some(Possible.Nope)
(Possible.Nope: Possible[String])
.intoPartial[Possible[Int]]
.withFallback(Possible.Nope: Possible[Int])
.transform
.asOption ==> Some(Possible.Nope)

Nested("10")
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(20))
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible("10"))
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible(20)))
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible("10"))
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible.Nope: Possible[String]))
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible.Nope: Possible[String])
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible(20)))
.transform
.asOption ==> Some(Nested(Possible.Nope))
Nested(Possible.Nope: Possible[String])
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible.Nope: Possible[Int]))
.transform
.asOption ==> Some(Nested(Possible.Nope))
}
}

group("setting .withFallbackFrom(selectorFrom)(fallbackValue)") {

test("should use only source Possible when no merging strategy is enabled") {
import merges.Nested

implicit val s2i: PartialTransformer[String, Int] = PartialTransformer.fromFunction[String, Int](_.toInt)

Nested("10")
.intoPartial[Nested[Possible[Int]]]
.withFallbackFrom(_.value)(20)
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible("10"))
.intoPartial[Nested[Possible[Int]]]
.withFallbackFrom(_.value)(Possible(20))
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible("10"))
.intoPartial[Nested[Possible[Int]]]
.withFallbackFrom(_.value)(Possible.Nope: Possible[String])
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible.Nope: Possible[String])
.intoPartial[Nested[Possible[Int]]]
.withFallbackFrom(_.value)(Possible(20))
.transform
.asOption ==> Some(Nested(Possible.Nope))
Nested(Possible.Nope: Possible[String])
.intoPartial[Nested[Possible[Int]]]
.withFallbackFrom(_.value)(Possible.Nope: Possible[Int])
.transform
.asOption ==> Some(Nested(Possible.Nope))

Nested(Nested("10"))
.intoPartial[Nested[Nested[Possible[Int]]]]
.withFallbackFrom(_.value)(Nested(20))
.transform
.asOption ==> Some(Nested(Nested(Possible.Present(10))))
Nested(Nested(Possible("10")))
.intoPartial[Nested[Nested[Possible[Int]]]]
.withFallbackFrom(_.value)(Nested(Possible(20)))
.transform
.asOption ==> Some(Nested(Nested(Possible.Present(10))))
Nested(Nested(Possible("10")))
.intoPartial[Nested[Nested[Possible[Int]]]]
.withFallbackFrom(_.value)(Nested(Possible.Nope: Possible[Int]))
.transform
.asOption ==> Some(Nested(Nested(Possible.Present(10))))
Nested(Nested(Possible.Nope: Possible[String]))
.intoPartial[Nested[Nested[Possible[Int]]]]
.withFallbackFrom(_.value)(Nested(Possible(20)))
.transform
.asOption ==> Some(Nested(Nested(Possible.Nope)))
Nested(Nested(Possible.Nope: Possible[String]))
.intoPartial[Nested[Nested[Possible[Int]]]]
.withFallbackFrom(_.value)(Nested(Possible.Nope: Possible[Int]))
.transform
.asOption ==> Some(Nested(Nested(Possible.Nope)))
}
}

group("flag .enableOptionFallbackMerge(SourceOrElseFallback)") {

test("should merge Possibles from source to fallback when SourceOrElseFallback strategy is enabled") {
import merges.Nested

implicit val s2i: PartialTransformer[String, Int] = PartialTransformer.fromFunction[String, Int](_.toInt)

"10"
.intoPartial[Possible[Int]]
.withFallback(20)
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Possible.Present(10))
Possible("10")
.intoPartial[Possible[Int]]
.withFallback(Possible(20))
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Possible.Present(10))
Possible("10")
.intoPartial[Possible[Int]]
.withFallback(Possible.Nope: Possible[String])
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Possible.Present(10))
(Possible.Nope: Possible[String])
.intoPartial[Possible[Int]]
.withFallback(Possible(20))
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Possible.Present(20))
(Possible.Nope: Possible[String])
.intoPartial[Possible[Int]]
.withFallback(Possible.Nope: Possible[Int])
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Possible.Nope)

Nested("10")
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(20))
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible("10"))
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible(20)))
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible("10"))
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible.Nope: Possible[Int]))
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible.Nope: Possible[String])
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible(20)))
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Nested(Possible.Present(20)))
Nested(Possible.Nope: Possible[String])
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible.Nope: Possible[Int]))
.enableOptionFallbackMerge(SourceOrElseFallback)
.transform
.asOption ==> Some(Nested(Possible.Nope))
}

test("should merge Possibles from fallback to source when FallbackOrElseSource strategy is enabled") {
import merges.Nested

implicit val s2i: PartialTransformer[String, Int] = PartialTransformer.fromFunction[String, Int](_.toInt)

"10"
.intoPartial[Possible[Int]]
.withFallback(20)
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Possible.Present(20))
Possible("10")
.intoPartial[Possible[Int]]
.withFallback(Possible(20))
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Possible.Present(20))
Possible("10")
.intoPartial[Possible[Int]]
.withFallback(Possible.Nope: Possible[Int])
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Possible.Present(10))
(Possible.Nope: Possible[String])
.intoPartial[Possible[Int]]
.withFallback(Possible(20))
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Possible.Present(20))
(Possible.Nope: Possible[String])
.intoPartial[Possible[Int]]
.withFallback(Possible.Nope: Possible[Int])
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Possible.Nope)

Nested("10")
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(20))
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Nested(Possible.Present(20)))
Nested(Possible("10"))
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible(20)))
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Nested(Possible.Present(20)))
Nested(Possible("10"))
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible.Nope: Possible[Int]))
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Nested(Possible.Present(10)))
Nested(Possible.Nope: Possible[String])
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible(20)))
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Nested(Possible.Present(20)))
Nested(Possible.Nope: Possible[String])
.intoPartial[Nested[Possible[Int]]]
.withFallback(Nested(Possible.Nope: Possible[Int]))
.enableOptionFallbackMerge(FallbackOrElseSource)
.transform
.asOption ==> Some(Nested(Possible.Nope))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.scalaland.chimney

import io.scalaland.chimney.dsl.*

class PatcherIntegrationsSpec extends ChimneySpec {

import TotalTransformerIntegrationsSpec.*
import PatcherStdLibSpec.*

test("patch Option-type with Option-type of the same type, replacing the value") {
Possible(Bar("a")).patchUsing(Possible(Bar("b"))) ==> Possible(Bar("b"))
Possible(Bar("a")).using(Possible(Bar("b"))).patch ==> Possible(Bar("b"))

Possible(Bar("a")).patchUsing(Possible.Nope: Possible[Bar]) ==> Possible.Nope
Possible(Bar("a")).using(Possible.Nope: Possible[Bar]).patch ==> Possible.Nope

(Possible.Nope: Possible[Bar]).patchUsing(Possible(Bar("b"))) ==> Possible(Bar("b"))
(Possible.Nope: Possible[Bar]).using(Possible(Bar("b"))).patch ==> Possible(Bar("b"))

(Possible.Nope: Possible[Bar]).patchUsing(Possible.Nope: Possible[Bar]) ==> Possible.Nope
(Possible.Nope: Possible[Bar]).using(Possible.Nope: Possible[Bar]).patch ==> Possible.Nope
}

group("flag .ignoreNoneInPatch") {

test("should patch Option-type with Option-type of the same type, with patch.orElse(obj)") {
Possible(Bar("a")).using(Possible.Nope: Possible[Bar]).ignoreNoneInPatch.patch ==> Possible(Bar("a"))
Possible(Bar("a")).using(Possible(Bar("b"))).ignoreNoneInPatch.patch ==> Possible(Bar("b"))
(Possible.Nope: Possible[Bar]).using(Possible(Bar("b"))).ignoreNoneInPatch.patch ==> Possible(Bar("b"))
(Possible.Nope: Possible[Bar]).using(Possible.Nope: Possible[Bar]).ignoreNoneInPatch.patch ==> Possible.Nope

locally {
implicit val ctx = PatcherConfiguration.default.ignoreNoneInPatch

Possible(Bar("a")).patchUsing(Possible(Bar("b"))) ==> Possible(Bar("b"))
Possible(Bar("a")).patchUsing(Possible.Nope: Possible[Bar]) ==> Possible(Bar("a"))
(Possible.Nope: Possible[Bar]).patchUsing(Possible(Bar("b"))) ==> Possible(Bar("b"))
(Possible.Nope: Possible[Bar]).patchUsing(Possible.Nope: Possible[Bar]) ==> Possible.Nope
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.scalaland.chimney

import io.scalaland.chimney.dsl.*

class PatcherStdLibSpec extends ChimneySpec {

import PatcherStdLibSpec.*

test("patch Option-type with Option-type of the same type, replacing the value") {
Option(Bar("a")).patchUsing(Option(Bar("b"))) ==> Option(Bar("b"))
Option(Bar("a")).using(Option(Bar("b"))).patch ==> Option(Bar("b"))

Option(Bar("a")).patchUsing(None: Option[Bar]) ==> None
Option(Bar("a")).using(None: Option[Bar]).patch ==> None

(None: Option[Bar]).patchUsing(Option(Bar("b"))) ==> Option(Bar("b"))
(None: Option[Bar]).using(Option(Bar("b"))).patch ==> Option(Bar("b"))

(None: Option[Bar]).patchUsing(None: Option[Bar]) ==> None
(None: Option[Bar]).using(None: Option[Bar]).patch ==> None
}

group("flag .ignoreNoneInPatch") {

test("should patch Option-type with Option-type of the same type, with patch.orElse(obj)") {
Option(Bar("a")).using(None: Option[Bar]).ignoreNoneInPatch.patch ==> Option(Bar("a"))
Option(Bar("a")).using(Option(Bar("b"))).ignoreNoneInPatch.patch ==> Option(Bar("b"))
(None: Option[Bar]).using(Option(Bar("b"))).ignoreNoneInPatch.patch ==> Option(Bar("b"))
(None: Option[Bar]).using(None: Option[Bar]).ignoreNoneInPatch.patch ==> None

locally {
implicit val ctx = PatcherConfiguration.default.ignoreNoneInPatch

Option(Bar("a")).patchUsing(Option(Bar("b"))) ==> Option(Bar("b"))
Option(Bar("a")).patchUsing(None: Option[Bar]) ==> Option(Bar("a"))
(None: Option[Bar]).patchUsing(Option(Bar("b"))) ==> Option(Bar("b"))
(None: Option[Bar]).patchUsing(None: Option[Bar]) ==> None
}
}
}
}
object PatcherStdLibSpec {

case class Foo(value: String, extra: Int)
case class Bar(value: String)
}
Loading

0 comments on commit 643a60b

Please sign in to comment.