ready for submission

This commit is contained in:
Claudio Maggioni 2024-12-22 22:35:13 +01:00
parent f73a8601c3
commit 0b9bff5ba8
5 changed files with 46 additions and 42 deletions

View file

@ -1,3 +1,23 @@
## Lecture 12
# Assignment 03
Code for Lecture 12.
Student: Claudio Maggioni
## Use of AI assistants / LLMs
I declare that I used the following AI assistants / LLMs (put an X where needed):
- [X] ChatGPT (GPT-4o mini)
Briefly, how helpful was the AI assistant for this assignment?
- assistance on how to pattern match complex quoted expressions for 'should have' and 'should contain' assertions
- assistance on how to build an AST for a lambda expression
## Exercises Completed
Please Mark the exercises that you chose/completed:
- [X] Exercise 1
- [X] Exercise 2
- [X] Exercise 3
- [X] Exercise 4 (with bonus)

View file

@ -154,16 +154,10 @@ object GenerativeFluentAssertionsDSL:
)
case '{
(${ typeProvider }: BePropertyTypeProvider[subjectType])
.applyDynamic($propertyNameExpr)($unit)
.applyDynamic($propertyNameExpr)($end)
.$asInstanceOf$[AssertionProperty]
} =>
'{} // placeholder
case '{
(${ typeProvider }: BePropertyTypeProvider[subjectType])
.selectDynamic($propertyNameExpr)
.$asInstanceOf$[AssertionProperty]
} =>
'{} // placeholder
case a =>
report.errorAndAbort(
"Invalid expression, must be a 'should be' or 'should have' assertion. ",

View file

@ -14,11 +14,6 @@ class DynamicShouldBeProperty extends AssertionProperty with Dynamic:
def applyDynamic(fieldName: String)(foo: Any*) = ???
end DynamicShouldBeProperty
/**
* Due to operator precedence, '!==' is the only comparison operator that is considered an "assignment operation"
* 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.
*/
sealed trait SatisfyingNotEquals[T]
case class Condition[-T](predicate: T => Boolean, op: String, expected: Any):
@ -89,6 +84,7 @@ case object have extends AssertionDSLVerb:
case object contain extends AssertionDSLVerb
case object `with` extends AssertionDSLVerb
case object `!!` extends AssertionDSLVerb
case class ContainsVerb[T](subject: Iterable[T])

View file

@ -17,6 +17,7 @@ case class Complex(re: Double, im: Double):
case class Person(firstName: String, lastName: String, age: Int):
def adult: Boolean = age >= 18
def minor: Boolean = !adult
case class Box(label: String, weight: Mass, price: Money)
@ -25,28 +26,30 @@ case class Box(label: String, weight: Mass, price: Money)
val box = Box("aBox", 30.kg, 10.CHF)
assertions:
/* be.property assertions */
// assert(person.adult, ...)
person should !(!be.adult)
// assert(List().isEmpty, ...)
List() should be.empty
// assert(List(1,2,3).nonEmpty)
List(1, 2, 3) should be.nonEmpty
person should have age satisfying >= 10
// New syntax for `be` with type provider
// either adult is a method with a dummy Unit parameter
person should be_ adult()
// or adult is a property but braces are needed to resolve the type provider
(person should be_).adult
// Exercise 1 solution:
// It is possible to implement a DSL for 'should be' assertions that uses a type provider like the 'should have'
// assertion. However, a slight change to the syntax is needed in order to maintain the 'subject [method value]+'
// pattern that DSL statements should maintain in order to be parsed correctly by the Scala parser. To do this,
// we define an extra token named '!!' as a case object that should be appended at the end of the assertion. This
// object will serve as a dummy parameter to the method called on the type provider to allow the assertion
// statement to be parsed correctly.
// (note that the verb is 'be_' instead of 'be' to avoid a clash with the original implementation)
person should be_ adult !!
// Exercise 2
List(1) should have head satisfying === 1
box should have weight satisfying === 30.kg
List() should have size satisfying >= 0
List(3) should have size satisfying !== 0
List(50, 2, 3) should have head satisfying < 100
person should have age satisfying >= 10
// Exercise 3
box should !(!have) weight satisfying <= 300.0.kg
person should !(!be.adult)
person should !be.minor
// Exercise 4
// we wrap the strings in StringOps instances in order to resolve the scala method "size". This would otherwise
// not happen automatically as the string types would resolve to "java.lang.String" thus not allowing the type
@ -58,17 +61,8 @@ case class Box(label: String, weight: Mass, price: Money)
new StringOps(""),
new StringOps("alice")
) should contain someElements `with` size satisfying === 0
// List(Seq(), Seq(), Seq()) should contain allElements `with` size satisfying >= 0
// List(List(1,2), List(20,1), List(3,4)) should contain noElements `with` head satisfying === 3
/* should have assertions */
// // assert(List(1).head == 1, ...)
// List(1) should have head 1
// // assert(box.weight == 30.kg, ...)
// box should have weight 30.kg
// // assert(person.age == 0x29, ...)
// person should have age 0x29
// List(2, 3) should have tail List(3)
// 3.i + 1 should have re 1.0
List(Seq(), Seq(), Seq()) should contain allElements `with` size satisfying >= 0
List(List(1,2), List(20,1), List(3,4)) should contain noElements `with` head satisfying === 3 // this assertion fails
end assertionsExample

View file

@ -16,8 +16,8 @@ object ShouldBeTypeProvider:
): TypeRepr =
// refine both as unary method with unit parameter and as property
// and let client code choose
val methodType = MethodType(List("unit"))(
_ => List(TypeRepr.of[Unit]),
val methodType = MethodType(List("end"))(
_ => List(TypeRepr.of[`!!`.type]),
_ => TypeRepr.of[AssertionProperty]
)
Refinement(