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 '{
|
case '{
|
||||||
(${ typeProvider }: BePropertyTypeProvider[subjectType])
|
(${ typeProvider }: BePropertyTypeProvider[subjectType])
|
||||||
.applyDynamic($propertyNameExpr)($unit)
|
.applyDynamic($propertyNameExpr)($end)
|
||||||
.$asInstanceOf$[AssertionProperty]
|
.$asInstanceOf$[AssertionProperty]
|
||||||
} =>
|
} =>
|
||||||
'{} // placeholder
|
'{} // placeholder
|
||||||
case '{
|
|
||||||
(${ typeProvider }: BePropertyTypeProvider[subjectType])
|
|
||||||
.selectDynamic($propertyNameExpr)
|
|
||||||
.$asInstanceOf$[AssertionProperty]
|
|
||||||
} =>
|
|
||||||
'{} // placeholder
|
|
||||||
case a =>
|
case a =>
|
||||||
report.errorAndAbort(
|
report.errorAndAbort(
|
||||||
"Invalid expression, must be a 'should be' or 'should have' assertion. ",
|
"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*) = ???
|
def applyDynamic(fieldName: String)(foo: Any*) = ???
|
||||||
end DynamicShouldBeProperty
|
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]
|
sealed trait SatisfyingNotEquals[T]
|
||||||
|
|
||||||
case class Condition[-T](predicate: T => Boolean, op: String, expected: Any):
|
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 contain extends AssertionDSLVerb
|
||||||
case object `with` extends AssertionDSLVerb
|
case object `with` extends AssertionDSLVerb
|
||||||
|
case object `!!` extends AssertionDSLVerb
|
||||||
|
|
||||||
case class ContainsVerb[T](subject: Iterable[T])
|
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):
|
case class Person(firstName: String, lastName: String, age: Int):
|
||||||
def adult: Boolean = age >= 18
|
def adult: Boolean = age >= 18
|
||||||
|
def minor: Boolean = !adult
|
||||||
|
|
||||||
case class Box(label: String, weight: Mass, price: Money)
|
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)
|
val box = Box("aBox", 30.kg, 10.CHF)
|
||||||
|
|
||||||
assertions:
|
assertions:
|
||||||
/* be.property assertions */
|
// Exercise 1 solution:
|
||||||
// assert(person.adult, ...)
|
// It is possible to implement a DSL for 'should be' assertions that uses a type provider like the 'should have'
|
||||||
person should !(!be.adult)
|
// assertion. However, a slight change to the syntax is needed in order to maintain the 'subject [method value]+'
|
||||||
// assert(List().isEmpty, ...)
|
// pattern that DSL statements should maintain in order to be parsed correctly by the Scala parser. To do this,
|
||||||
List() should be.empty
|
// we define an extra token named '!!' as a case object that should be appended at the end of the assertion. This
|
||||||
// assert(List(1,2,3).nonEmpty)
|
// object will serve as a dummy parameter to the method called on the type provider to allow the assertion
|
||||||
List(1, 2, 3) should be.nonEmpty
|
// statement to be parsed correctly.
|
||||||
|
// (note that the verb is 'be_' instead of 'be' to avoid a clash with the original implementation)
|
||||||
person should have age satisfying >= 10
|
person should be_ adult !!
|
||||||
|
|
||||||
// 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 2
|
||||||
List(1) should have head satisfying === 1
|
List(1) should have head satisfying === 1
|
||||||
box should have weight satisfying === 30.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
|
||||||
|
person should have age satisfying >= 10
|
||||||
|
|
||||||
|
// Exercise 3
|
||||||
box should !(!have) weight satisfying <= 300.0.kg
|
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
|
// 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
|
// 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(""),
|
||||||
new StringOps("alice")
|
new StringOps("alice")
|
||||||
) should contain someElements `with` size satisfying === 0
|
) 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 */
|
List(Seq(), Seq(), Seq()) should contain allElements `with` size satisfying >= 0
|
||||||
// // assert(List(1).head == 1, ...)
|
List(List(1,2), List(20,1), List(3,4)) should contain noElements `with` head satisfying === 3 // this assertion fails
|
||||||
// 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
|
|
||||||
|
|
||||||
end assertionsExample
|
end assertionsExample
|
||||||
|
|
|
@ -16,8 +16,8 @@ object ShouldBeTypeProvider:
|
||||||
): TypeRepr =
|
): TypeRepr =
|
||||||
// refine both as unary method with unit parameter and as property
|
// refine both as unary method with unit parameter and as property
|
||||||
// and let client code choose
|
// and let client code choose
|
||||||
val methodType = MethodType(List("unit"))(
|
val methodType = MethodType(List("end"))(
|
||||||
_ => List(TypeRepr.of[Unit]),
|
_ => List(TypeRepr.of[`!!`.type]),
|
||||||
_ => TypeRepr.of[AssertionProperty]
|
_ => TypeRepr.of[AssertionProperty]
|
||||||
)
|
)
|
||||||
Refinement(
|
Refinement(
|
||||||
|
|
Loading…
Reference in a new issue