From d1772865f1532b8609194f8ced866c1dfca49350 Mon Sep 17 00:00:00 2001 From: Alexander Myltsev Date: Wed, 11 Dec 2013 03:55:56 +0400 Subject: [PATCH] Implement 2nd assignment --- .../src/main/scala/funsets/FunSets.scala | 22 ++-- .../src/test/scala/funsets/FractionSpec.scala | 56 ++++++++++ .../src/test/scala/funsets/FunSetSuite.scala | 99 +++++++++-------- .../src/test/scala/funsets/SetExtension.scala | 9 ++ .../src/test/scala/funsets/SetSpecs.scala | 102 ++++++++++++++++++ a2-funsets/src/test/scala/funsets/Sets.sc | 23 ++++ 6 files changed, 253 insertions(+), 58 deletions(-) create mode 100644 a2-funsets/src/test/scala/funsets/FractionSpec.scala create mode 100644 a2-funsets/src/test/scala/funsets/SetExtension.scala create mode 100644 a2-funsets/src/test/scala/funsets/SetSpecs.scala create mode 100644 a2-funsets/src/test/scala/funsets/Sets.sc diff --git a/a2-funsets/src/main/scala/funsets/FunSets.scala b/a2-funsets/src/main/scala/funsets/FunSets.scala index 594a49d..724608e 100644 --- a/a2-funsets/src/main/scala/funsets/FunSets.scala +++ b/a2-funsets/src/main/scala/funsets/FunSets.scala @@ -20,30 +20,30 @@ object FunSets { /** * Returns the set of the one given element. */ - def singletonSet(elem: Int): Set = ??? + def singletonSet(elem: Int): Set = x => x == elem /** * Returns the union of the two given sets, * the sets of all elements that are in either `s` or `t`. */ - def union(s: Set, t: Set): Set = ??? + def union(s: Set, t: Set): Set = x => s(x) || t(x) /** * Returns the intersection of the two given sets, * the set of all elements that are both in `s` and `t`. */ - def intersect(s: Set, t: Set): Set = ??? + def intersect(s: Set, t: Set): Set = x => s(x) && t(x) /** * Returns the difference of the two given sets, * the set of all elements of `s` that are not in `t`. */ - def diff(s: Set, t: Set): Set = ??? + def diff(s: Set, t: Set): Set = x => s(x) && !t(x) /** * Returns the subset of `s` for which `p` holds. */ - def filter(s: Set, p: Int => Boolean): Set = ??? + def filter(s: Set, p: Int => Boolean): Set = x => s(x) && p(x) /** * The bounds for `forall` and `exists` are +/- 1000. @@ -55,23 +55,23 @@ object FunSets { */ def forall(s: Set, p: Int => Boolean): Boolean = { def iter(a: Int): Boolean = { - if (???) ??? - else if (???) ??? - else iter(???) + if (a > bound) true + else if (contains(s, a)) p(a) && iter(a + 1) + else iter(a + 1) } - iter(???) + iter(-bound) } /** * Returns whether there exists a bounded integer within `s` * that satisfies `p`. */ - def exists(s: Set, p: Int => Boolean): Boolean = ??? + def exists(s: Set, p: Int => Boolean): Boolean = !forall(s, x => !p(x)) /** * Returns a set transformed by applying `f` to each element of `s`. */ - def map(s: Set, f: Int => Int): Set = ??? + def map(s: Set, f: Int => Int): Set = { case x => exists(s, (si => f(si) == x)) } /** * Displays the contents of a set diff --git a/a2-funsets/src/test/scala/funsets/FractionSpec.scala b/a2-funsets/src/test/scala/funsets/FractionSpec.scala new file mode 100644 index 0000000..87fb31a --- /dev/null +++ b/a2-funsets/src/test/scala/funsets/FractionSpec.scala @@ -0,0 +1,56 @@ +package funsets + +/* +import org.scalatest.PropSpec +import org.scalatest.prop.PropertyChecks +import org.scalatest.matchers.ShouldMatchers + +class Fraction(n: Int, d: Int) { + require(d != 0) + require(d != Integer.MIN_VALUE) + require(n != Integer.MIN_VALUE) + + val numer = if (d < 0) -1 * n else n + val denom = d.abs + + override def toString = numer + " / " + denom +} + + +class FractionSpec extends PropSpec with PropertyChecks with ShouldMatchers { + + property("Fraction constructor normalizes numerator and denominator") { + forAll { (n: Int, d: Int) => + whenever(d != 0 && d != Integer.MIN_VALUE && n != Integer.MIN_VALUE) { + val f = new Fraction(n, d) + + if (n < 0 && d < 0 || n > 0 && d > 0) + f.numer should be > 0 + else if (n != 0) + f.numer should be < 0 + else + f.numer should be === 0 + + f.denom should be > 0 + } + } + } + + property("Fraction constructor throws IAE on bad data.") { + val invalidCombos = + Table( + ("n", "d"), + (Integer.MIN_VALUE, Integer.MIN_VALUE), + (1, Integer.MIN_VALUE), + (Integer.MIN_VALUE, 1), + (Integer.MIN_VALUE, 0), + (1, 0)) + + forAll(invalidCombos) { (n: Int, d: Int) => + evaluating { + new Fraction(n, d) + } should produce[IllegalArgumentException] + } + } +} +*/ \ No newline at end of file diff --git a/a2-funsets/src/test/scala/funsets/FunSetSuite.scala b/a2-funsets/src/test/scala/funsets/FunSetSuite.scala index e75ba8c..62291a9 100644 --- a/a2-funsets/src/test/scala/funsets/FunSetSuite.scala +++ b/a2-funsets/src/test/scala/funsets/FunSetSuite.scala @@ -13,64 +13,30 @@ import org.scalatest.junit.JUnitRunner */ @RunWith(classOf[JUnitRunner]) class FunSetSuite extends FunSuite { - - - /** - * Link to the scaladoc - very clear and detailed tutorial of FunSuite - * - * http://doc.scalatest.org/1.9.1/index.html#org.scalatest.FunSuite - * - * Operators - * - test - * - ignore - * - pending - */ - - /** - * Tests are written using the "test" operator and the "assert" method. - */ - test("string take") { - val message = "hello, world" - assert(message.take(5) == "hello") - } - - /** - * For ScalaTest tests, there exists a special equality operator "===" that - * can be used inside "assert". If the assertion fails, the two values will - * be printed in the error message. Otherwise, when using "==", the test - * error message will only say "assertion failed", without showing the values. - * - * Try it out! Change the values so that the assertion fails, and look at the - * error message. - */ - test("adding ints") { - assert(1 + 2 === 3) - } - - import FunSets._ + import SetExtension._ test("contains is implemented") { assert(contains(x => true, 100)) } - + /** * When writing tests, one would often like to re-use certain values for multiple * tests. For instance, we would like to create an Int-set and have multiple test * about it. - * + * * Instead of copy-pasting the code for creating the set into every test, we can * store it in the test class using a val: - * + * * val s1 = singletonSet(1) - * + * * However, what happens if the method "singletonSet" has a bug and crashes? Then * the test methods are not even executed, because creating an instance of the * test class fails! - * + * * Therefore, we put the shared values into a separate trait (traits are like * abstract classes), and create an instance inside each test method. - * + * */ trait TestSets { @@ -82,15 +48,15 @@ class FunSetSuite extends FunSuite { /** * This test is currently disabled (by using "ignore") because the method * "singletonSet" is not yet implemented and the test would fail. - * + * * Once you finish your implementation of "singletonSet", exchange the * function "ignore" by "test". */ - ignore("singletonSet(1) contains 1") { - + test("singletonSet(1) contains 1") { + /** * We create a new instance of the "TestSets" trait, this gives us access - * to the values "s1" to "s3". + * to the values "s1" to "s3". */ new TestSets { /** @@ -101,7 +67,13 @@ class FunSetSuite extends FunSuite { } } - ignore("union contains all elements") { + test("singletonSet(1) does not contain 1") { + new TestSets { + assert(!contains(s1, 2), "Singleton not") + } + } + + test("union contains all elements") { new TestSets { val s = union(s1, s2) assert(contains(s, 1), "Union 1") @@ -109,4 +81,37 @@ class FunSetSuite extends FunSuite { assert(!contains(s, 3), "Union 3") } } -} + + test("forall: {1,2,3,4}") { + assert(forall(toFunSet(Set(1, 2, 3, 4)), x => x < 5), "All elements in the set are strictly less than 5") + } + + test("forall: {-1000,0}") { + assert(forall(toFunSet(Set(-1000)), x => x < 1000), "All elements in the set are strictly less than 1000") + } + + test("forall & filter: even") { + val s: Set = toFunSet((-500 to 500).toSet) + def even(x: Int) = x % 2 == 0 + assert(forall(FunSets.filter(s, even), even), "The set of all even numbers should contain only even numbers") + } + + test("forall & map: doubling numbers") { + val s: Set = toFunSet((-500 to 500).toSet) + def even(x: Int) = x % 2 == 0 + def double(x: Int) = x * 2 + assert(forall(FunSets.map(s, double), even), "The set obtained by doubling all numbers should contain only even numbers") + } + + test("exists: given {1,3,4,5,7,1000}") { + val s: Set = toFunSet(Set(1, 3, 4, 5, 7, 1000)) + assert(!FunSets.exists(s, x => x == 2), "2 shouldn't exist in the given set") + } + + test("exists & filter: even") { + val s: Set = toFunSet((-300 to 300).toSet) + def even(x: Int) = x % 2 == 0 + def odd(x: Int) = !even(x) + assert(!FunSets.exists(FunSets.filter(s, even), odd), "The set of all even numbers should not contain odd element.") + } +} \ No newline at end of file diff --git a/a2-funsets/src/test/scala/funsets/SetExtension.scala b/a2-funsets/src/test/scala/funsets/SetExtension.scala new file mode 100644 index 0000000..044a426 --- /dev/null +++ b/a2-funsets/src/test/scala/funsets/SetExtension.scala @@ -0,0 +1,9 @@ +package funsets + +import FunSets._ +import scala.language.implicitConversions +import scala.collection.immutable + +object SetExtension { + def toFunSet(l: immutable.Set[Int]): Set = (x => l.contains(x)) +} \ No newline at end of file diff --git a/a2-funsets/src/test/scala/funsets/SetSpecs.scala b/a2-funsets/src/test/scala/funsets/SetSpecs.scala new file mode 100644 index 0000000..6b552aa --- /dev/null +++ b/a2-funsets/src/test/scala/funsets/SetSpecs.scala @@ -0,0 +1,102 @@ +package funsets + +import org.scalatest.FunSuite + +import org.scalatest.PropSpec +import org.scalatest.prop.PropertyChecks +import org.scalatest.matchers.ShouldMatchers + +class SetsSpec extends PropSpec with PropertyChecks with ShouldMatchers { + import FunSets._ + import SetExtension._ + import scala.collection.immutable + + val emptySet: Set = (x => false) + val universalSet: Set = (x => true) + + property("union -- from definition") { + forAll { (l1: immutable.Set[Int], l2: immutable.Set[Int]) => + val unionSet: Set = FunSets.union(toFunSet(l1), toFunSet(l2)) + (l1 forall (contains(unionSet, _))) should be(true) + (l2 forall (contains(unionSet, _))) should be(true) + ((l1 ++ l2) forall (contains(unionSet, _))) should be(true) + } + } + + property("union -- no additional elements") { + forAll { (n: Int, l: immutable.Set[Int]) => + whenever(!(l contains n)) { + val unionSet: Set = FunSets.union(toFunSet(l), toFunSet(l)) + (!contains(unionSet, n)) should be(true) + } + } + } + + property("union -- with empty set") { + forAll { (l: immutable.Set[Int]) => + { + val unionSet: Set = FunSets.union(emptySet, toFunSet(l)) + (l forall (contains(unionSet, _))) should be(true) + } + } + } + + property("intersect -- from definition") { + forAll { (l1: immutable.Set[Int], l2: immutable.Set[Int]) => + val intersectSet: Set = FunSets.intersect(toFunSet(l1), toFunSet(l2)) + ((l1 intersect l2) forall (contains(intersectSet, _))) should be(true) + ((l1 diff l2) forall (!contains(intersectSet, _))) should be(true) + ((l2 diff l1) forall (!contains(intersectSet, _))) should be(true) + } + } + + property("intersect -- no additional elements") { + forAll { (n: Int, l: immutable.Set[Int]) => + whenever(!(l contains n)) { + val unionSet: Set = FunSets.union(toFunSet(l), toFunSet(l)) + (contains(unionSet, n)) should be(false) + } + } + } + + property("intersect -- with universal set") { + forAll { (l: immutable.Set[Int]) => + { + val intersectSet: Set = FunSets.intersect(universalSet, toFunSet(l)) + (l forall (contains(intersectSet, _))) should be(true) + } + } + } + + property("diff") { + forAll { (s1: immutable.Set[Int], s2: immutable.Set[Int]) => + { + val diffSet: Set = FunSets.diff(toFunSet(s1), toFunSet(s2)) + ((s1 diff s2) forall (contains(diffSet, _))) should be(true) + ((s2 diff s1) forall (!contains(diffSet, _))) should be(true) + } + } + } + + property("filter") { + forAll { (s: immutable.Set[Int]) => + { + def even(x: Int) = x % 2 == 0 + val filterSet: Set = FunSets.filter(toFunSet(s), even) + ((s filter even) forall (contains(filterSet, _))) should be(true) + ((s filter (x => !even(x))) forall (!contains(filterSet, _))) should be(true) + } + } + } + + property("map") { + forAll { (s1: immutable.Set[Int]) => + { + val s = s1.map(x => x % 300) + def double(x: Int) = 2 * x + val mappedSet: Set = FunSets.map(toFunSet(s), double) + ((s map double) forall (contains(mappedSet, _))) should be(true) + } + } + } +} \ No newline at end of file diff --git a/a2-funsets/src/test/scala/funsets/Sets.sc b/a2-funsets/src/test/scala/funsets/Sets.sc new file mode 100644 index 0000000..58307f3 --- /dev/null +++ b/a2-funsets/src/test/scala/funsets/Sets.sc @@ -0,0 +1,23 @@ +package funsets + +object Sets { + import FunSets._ + + implicit def list2set(l: List[Int]): Set = (x => l.contains(x)) + //> list2set: (l: List[Int])Int => Boolean + + val k = List() intersect List() //> k : List[Nothing] = List() + val universalSet: Set = (x => true) //> universalSet : Int => Boolean = + val emptySet: Set = (x => false) //> emptySet : Int => Boolean = + k forall (contains(universalSet, _)) //> res0: Boolean = true + k forall (contains(emptySet, _)) //> res1: Boolean = true + + val intersectSet = FunSets.intersect(List(), List()) + //> intersectSet : Int => Boolean = + ((List() diff List()) forall (contains(intersectSet, _))) + //> res2: Boolean = true + + List(0, 0) diff List(0) //> res3: List[Int] = List(0) + + (Set(-10)).map(x => math.abs(x)).max //> res4: Int = 10 +} \ No newline at end of file