Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
9b1765f8bf |
4 changed files with 32 additions and 42 deletions
|
@ -12,20 +12,22 @@ class DynamicShouldBeProperty extends AssertionProperty with Dynamic:
|
|||
def applyDynamic(fieldName: String)(foo: Any*) = ???
|
||||
end DynamicShouldBeProperty
|
||||
|
||||
object satisfying:
|
||||
def `===`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
||||
something => ord.eq(something, toWhat)
|
||||
def `!==`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
||||
something => ord.ne(something, toWhat)
|
||||
def `<`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
||||
something => ord.lt(something, toWhat)
|
||||
def `>`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
||||
something => ord.gt(something, toWhat)
|
||||
def `<=`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
||||
something => ord.lteq(something, toWhat)
|
||||
def `>=`[T](toWhat: T)(using ord: Ordering[T]): T => Boolean =
|
||||
something => ord.gteq(something, toWhat)
|
||||
end satisfying
|
||||
case object satisfying
|
||||
|
||||
case class AssertionCandidate[T](value: T, subject: String, propertyName: String):
|
||||
private def comparison(other: T, predicate: (T, T) => Boolean, predicateOp: String): Unit =
|
||||
assert(
|
||||
predicate.apply(value, other),
|
||||
s"${subject} did not have ${propertyName} ${predicateOp} ${other}, but it was equal to ${value}"
|
||||
)
|
||||
|
||||
def `===`(other: T)(using ord: Ordering[T]): Unit = comparison(other, ord.eq(_, _), "==")
|
||||
def `!==`(other: T)(using ord: Ordering[T]): Unit = comparison(other, ord.ne(_, _), "!=")
|
||||
def `<=`(other: T)(using ord: Ordering[T]): Unit = comparison(other, ord.lteq, "<=")
|
||||
def `>=`(other: T)(using ord: Ordering[T]): Unit = comparison(other, ord.gteq, ">=")
|
||||
def `<`(other: T)(using ord: Ordering[T]): Unit = comparison(other, ord.lt, "<")
|
||||
def `>`(other: T)(using ord: Ordering[T]): Unit = comparison(other, ord.gt, ">")
|
||||
end AssertionCandidate
|
||||
|
||||
class BePropertyTypeProvider[T](val subject: T) extends Selectable:
|
||||
def selectDynamic(fieldName: String): AssertionProperty = ???
|
||||
|
@ -44,7 +46,7 @@ end BePropertyTypeProvider
|
|||
* corresponding method def foo(arg: X): AssertionProperty.
|
||||
*/
|
||||
class HavePropertyTypeProvider[T](val subject: T) extends Selectable:
|
||||
def applyDynamic(fieldName: String)(arg: Any): AssertionProperty = ???
|
||||
def applyDynamic(fieldName: String)(arg: Any): AssertionCandidate[T] = ???
|
||||
end HavePropertyTypeProvider
|
||||
|
||||
/** A trait for each type of assertion (be or have).
|
||||
|
|
|
@ -25,13 +25,6 @@ case class Box(label: String, weight: Mass, price: Money)
|
|||
val box = Box("aBox", 30.kg, 10.CHF)
|
||||
|
||||
assertions:
|
||||
// {
|
||||
// val p: BePropertyTypeProvider[Person] = new BePropertyTypeProvider[Person](person)
|
||||
// p.asInstanceOf[BePropertyTypeProvider[Person] {
|
||||
// def adult: AssertionProperty
|
||||
// }].adult
|
||||
// }
|
||||
|
||||
/* be.property assertions */
|
||||
// assert(person.adult, ...)
|
||||
person should be.adult
|
||||
|
@ -40,6 +33,14 @@ case class Box(label: String, weight: Mass, price: Money)
|
|||
// assert(List(1,2,3).nonEmpty)
|
||||
List(1, 2, 3) should be.nonEmpty
|
||||
|
||||
List(1) should have head satisfying === 1
|
||||
box should have weight satisfying === 3.kg
|
||||
|
||||
|
||||
List() should have size satisfying >= 0
|
||||
List(3) should have size satisfying !== 0
|
||||
List(50, 2, 3) should have head satisfying < 100
|
||||
box should have.weight satisfying >= 10.kg
|
||||
person should have age satisfying >= 10
|
||||
|
||||
// New syntax for `be` with type provider
|
||||
|
|
|
@ -66,7 +66,6 @@ object ShouldBeTypeProvider:
|
|||
val p = BePropertyTypeProvider[T]($subject)
|
||||
p.asInstanceOf[tpe]
|
||||
}
|
||||
println(res.show)
|
||||
res
|
||||
|
||||
end ShouldBeTypeProvider
|
||||
|
|
|
@ -29,26 +29,14 @@ object ShouldHaveTypeProvider:
|
|||
// Getting it as is returns an applied type with useless bounds (Nothing to Any), and the returned TypeRepr,
|
||||
// if re-applied to some `I` input type and `O` output type would be incompatible with `TypeRepr.of[I => O]` for
|
||||
// some reason
|
||||
val function1TypeConstructor = AppliedType.unapply(TypeRepr.of[? => ?].asInstanceOf[AppliedType])._1
|
||||
val acTypeCtor = AppliedType.unapply(TypeRepr.of[AssertionCandidate[Unit]].asInstanceOf[AppliedType])._1
|
||||
val assertionCandidateType = AppliedType(acTypeCtor, List(fieldTypeRepr))
|
||||
|
||||
val appliedType = AppliedType(function1TypeConstructor, List(fieldTypeRepr, TypeRepr.of[Boolean]))
|
||||
|
||||
// Generates the "type" of the method to be generated for the refinement.
|
||||
// The first parameter is the list of arguments, the second is a function returning
|
||||
// the type of arguments, and the third one is a function returning the return type
|
||||
// of the method.
|
||||
// In this case: arg is the name of the parameter;
|
||||
// _ => List(fieldTypeRepr) returns a list with the type of arg;
|
||||
// _ => TypeRepr.of[AssertionProperty] returns the (reflection) type of the method.
|
||||
val methodType = MethodType(List("arg"))(
|
||||
_ => List(appliedType),
|
||||
_ => TypeRepr.of[AssertionProperty]
|
||||
).widen
|
||||
// returns the refinement of currentTypeRepr -
|
||||
// symbol.name is the name of the method,
|
||||
// methodType is its type.
|
||||
val refinement = Refinement(currentTypeRepr, symbol.name, methodType)
|
||||
refinement
|
||||
val methodType = MethodType(List("satisfying"))(
|
||||
_ => List(TypeRepr.of[satisfying.type]),
|
||||
_ => assertionCandidateType
|
||||
)
|
||||
Refinement(currentTypeRepr, symbol.name, methodType)
|
||||
|
||||
/** Refines a type according to a list of fields or methods of arity 0.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue