diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala index e428dd04b..85054795b 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformProductToProductRuleModule.scala @@ -461,11 +461,10 @@ private[compiletime] trait TransformProductToProductRuleModule { this: Derivatio case Nil => whenAbsent case runtimeFieldOverride :: Nil => - import FromOperation.{Computed, ComputedPartial} import io.scalaland.chimney.internal.compiletime.DerivationError.TransformerError as TError import io.scalaland.chimney.internal.compiletime.NotSupportedOperationFromPath as NotSupportedFrom useOverride[From, To, CtorParam](toName, runtimeFieldOverride).recoverWith { - case DerivationErrors(TError(NotSupportedFrom(Computed | ComputedPartial, `toName`, _, _)), Vector()) => + case DerivationErrors(TError(NotSupportedFrom(_, `toName`, _, _)), Vector()) => // If we cannot extract value in .withFieldComputedFrom/.withFieldComputedPartialFrom, it might be because // path is matching on TargetSide, but SourceSide requires recursion, TransformationContext update, // and then matching on some other rule. diff --git a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala index 692c0b40d..932be55fb 100644 --- a/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala +++ b/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala @@ -65,9 +65,9 @@ private[compiletime] trait TransformSealedHierarchyToSealedHierarchyRuleModule { case (_, TransformerOverride.Computed(_, targetPath, _)) => targetPath == ctx.currentTgt case (_, TransformerOverride.ComputedPartial(_, targetPath, _)) => targetPath == ctx.currentTgt case (_, TransformerOverride.Renamed(_, targetPath)) => - targetPath match { - case Path.AtSubtype(someTo, root) => someTo.Underlying <:< Type[To] && root == ctx.currentTgt - case _ => false + targetPath.drop(ctx.currentTgt) match { + case Some(Path.AtSubtype(someTo, root)) => someTo.Underlying <:< Type[To] && root == Path.Root + case _ => false } } .toList @@ -105,7 +105,7 @@ private[compiletime] trait TransformSealedHierarchyToSealedHierarchyRuleModule { runtimeData.asInstanceOfExpr[From => partial.Result[To]].apply(fromExpr) ) case TransformerOverride.Renamed(_, targetPath) => - val Path.AtSubtype(someTo, _) = targetPath: @unchecked + val Some(Path.AtSubtype(someTo, _)) = targetPath.drop(ctx.currentTgt): @unchecked // We're constructing: // case someFromExpr: $someFrom => $derivedToSubtype.asInstance import someTo.Underlying as SomeTo diff --git a/chimney/src/test/scala/io/scalaland/chimney/PartialTransformerSealedHierarchySpec.scala b/chimney/src/test/scala/io/scalaland/chimney/PartialTransformerSealedHierarchySpec.scala index 198ef96d6..9729aa92b 100644 --- a/chimney/src/test/scala/io/scalaland/chimney/PartialTransformerSealedHierarchySpec.scala +++ b/chimney/src/test/scala/io/scalaland/chimney/PartialTransformerSealedHierarchySpec.scala @@ -366,30 +366,30 @@ class PartialTransformerSealedHierarchySpec extends ChimneySpec { test( """transform sealed hierarchies from "superset" of case objects to "subset" of case objects when user-provided mapping handled additional cases""" ) { - def blackIsRed(b: colors2.Black.type): partial.Result[colors1.Color] = + def blackIsFail(b: colors2.Black.type): partial.Result[colors1.Color] = partial.Result.fromEmpty (colors2.Black: colors2.Color) .intoPartial[colors1.Color] - .withSealedSubtypeHandledPartial(blackIsRed) + .withSealedSubtypeHandledPartial(blackIsFail) .transform .asOption ==> None (colors2.Red: colors2.Color) .intoPartial[colors1.Color] - .withSealedSubtypeHandledPartial(blackIsRed) + .withSealedSubtypeHandledPartial(blackIsFail) .transform .asOption ==> Some(colors1.Red) (colors2.Green: colors2.Color) .intoPartial[colors1.Color] - .withSealedSubtypeHandledPartial(blackIsRed) + .withSealedSubtypeHandledPartial(blackIsFail) .transform .asOption ==> Some(colors1.Green) (colors2.Blue: colors2.Color) .intoPartial[colors1.Color] - .withSealedSubtypeHandledPartial(blackIsRed) + .withSealedSubtypeHandledPartial(blackIsFail) .transform .asOption ==> Some(colors1.Blue) } @@ -453,30 +453,30 @@ class PartialTransformerSealedHierarchySpec extends ChimneySpec { test( """transform sealed hierarchies from "superset" of case objects to "subset" of case objects when user-provided mapping handled additional cases""" ) { - def blackIsRed(b: colors2.Black.type): partial.Result[colors1.Color] = + def blackIsFail(b: colors2.Black.type): partial.Result[colors1.Color] = partial.Result.fromEmpty (colors2.Black: colors2.Color) .intoPartial[colors1.Color] - .withEnumCaseHandledPartial(blackIsRed) + .withEnumCaseHandledPartial(blackIsFail) .transform .asOption ==> None (colors2.Red: colors2.Color) .intoPartial[colors1.Color] - .withEnumCaseHandledPartial(blackIsRed) + .withEnumCaseHandledPartial(blackIsFail) .transform .asOption ==> Some(colors1.Red) (colors2.Green: colors2.Color) .intoPartial[colors1.Color] - .withEnumCaseHandledPartial(blackIsRed) + .withEnumCaseHandledPartial(blackIsFail) .transform .asOption ==> Some(colors1.Green) (colors2.Blue: colors2.Color) .intoPartial[colors1.Color] - .withEnumCaseHandledPartial(blackIsRed) + .withEnumCaseHandledPartial(blackIsFail) .transform .asOption ==> Some(colors1.Blue) } @@ -587,6 +587,281 @@ class PartialTransformerSealedHierarchySpec extends ChimneySpec { } } + group("setting .withFieldComputedFrom(selectorFrom)(selectorTo, mapping)") { + + test("should provide support for withSealedSubtypeHandled/withEnumCaseHandled cases but nested") { + def blackIsRed(@unused b: colors2.Black.type): colors1.Color = + colors1.Red + + (Some(colors2.Black): Option[colors2.Color]) + .intoPartial[Option[colors1.Color]] + .withFieldComputedFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsRed) + .transform + .asOption ==> Some(Some(colors1.Red)) + (Some(colors2.Red): Option[colors2.Color]) + .intoPartial[Option[colors1.Color]] + .withFieldComputedFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsRed) + .transform + .asOption ==> Some(Some(colors1.Red)) + (Some(colors2.Green): Option[colors2.Color]) + .intoPartial[Option[colors1.Color]] + .withFieldComputedFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsRed) + .transform + .asOption ==> Some(Some(colors1.Green)) + (Some(colors2.Blue): Option[colors2.Color]) + .intoPartial[Option[colors1.Color]] + .withFieldComputedFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsRed) + .transform + .asOption ==> Some(Some(colors1.Blue)) + + (Left(colors2.Black): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform + .asOption ==> Some(Left(colors1.Red)) + (Left(colors2.Red): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform + .asOption ==> Some(Left(colors1.Red)) + (Left(colors2.Green): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform + .asOption ==> Some(Left(colors1.Green)) + (Left(colors2.Blue): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform + .asOption ==> Some(Left(colors1.Blue)) + (Right(colors2.Black): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform + .asOption ==> Some(Right(colors1.Red)) + (Right(colors2.Red): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform + .asOption ==> Some(Right(colors1.Red)) + (Right(colors2.Green): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform + .asOption ==> Some(Right(colors1.Green)) + (Right(colors2.Blue): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform + .asOption ==> Some(Right(colors1.Blue)) + + (List(colors2.Black, colors2.Red, colors2.Green, colors2.Blue): List[colors2.Color]) + .intoPartial[List[colors1.Color]] + .withFieldComputedFrom(_.everyItem.matching[colors2.Black.type])(_.everyItem, blackIsRed) + .transform + .asOption ==> Some(List(colors1.Red, colors1.Red, colors1.Green, colors1.Blue)) + + (Map( + colors2.Black -> colors2.Black, + colors2.Red -> colors2.Red, + colors2.Green -> colors2.Green, + colors2.Blue -> colors2.Blue + ): Map[ + colors2.Color, + colors2.Color + ]) + .intoPartial[Map[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.everyMapKey.matching[colors2.Black.type])(_.everyMapKey, blackIsRed) + .withFieldComputedFrom(_.everyMapValue.matching[colors2.Black.type])(_.everyMapValue, blackIsRed) + .transform + .asOption ==> Some( + Map( + colors1.Red -> colors1.Red, + colors1.Red -> colors1.Red, + colors1.Green -> colors1.Green, + colors1.Blue -> colors1.Blue + ) + ) + } + } + + group("setting .withFieldComputedPartialFrom(selectorFrom)(selectorTo, mapping)") { + + test("should provide support for withSealedSubtypeHandledPartial/withEnumCaseHandledPartial cases but nested") { + def blackIsFail(b: colors2.Black.type): partial.Result[colors1.Color] = + partial.Result.fromEmpty + + (Some(colors2.Black): Option[colors2.Color]) + .intoPartial[Option[colors1.Color]] + .withFieldComputedPartialFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsFail) + .transform + .asOption ==> None + (Some(colors2.Red): Option[colors2.Color]) + .intoPartial[Option[colors1.Color]] + .withFieldComputedPartialFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsFail) + .transform + .asOption ==> Some(Some(colors1.Red)) + (Some(colors2.Green): Option[colors2.Color]) + .intoPartial[Option[colors1.Color]] + .withFieldComputedPartialFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsFail) + .transform + .asOption ==> Some(Some(colors1.Green)) + (Some(colors2.Blue): Option[colors2.Color]) + .intoPartial[Option[colors1.Color]] + .withFieldComputedPartialFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsFail) + .transform + .asOption ==> Some(Some(colors1.Blue)) + + (Left(colors2.Black): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsFail) + .withFieldComputedPartialFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsFail) + .transform + .asOption ==> None + (Left(colors2.Red): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsFail) + .withFieldComputedPartialFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsFail) + .transform + .asOption ==> Some(Left(colors1.Red)) + (Left(colors2.Green): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsFail) + .withFieldComputedPartialFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsFail) + .transform + .asOption ==> Some(Left(colors1.Green)) + (Left(colors2.Blue): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsFail) + .withFieldComputedPartialFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsFail) + .transform + .asOption ==> Some(Left(colors1.Blue)) + (Right(colors2.Black): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsFail) + .withFieldComputedPartialFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsFail) + .transform + .asOption ==> None + (Right(colors2.Red): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsFail) + .withFieldComputedPartialFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsFail) + .transform + .asOption ==> Some(Right(colors1.Red)) + (Right(colors2.Green): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsFail) + .withFieldComputedPartialFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsFail) + .transform + .asOption ==> Some(Right(colors1.Green)) + (Right(colors2.Blue): Either[colors2.Color, colors2.Color]) + .intoPartial[Either[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsFail) + .withFieldComputedPartialFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsFail) + .transform + .asOption ==> Some(Right(colors1.Blue)) + + (List(colors2.Black): List[colors2.Color]) + .intoPartial[List[colors1.Color]] + .withFieldComputedPartialFrom(_.everyItem.matching[colors2.Black.type])(_.everyItem, blackIsFail) + .transform + .asOption ==> None + (List(colors2.Red, colors2.Green, colors2.Blue): List[colors2.Color]) + .intoPartial[List[colors1.Color]] + .withFieldComputedPartialFrom(_.everyItem.matching[colors2.Black.type])(_.everyItem, blackIsFail) + .transform + .asOption ==> Some(List(colors1.Red, colors1.Green, colors1.Blue)) + + (Map(colors2.Black -> colors2.Red): Map[colors2.Color, colors2.Color]) + .intoPartial[Map[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.everyMapKey.matching[colors2.Black.type])(_.everyMapKey, blackIsFail) + .withFieldComputedPartialFrom(_.everyMapValue.matching[colors2.Black.type])(_.everyMapValue, blackIsFail) + .transform + .asOption ==> None + (Map(colors2.Blue -> colors2.Black): Map[colors2.Color, colors2.Color]) + .intoPartial[Map[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.everyMapKey.matching[colors2.Black.type])(_.everyMapKey, blackIsFail) + .withFieldComputedPartialFrom(_.everyMapValue.matching[colors2.Black.type])(_.everyMapValue, blackIsFail) + .transform + .asOption ==> None + (Map(colors2.Red -> colors2.Red, colors2.Green -> colors2.Green, colors2.Blue -> colors2.Blue): Map[ + colors2.Color, + colors2.Color + ]) + .intoPartial[Map[colors1.Color, colors1.Color]] + .withFieldComputedPartialFrom(_.everyMapKey.matching[colors2.Black.type])(_.everyMapKey, blackIsFail) + .withFieldComputedPartialFrom(_.everyMapValue.matching[colors2.Black.type])(_.everyMapValue, blackIsFail) + .transform + .asOption ==> Some( + Map(colors1.Red -> colors1.Red, colors1.Green -> colors1.Green, colors1.Blue -> colors1.Blue) + ) + } + } + + group("settings .withFieldRenamed(selectorFrom, selectorTo)") { + + import fixtures.renames.Subtypes.* + + test("should provide support for withSealedSubtypeRenamed/withEnumCaseRenamed cases but nested") { + (Some(Foo3.Baz): Option[Foo3]) + .intoPartial[Option[Bar]] + .withFieldRenamed(_.matchingSome.matching[Foo3.Bazz.type], _.matchingSome.matching[Bar.Baz.type]) + .transform + .asOption ==> Some(Some(Bar.Baz)) + (Some(Foo3.Bazz): Option[Foo3]) + .intoPartial[Option[Bar]] + .withFieldRenamed(_.matchingSome.matching[Foo3.Bazz.type], _.matchingSome.matching[Bar.Baz.type]) + .transform + .asOption ==> Some(Some(Bar.Baz)) + + (Left(Foo3.Baz): Either[Foo3, Foo3]) + .intoPartial[Either[Bar, Bar]] + .withFieldRenamed(_.matchingLeft.matching[Foo3.Bazz.type], _.matchingLeft.matching[Bar.Baz.type]) + .withFieldRenamed(_.matchingRight.matching[Foo3.Bazz.type], _.matchingRight.matching[Bar.Baz.type]) + .transform + .asOption ==> Some(Left(Bar.Baz)) + (Left(Foo3.Bazz): Either[Foo3, Foo3]) + .intoPartial[Either[Bar, Bar]] + .withFieldRenamed(_.matchingLeft.matching[Foo3.Bazz.type], _.matchingLeft.matching[Bar.Baz.type]) + .withFieldRenamed(_.matchingRight.matching[Foo3.Bazz.type], _.matchingRight.matching[Bar.Baz.type]) + .transform + .asOption ==> Some(Left(Bar.Baz)) + (Right(Foo3.Baz): Either[Foo3, Foo3]) + .intoPartial[Either[Bar, Bar]] + .withFieldRenamed(_.matchingLeft.matching[Foo3.Bazz.type], _.matchingLeft.matching[Bar.Baz.type]) + .withFieldRenamed(_.matchingRight.matching[Foo3.Bazz.type], _.matchingRight.matching[Bar.Baz.type]) + .transform + .asOption ==> Some(Right(Bar.Baz)) + (Right(Foo3.Bazz): Either[Foo3, Foo3]) + .intoPartial[Either[Bar, Bar]] + .withFieldRenamed(_.matchingLeft.matching[Foo3.Bazz.type], _.matchingLeft.matching[Bar.Baz.type]) + .withFieldRenamed(_.matchingRight.matching[Foo3.Bazz.type], _.matchingRight.matching[Bar.Baz.type]) + .transform + .asOption ==> Some(Right(Bar.Baz)) + + (List(Foo3.Baz, Foo3.Bazz): List[Foo3]) + .intoPartial[List[Bar]] + .withFieldRenamed(_.everyItem.matching[Foo3.Bazz.type], _.everyItem.matching[Bar.Baz.type]) + .transform + .asOption ==> Some(List(Bar.Baz, Bar.Baz)) + + (Map(Foo3.Baz -> Foo3.Baz, Foo3.Bazz -> Foo3.Bazz): Map[Foo3, Foo3]) + .intoPartial[Map[Bar, Bar]] + .withFieldRenamed(_.everyMapKey.matching[Foo3.Bazz.type], _.everyMapKey.matching[Bar.Baz.type]) + .withFieldRenamed(_.everyMapValue.matching[Foo3.Bazz.type], _.everyMapValue.matching[Bar.Baz.type]) + .transform + .asOption ==> Some(Map(Bar.Baz -> Bar.Baz)) + } + } + group("flag .enableCustomSubtypeNameComparison") { import fixtures.renames.Subtypes.* diff --git a/chimney/src/test/scala/io/scalaland/chimney/TotalTransformerSealedHierarchySpec.scala b/chimney/src/test/scala/io/scalaland/chimney/TotalTransformerSealedHierarchySpec.scala index 8e30cca02..b6ad0a254 100644 --- a/chimney/src/test/scala/io/scalaland/chimney/TotalTransformerSealedHierarchySpec.scala +++ b/chimney/src/test/scala/io/scalaland/chimney/TotalTransformerSealedHierarchySpec.scala @@ -315,6 +315,146 @@ class TotalTransformerSealedHierarchySpec extends ChimneySpec { } } + group("setting .withFieldComputedFrom(selectorFrom)(selectorTo, mapping)") { + + test("should provide support for withSealedSubtypeHandled/withEnumCaseHandled cases but nested") { + def blackIsRed(@unused b: colors2.Black.type): colors1.Color = + colors1.Red + + (Some(colors2.Black): Option[colors2.Color]) + .into[Option[colors1.Color]] + .withFieldComputedFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsRed) + .transform ==> Some(colors1.Red) + (Some(colors2.Red): Option[colors2.Color]) + .into[Option[colors1.Color]] + .withFieldComputedFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsRed) + .transform ==> Some(colors1.Red) + (Some(colors2.Green): Option[colors2.Color]) + .into[Option[colors1.Color]] + .withFieldComputedFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsRed) + .transform ==> Some(colors1.Green) + (Some(colors2.Blue): Option[colors2.Color]) + .into[Option[colors1.Color]] + .withFieldComputedFrom(_.matchingSome.matching[colors2.Black.type])(_.matchingSome, blackIsRed) + .transform ==> Some(colors1.Blue) + + (Left(colors2.Black): Either[colors2.Color, colors2.Color]) + .into[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform ==> Left(colors1.Red) + (Left(colors2.Red): Either[colors2.Color, colors2.Color]) + .into[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform ==> Left(colors1.Red) + (Left(colors2.Green): Either[colors2.Color, colors2.Color]) + .into[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform ==> Left(colors1.Green) + (Left(colors2.Blue): Either[colors2.Color, colors2.Color]) + .into[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform ==> Left(colors1.Blue) + (Right(colors2.Black): Either[colors2.Color, colors2.Color]) + .into[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform ==> Right(colors1.Red) + (Right(colors2.Red): Either[colors2.Color, colors2.Color]) + .into[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform ==> Right(colors1.Red) + (Right(colors2.Green): Either[colors2.Color, colors2.Color]) + .into[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform ==> Right(colors1.Green) + (Right(colors2.Blue): Either[colors2.Color, colors2.Color]) + .into[Either[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.matchingLeft.matching[colors2.Black.type])(_.matchingLeft, blackIsRed) + .withFieldComputedFrom(_.matchingRight.matching[colors2.Black.type])(_.matchingRight, blackIsRed) + .transform ==> Right(colors1.Blue) + + (List(colors2.Black, colors2.Red, colors2.Green, colors2.Blue): List[colors2.Color]) + .into[List[colors1.Color]] + .withFieldComputedFrom(_.everyItem.matching[colors2.Black.type])(_.everyItem, blackIsRed) + .transform ==> List(colors1.Red, colors1.Red, colors1.Green, colors1.Blue) + + (Map( + colors2.Black -> colors2.Black, + colors2.Red -> colors2.Red, + colors2.Green -> colors2.Green, + colors2.Blue -> colors2.Blue + ): Map[ + colors2.Color, + colors2.Color + ]) + .into[Map[colors1.Color, colors1.Color]] + .withFieldComputedFrom(_.everyMapKey.matching[colors2.Black.type])(_.everyMapKey, blackIsRed) + .withFieldComputedFrom(_.everyMapValue.matching[colors2.Black.type])(_.everyMapValue, blackIsRed) + .transform ==> + Map( + colors1.Red -> colors1.Red, + colors1.Red -> colors1.Red, + colors1.Green -> colors1.Green, + colors1.Blue -> colors1.Blue + ) + + } + } + + group("settings .withFieldRenamed(selectorFrom, selectorTo)") { + + import fixtures.renames.Subtypes.* + + test("should provide support for withSealedSubtypeRenamed/withEnumCaseRenamed cases but nested") { + (Some(Foo3.Baz): Option[Foo3]) + .into[Option[Bar]] + .withFieldRenamed(_.matchingSome.matching[Foo3.Bazz.type], _.matchingSome.matching[Bar.Baz.type]) + .transform ==> Some(Bar.Baz) + (Some(Foo3.Bazz): Option[Foo3]) + .into[Option[Bar]] + .withFieldRenamed(_.matchingSome.matching[Foo3.Bazz.type], _.matchingSome.matching[Bar.Baz.type]) + .transform ==> Some(Bar.Baz) + + (Left(Foo3.Baz): Either[Foo3, Foo3]) + .into[Either[Bar, Bar]] + .withFieldRenamed(_.matchingLeft.matching[Foo3.Bazz.type], _.matchingLeft.matching[Bar.Baz.type]) + .withFieldRenamed(_.matchingRight.matching[Foo3.Bazz.type], _.matchingRight.matching[Bar.Baz.type]) + .transform ==> Left(Bar.Baz) + (Left(Foo3.Bazz): Either[Foo3, Foo3]) + .into[Either[Bar, Bar]] + .withFieldRenamed(_.matchingLeft.matching[Foo3.Bazz.type], _.matchingLeft.matching[Bar.Baz.type]) + .withFieldRenamed(_.matchingRight.matching[Foo3.Bazz.type], _.matchingRight.matching[Bar.Baz.type]) + .transform ==> Left(Bar.Baz) + (Right(Foo3.Baz): Either[Foo3, Foo3]) + .into[Either[Bar, Bar]] + .withFieldRenamed(_.matchingLeft.matching[Foo3.Bazz.type], _.matchingLeft.matching[Bar.Baz.type]) + .withFieldRenamed(_.matchingRight.matching[Foo3.Bazz.type], _.matchingRight.matching[Bar.Baz.type]) + .transform ==> Right(Bar.Baz) + (Right(Foo3.Bazz): Either[Foo3, Foo3]) + .into[Either[Bar, Bar]] + .withFieldRenamed(_.matchingLeft.matching[Foo3.Bazz.type], _.matchingLeft.matching[Bar.Baz.type]) + .withFieldRenamed(_.matchingRight.matching[Foo3.Bazz.type], _.matchingRight.matching[Bar.Baz.type]) + .transform ==> Right(Bar.Baz) + + (List(Foo3.Baz, Foo3.Bazz): List[Foo3]) + .into[List[Bar]] + .withFieldRenamed(_.everyItem.matching[Foo3.Bazz.type], _.everyItem.matching[Bar.Baz.type]) + .transform ==> List(Bar.Baz, Bar.Baz) + + (Map(Foo3.Baz -> Foo3.Baz, Foo3.Bazz -> Foo3.Bazz): Map[Foo3, Foo3]) + .into[Map[Bar, Bar]] + .withFieldRenamed(_.everyMapKey.matching[Foo3.Bazz.type], _.everyMapKey.matching[Bar.Baz.type]) + .withFieldRenamed(_.everyMapValue.matching[Foo3.Bazz.type], _.everyMapValue.matching[Bar.Baz.type]) + .transform ==> Map(Bar.Baz -> Bar.Baz) + } + } + group("flag .enableCustomSubtypeNameComparison") { import fixtures.renames.Subtypes.*