ex2 works
This commit is contained in:
parent
dda2d1b61f
commit
fa3972ec1b
3 changed files with 26 additions and 12 deletions
|
@ -8,6 +8,25 @@ import scala.language.postfixOps
|
||||||
*/
|
*/
|
||||||
object GenerativeFluentAssertionsDSL:
|
object GenerativeFluentAssertionsDSL:
|
||||||
|
|
||||||
|
extension [T](inline property: SatisfyingNotEquals[T])
|
||||||
|
inline def `!==`(inline obj: T)(using inline ord: Ordering[T]): AssertionProperty =
|
||||||
|
${ notEqualsImpl('property, 'obj, 'ord) }
|
||||||
|
|
||||||
|
private def notEqualsImpl[T: Type](property: Expr[SatisfyingNotEquals[T]], obj: Expr[T], ord: Expr[Ordering[T]])(
|
||||||
|
using Quotes
|
||||||
|
): Expr[AssertionProperty] = {
|
||||||
|
import quotes.reflect.*
|
||||||
|
|
||||||
|
property match
|
||||||
|
case '{ (${ typeProvider }: HavePropertyTypeProvider[subjectType])
|
||||||
|
.applyDynamic($propertyNameExpr: String)(satisfying)
|
||||||
|
.$asInstanceOf$[SatisfyingNotEquals[T]] } => '{
|
||||||
|
$typeProvider
|
||||||
|
.applyDynamic($propertyNameExpr)(satisfying.notEquals[T]($obj, $ord))
|
||||||
|
.$asInstanceOf$[AssertionProperty]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Entrypoint. This macro method takes an expression composed of
|
/** Entrypoint. This macro method takes an expression composed of
|
||||||
* AssertionProperty expressions and rewrites them into actual assertions.
|
* AssertionProperty expressions and rewrites them into actual assertions.
|
||||||
*/
|
*/
|
||||||
|
@ -70,18 +89,12 @@ object GenerativeFluentAssertionsDSL:
|
||||||
// the should have assertion. Again, the applyDynamic is explicit.
|
// the should have assertion. Again, the applyDynamic is explicit.
|
||||||
// The quoted pattern also extracts: the type of the assertion subject,
|
// The quoted pattern also extracts: the type of the assertion subject,
|
||||||
// and the type of the property (actually... not exactly that. Why?)
|
// and the type of the property (actually... not exactly that. Why?)
|
||||||
case '{
|
|
||||||
(${ typeProvider }: HavePropertyTypeProvider[subjectType])
|
|
||||||
.applyDynamic($propertyNameExpr: String)(satisfying)
|
|
||||||
.$asInstanceOf$[SatisfyingNotEquals[fieldType]]
|
|
||||||
.`!==`($property)
|
|
||||||
} =>
|
|
||||||
'{}
|
|
||||||
case '{
|
case '{
|
||||||
(${ typeProvider }: HavePropertyTypeProvider[subjectType])
|
(${ typeProvider }: HavePropertyTypeProvider[subjectType])
|
||||||
.applyDynamic($propertyNameExpr: String)($valueExpr: valueType => Boolean)
|
.applyDynamic($propertyNameExpr: String)($valueExpr: valueType => Boolean)
|
||||||
.$asInstanceOf$[AssertionProperty]
|
.$asInstanceOf$[AssertionProperty]
|
||||||
} =>
|
} =>
|
||||||
|
println(assertionExpr.show)
|
||||||
val subjectExpr = '{ $typeProvider.subject }
|
val subjectExpr = '{ $typeProvider.subject }
|
||||||
generateShouldHaveAssertion[subjectType, valueType](
|
generateShouldHaveAssertion[subjectType, valueType](
|
||||||
subjectExpr,
|
subjectExpr,
|
||||||
|
|
|
@ -17,12 +17,13 @@ end DynamicShouldBeProperty
|
||||||
* and thus has lower precedence than alphanumeric operators. Therefore, we must handle "!==" as the final link of
|
* and thus has lower precedence than alphanumeric operators. Therefore, we must handle "!==" as the final link of
|
||||||
* a method chain instead of a predicate builder on `satisfying`, like the other operators.
|
* a method chain instead of a predicate builder on `satisfying`, like the other operators.
|
||||||
*/
|
*/
|
||||||
sealed trait SatisfyingNotEquals[T]:
|
sealed trait SatisfyingNotEquals[T]
|
||||||
def `!==`(toWhat: T): AssertionProperty = ???
|
|
||||||
|
|
||||||
case object satisfying:
|
case object satisfying:
|
||||||
def `===`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
def `===`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
||||||
something => ord.eq(something, toWhat)
|
something => ord.equiv(something, toWhat)
|
||||||
|
def notEquals[T](toWhat: T, ord: Ordering[T]): T => Boolean =
|
||||||
|
something => !ord.equiv(something, toWhat)
|
||||||
def `<`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
def `<`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
||||||
something => ord.lt(something, toWhat)
|
something => ord.lt(something, toWhat)
|
||||||
def `>`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
def `>`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
||||||
|
|
|
@ -41,11 +41,11 @@ case class Box(label: String, weight: Mass, price: Money)
|
||||||
(person should be_).adult
|
(person should be_).adult
|
||||||
|
|
||||||
List(1) should have head satisfying === 1
|
List(1) should have head satisfying === 1
|
||||||
box should have weight satisfying === 3.kg
|
box should have weight satisfying === 30.kg
|
||||||
List() should have size satisfying >= 0
|
List() should have size satisfying >= 0
|
||||||
List(3) should have size satisfying !== 0
|
List(3) should have size satisfying !== 0
|
||||||
List(50, 2, 3) should have head satisfying < 100
|
List(50, 2, 3) should have head satisfying < 100
|
||||||
box should have weight satisfying <= 3.0.kg
|
box should have weight satisfying >= 3.0.kg
|
||||||
|
|
||||||
/* should have assertions */
|
/* should have assertions */
|
||||||
// // assert(List(1).head == 1, ...)
|
// // assert(List(1).head == 1, ...)
|
||||||
|
|
Loading…
Reference in a new issue