Compare commits

...

1 commit
main ... ex2

Author SHA1 Message Date
9b1765f8bf attempt 2024-12-17 15:03:35 +01:00
4 changed files with 32 additions and 42 deletions

View file

@ -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).

View file

@ -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

View file

@ -66,7 +66,6 @@ object ShouldBeTypeProvider:
val p = BePropertyTypeProvider[T]($subject)
p.asInstanceOf[tpe]
}
println(res.show)
res
end ShouldBeTypeProvider

View file

@ -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.
*/