Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Close #63 - [refined4s-cats] Add CatsEq, CatsShow and CatsEqShow to derive Eq and Show from the actual type's Eq and Show #64

Merged
merged 1 commit into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package refined4s.cats.derivation

import cats.Eq
import refined4s.*

/** @author Kevin Lee
* @since 2023-12-07
*/
trait CatsEq[A: Eq] {
self: NewtypeBase[A] =>

inline given derivedEq: Eq[Type] = deriving[Eq]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package refined4s.cats.derivation

import refined4s.NewtypeBase

/** @author Kevin Lee
* @since 2023-12-07
*/
trait CatsEqShow[A] extends CatsEq[A] with CatsShow[A] {
self: NewtypeBase[A] =>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package refined4s.cats.derivation

import cats.Show
import refined4s.*

/** @author Kevin Lee
* @since 2023-12-07
*/
trait CatsShow[A: Show] {
self: NewtypeBase[A] =>

given derivedShow: Show[Type] = deriving[Show]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package refined4s.cats.derivation

import cats.*
import cats.syntax.all.*
import hedgehog.*
import hedgehog.runner.*
import refined4s.*
import refined4s.cats.derivation.CatsShowSpec.{MyRefinedNewtype, MyRefinedType}

/** @author Kevin Lee
* @since 2023-12-07
*/
object CatsEqShowSpec extends Properties {
override def tests: List[Test] = List(
property("Given Newtype with CatsEq. Newtype[A](a) === Newtype[A](a) should return true", testEqNewtypeSame),
property(
"Given Newtype with CatsEq. Newtype[A](a) =!= Newtype[A](not a) should return true",
testEqNewtypeDifferent,
),
property(
"Given Refined with CatsEq. Refined[A](a) === Refined[A](a) should return true",
testEqRefinedSame,
),
property(
"Given Refined with CatsEq. Refined[A](a) =!= Refined[A](not a) should return true",
testEqRefinedDifferent,
),
property(
"Given Newtype[Refined] with CatsEq. Newtype[Refined[A]](a) === Newtype[Refined[A]](a) should return true",
testEqNewtypeRefinedSame,
),
property(
"Given Newtype[Refined] with CatsEq. Newtype[Refined[A]](a) =!= Newtype[Refined[A]](not a) should return true",
testEqNewtypeRefinedDifferent,
),
property(
"Given Newtype with CatsShow. Newtype[A].show(a) should return the same String as Show[A].show(a)",
testShowNewtype,
),
property(
"Given Refined with CatsShow. Refined[A].show(a) should return the same String as Show[A].show(a)",
testShowRefined,
),
property(
"Given Newtype[Refined] with CatsShow. Newtype[Refined[A]].show(a) should return the same String as Show[A].show(a)",
testShowNewtypeRefined,
),
)

def testEqNewtypeSame: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(0, 10)).log("s")
} yield {
val a = MyNewtype(s)
val b = a
Result.diffNamed("MyNewtype(value) === MyNewtype(value)", a, b)(_ === _)
}

def testEqNewtypeDifferent: Property =
for {
s1 <- Gen.string(Gen.unicode, Range.linear(0, 10)).log("s1")
s2 <- Gen.string(Gen.unicode, Range.linear(0, 10)).map(s1 + "-" + _).log("s2")
} yield {
val a = MyNewtype(s1)
val b = MyNewtype(s2)
Result.diffNamed("MyNewtype(value) =!= MyNewtype(value)", a, b)(_ =!= _)
}

def testEqRefinedSame: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s")
} yield {
val a = MyRefinedType.unsafeFrom(s)
val b = a
Result.diffNamed(s"MyRefinedType(${a.value}) === MyRefinedType(${b.value})", a, b)(_ === _)
}

def testEqRefinedDifferent: Property =
for {
s1 <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s1")
s2 <- Gen.string(Gen.unicode, Range.linear(1, 10)).map(s1 + "-" + _).log("s2")
} yield {
val a = MyRefinedType.unsafeFrom(s1)
val b = MyRefinedType.unsafeFrom(s2)
Result.diffNamed(s"MyRefinedType(${a.value}) =!= MyRefinedType(${b.value})", a, b)(_ =!= _)
}

def testEqNewtypeRefinedSame: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s")
} yield {
val a = MyRefinedNewtype(MyRefinedType.unsafeFrom(s))
val b = a
Result.diffNamed(
s"MyRefinedNewtype(MyRefinedType(${a.value})) === MyRefinedNewtype(MyRefinedType(${b.value}))",
a,
b,
)(_ === _)
}

def testEqNewtypeRefinedDifferent: Property =
for {
s1 <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s1")
s2 <- Gen.string(Gen.unicode, Range.linear(1, 10)).map(s1 + "-" + _).log("s2")
} yield {
val a = MyRefinedNewtype(MyRefinedType.unsafeFrom(s1))
val b = MyRefinedNewtype(MyRefinedType.unsafeFrom(s2))
Result.diffNamed(
s"MyRefinedNewtype(MyRefinedType(${a.value})) =!= MyRefinedNewtype(MyRefinedType(${b.value}))",
a,
b,
)(_ =!= _)
}

def testShowNewtype: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(0, 10)).log("s")
} yield {
val a = MyNewtype(s)
a.show ==== Show[String].show(s)
}

def testShowRefined: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s")
} yield {
val a = MyRefinedType.unsafeFrom(s)
a.show ==== Show[String].show(s)
}

def testShowNewtypeRefined: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s")
} yield {
val a = MyRefinedNewtype(MyRefinedType.unsafeFrom(s))
a.show ==== Show[String].show(s)
}

type MyNewtype = MyNewtype.Type
object MyNewtype extends Newtype[String] with CatsEqShow[String]

type MyRefinedType = MyRefinedType.Type
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
object MyRefinedType extends Refined[String] with CatsEqShow[String] {
override inline def invalidReason(a: String): String =
"It has to be a non-empty String but got \"" + a + "\""

override inline def predicate(a: String): Boolean = a != ""
}

type MyRefinedNewtype = MyRefinedNewtype.Type
object MyRefinedNewtype extends Newtype[MyRefinedType] with CatsEqShow[MyRefinedType]

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package refined4s.cats.derivation

import cats.*
import cats.syntax.all.*
import hedgehog.*
import hedgehog.runner.*
import refined4s.*

/** @author Kevin Lee
* @since 2023-12-07
*/
object CatsEqSpec extends Properties {
override def tests: List[Test] = List(
property(
"Given Newtype with CatsEq. Newtype[A](a) === Newtype[A](a) should return true",
testEqNewtypeSame,
),
property(
"Given Newtype with CatsEq. Newtype[A](a) =!= Newtype[A](not a) should return true",
testEqNewtypeDifferent,
),
property(
"Given Refined with CatsEq. Refined[A](a) === Refined[A](a) should return true",
testEqRefinedSame,
),
property(
"Given Refined with CatsEq. Refined[A](a) =!= Refined[A](not a) should return true",
testEqRefinedDifferent,
),
property(
"Given Newtype[Refined] with CatsEq. Newtype[Refined[A]](a) === Newtype[Refined[A]](a) should return true",
testEqNewtypeRefinedSame,
),
property(
"Given Newtype[Refined] with CatsEq. Newtype[Refined[A]](a) =!= Newtype[Refined[A]](not a) should return true",
testEqNewtypeRefinedDifferent,
),
)

def testEqNewtypeSame: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(0, 10)).log("s")
} yield {
val a = MyNewtype(s)
val b = a
Result.diffNamed("MyNewtype(value) === MyNewtype(value)", a, b)(_ === _)
}

def testEqNewtypeDifferent: Property =
for {
s1 <- Gen.string(Gen.unicode, Range.linear(0, 10)).log("s1")
s2 <- Gen.string(Gen.unicode, Range.linear(0, 10)).map(s1 + "-" + _).log("s2")
} yield {
val a = MyNewtype(s1)
val b = MyNewtype(s2)
Result.diffNamed("MyNewtype(value) =!= MyNewtype(value)", a, b)(_ =!= _)
}

def testEqRefinedSame: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s")
} yield {
val a = MyRefinedType.unsafeFrom(s)
val b = a
Result.diffNamed(s"MyRefinedType(${a.value}) === MyRefinedType(${b.value})", a, b)(_ === _)
}

def testEqRefinedDifferent: Property =
for {
s1 <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s1")
s2 <- Gen.string(Gen.unicode, Range.linear(1, 10)).map(s1 + "-" + _).log("s2")
} yield {
val a = MyRefinedType.unsafeFrom(s1)
val b = MyRefinedType.unsafeFrom(s2)
Result.diffNamed(s"MyRefinedType(${a.value}) =!= MyRefinedType(${b.value})", a, b)(_ =!= _)
}

def testEqNewtypeRefinedSame: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s")
} yield {
val a = MyRefinedNewtype(MyRefinedType.unsafeFrom(s))
val b = a
Result.diffNamed(
s"MyRefinedNewtype(MyRefinedType(${a.value})) === MyRefinedNewtype(MyRefinedType(${b.value}))",
a,
b,
)(_ === _)
}

def testEqNewtypeRefinedDifferent: Property =
for {
s1 <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s1")
s2 <- Gen.string(Gen.unicode, Range.linear(1, 10)).map(s1 + "-" + _).log("s2")
} yield {
val a = MyRefinedNewtype(MyRefinedType.unsafeFrom(s1))
val b = MyRefinedNewtype(MyRefinedType.unsafeFrom(s2))
Result.diffNamed(
s"MyRefinedNewtype(MyRefinedType(${a.value})) =!= MyRefinedNewtype(MyRefinedType(${b.value}))",
a,
b,
)(_ =!= _)
}

type MyNewtype = MyNewtype.Type
object MyNewtype extends Newtype[String] with CatsEq[String]

type MyRefinedType = MyRefinedType.Type
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
object MyRefinedType extends Refined[String] with CatsEq[String] {
override inline def invalidReason(a: String): String =
"It has to be a non-empty String but got \"" + a + "\""

override inline def predicate(a: String): Boolean = a != ""
}

type MyRefinedNewtype = MyRefinedNewtype.Type
object MyRefinedNewtype extends Newtype[MyRefinedType] with CatsEq[MyRefinedType]

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package refined4s.cats.derivation

import cats.*
import cats.syntax.all.*
import hedgehog.*
import hedgehog.runner.*
import refined4s.*

/** @author Kevin Lee
* @since 2023-12-07
*/
object CatsShowSpec extends Properties {
override def tests: List[Test] = List(
property(
"Given Newtype with CatsShow. Newtype[A].show(a) should return the same String as Show[A].show(a)",
testShowNewtype,
),
property(
"Given Refined with CatsShow. Refined[A].show(a) should return the same String as Show[A].show(a)",
testShowRefined,
),
property(
"Given Newtype[Refined] with CatsShow. Newtype[Refined[A]].show(a) should return the same String as Show[A].show(a)",
testShowNewtypeRefined,
),
)

def testShowNewtype: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(0, 10)).log("s")
} yield {
val a = MyNewtype(s)
a.show ==== Show[String].show(s)
}

def testShowRefined: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s")
} yield {
val a = MyRefinedType.unsafeFrom(s)
a.show ==== Show[String].show(s)
}

def testShowNewtypeRefined: Property =
for {
s <- Gen.string(Gen.unicode, Range.linear(1, 10)).log("s")
} yield {
val a = MyRefinedNewtype(MyRefinedType.unsafeFrom(s))
a.show ==== Show[String].show(s)
}

type MyNewtype = MyNewtype.Type
object MyNewtype extends Newtype[String] with CatsShow[String]

type MyRefinedType = MyRefinedType.Type
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
object MyRefinedType extends Refined[String] with CatsShow[String] {
override inline def invalidReason(a: String): String =
"It has to be a non-empty String but got \"" + a + "\""

override inline def predicate(a: String): Boolean = a != ""
}

type MyRefinedNewtype = MyRefinedNewtype.Type
object MyRefinedNewtype extends Newtype[MyRefinedType] with CatsShow[MyRefinedType]

}