ready for submission
This commit is contained in:
parent
f73a8601c3
commit
0b9bff5ba8
5 changed files with 46 additions and 42 deletions
24
README.md
24
README.md
|
@ -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)
|
|
@ -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. ",
|
||||
|
|
|
@ -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])
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue