|
Scala example source code file (ZipperTest.scala)
The ZipperTest.scala Scala example source codepackage scalaz import Scalaz._ import NonEmptyList.nels import Zipper._ import scalaz.scalacheck.ScalazProperties._ import scalaz.scalacheck.ScalazArbitrary._ import org.scalacheck.Arbitrary import org.scalacheck.Arbitrary.arbitrary import org.scalacheck.{Gen, Prop} import org.scalacheck.Prop.forAll object ZipperTest extends SpecLite { "Zipper From Stream" ! forAll { (xs: Stream[Int]) => (xs.toZipper map (_.toStream)).getOrElse(Stream()) === xs } "Mapping on a zipper should be the same as mapping on the elements of the stream" ! forAll { (xs: Stream[Int], a: Int) => val fun: Int => Int = _ + a ( for (z <- xs.toZipper; zM <- (xs map fun).toZipper) yield z.map(fun) must_===(zM) ) getOrElse { xs.length must_===(0) } } "Zipper Move Then To Stream" in check { val n = nels(1, 2, 3, 4) n.toZipper.move(2).map(_.toStream).exists(_ ==(n.stream)) } "Next Affects Lengths" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.toZipper; zn <- z.next) yield { (zn.lefts.length must_===(z.lefts.length + 1)); (zn.rights.length must_===(z.rights.length - 1)) } ) getOrElse { xs.length mustBe_<(2) } } "nextC moves focus or loops" ! forAll { z: Zipper[Int] => val zn = z.nextC zn.toStream must_===(z.toStream) if (z.atEnd) zn.atStart must_==(true) else zn.index must_===(z.index + 1) } "Next changes focus, lefts and rights " ! forAll { (l: Stream[Int], f: Int, r: Stream[Int]) => if (r.length > 0) { val nextZipper = zipper(l, f, r).next.get nextZipper.focus must_===(r(0)) nextZipper.lefts must_===(f +: l) nextZipper.rights must_===(r.tail) } else { zipper(l, f, r).next.isEmpty must_==(true) } } "Zipper next returns Some when rights is nonempty, none otherwise." ! forAll { (l: Stream[Int], f: Int, r: Stream[Int]) => if (r.length > 0) zipper(l, f, r).next.isDefined must_==(true) else zipper(l, f, r).next.isDefined must_==(false) } "Zipper nextOr returns a new zipper when used on empty rights or Some of next" ! forAll { (l: Stream[Int], f: Int, r: Stream[Int], alt: Zipper[Int]) => val z = zipper(l, f, r) if (r.length > 0) { z.next must_===(Some(z.nextOr(alt))) } else { z.nextOr(alt) must_===(alt) } } "Previous Affects Lengths" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.zipperEnd; zn <- z.previous) yield zn.lefts.length must_===(z.lefts.length - 1) and (zn.rights.length must_===(z.rights.length + 1)) ) getOrElse { xs.length mustBe_<(2) } } "previousC moves focus or loops" ! forAll { z: Zipper[Int] => val zp = z.previousC zp.toStream must_===(z.toStream) if (z.atStart) zp.atEnd must_==(true) else zp.index must_===(z.index - 1) } "Previous changes the focus, lefts and rights " ! forAll { (l: Stream[Int], f: Int, r: Stream[Int]) => if (l.length > 0) { val prevZipper = zipper(l, f, r).previous.get prevZipper.focus must_===(l(0)) prevZipper.lefts must_===(l.tail) prevZipper.rights must_===(f +: r) } else { zipper(l, f, r).previous.isDefined must_==(false) } } "Zipper previousOr returns a new zipper when used on empty rights or Some of next" ! forAll { (l: Stream[Int], f: Int, r: Stream[Int], alt: Zipper[Int]) => val z = zipper(l, f, r) if (l.length > 0) { z.previous must_===(Some(z.previousOr(alt))) } else { z.previousOr(alt) must_===(alt) } } "Zipper tryPrevious returns Some of next or throws" ! forAll { (l: Stream[Int], f: Int, r: Stream[Int]) => val z = zipper(l, f, r) if (l.length > 0) { z.previous must_===(Some(z.tryPrevious)) } else { z.tryPrevious.mustThrowA[RuntimeException] } } def insertionTest( name: String, insertion: (Zipper[Int], Int) => Zipper[Int], pred: (Zipper[Int], Zipper[Int], Int) => Prop) = name ! forAll { (z: Zipper[Int], e: Int) => val zi = insertion(z, e) pred(zi, z, e) } val leftAndFocusChanged: (Zipper[Int], Zipper[Int], Int) => Prop = { (zNew, zOld, newFocus) => {zNew.focus must_===(newFocus)} and {zNew.lefts.head must_===(zOld.focus)} and {zNew.lefts.tail must_===(zOld.lefts)} and {zNew.rights must_===(zOld.rights)} } val rightAndFocusChanged: (Zipper[Int], Zipper[Int], Int) => Prop = { (zNew, zOld, newFocus) => {zNew.focus must_===(newFocus)} and {zNew.lefts must_===(zOld.lefts)} and {zNew.rights.head must_===(zOld.focus)} and {zNew.rights.tail must_===(zOld.rights)} } insertionTest("insertRight changes focus and appends to lefts", (z, e) => z.insertRight(e), leftAndFocusChanged) insertionTest("insert changes focus and appends to lefts", (z, e) => z.insert(e), leftAndFocusChanged) insertionTest("insertLeft changes focus and appends to lefts", (z, e) => z.insertLeft(e), rightAndFocusChanged) "DeleteRight Affects Lengths" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.toZipper; zn <- z.deleteRight) yield zn.rights.length must_===(z.rights.length - 1) ) getOrElse {xs.length mustBe_<(2) } } "DeleteRightC Affects Lengths" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.toZipper; zn <- z.deleteRightC) yield zn.rights.length must_===(z.rights.length - 1) ) getOrElse {xs.length mustBe_<(2) } } "deleteRightC moves the focus to the right or if not possible to the first element" ! forAll { z: Zipper[Int] => ( for { zd <- z.deleteRightC } yield { if (z.rights.length > 0) zd.focus must_===(z.rights(0)) else zd.focus must_===(z.lefts.last) } ) getOrElse{ (z.lefts.isEmpty must_==(true)) and (z.rights.isEmpty must_==(true)) } } "deleteRightCOr should return Some of deleteLeftC or an alternative" ! forAll { (z: Zipper[Int], alt: Zipper[Int]) => val zd = z.deleteRightCOr(alt) if (z.lefts.length == 0 && z.rights.length == 0) zd must_===(alt) else z.deleteRightC must_===(Some(zd)) } "DeleteRight Affects Lengths and Moves Left if at end" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.zipperEnd; zn <- z.deleteRight) yield zn.lefts.length must_===(z.lefts.length - 1) ) getOrElse ( xs.length mustBe_<(2) ) } "deleteRight moves the focus to the right or if not possible left" ! forAll { z: Zipper[Int] => ( for { zd <- z.deleteRight } yield { if (z.rights.length > 0) zd.focus must_===(z.rights(0)) else zd.focus must_===(z.lefts(0)) } ) getOrElse{ (z.lefts.isEmpty must_==(true)) and (z.rights.isEmpty must_==(true)) } } "deleteRightOr should return Some of deleteLeft or an alternative" ! forAll { (z: Zipper[Int], alt: Zipper[Int]) => val zd = z.deleteRightOr(alt) if (z.lefts.length == 0 && z.rights.length == 0) zd must_===(alt) else if (z.rights.length != 0) (zd.rights must_===(z.rights.tail)) and (zd.lefts must_===(z.lefts)) else (zd.rights.isEmpty must_==(true)) and (zd.lefts must_===(z.lefts.tail)) } "DeleteLeft Affects Lengths" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.zipperEnd; zn <- z.deleteLeft) yield zn.lefts.length must_===(z.lefts.length - 1) ) getOrElse (xs.length mustBe_<(2)) } "deleteLeft moves the focus to the left or if not possible right" ! forAll { z: Zipper[Int] => ( for { zd <- z.deleteLeft } yield { if (z.lefts.length > 0) zd.focus must_===(z.lefts(0)) else zd.focus must_===(z.rights(0)) } ) getOrElse((z.lefts.isEmpty must_==(true)) and (z.rights.isEmpty must_==(true))) } "DeleteLeftC Affects Lengths" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.zipperEnd; zn <- z.deleteLeftC) yield zn.lefts.length must_===(z.lefts.length - 1) ) getOrElse (xs.length mustBe_<(2)) } "deleteLeftC moves the focus to the left or if not possible to the last element" ! forAll { z: Zipper[Int] => ( for { zd <- z.deleteLeftC } yield { if (z.lefts.length > 0) zd.focus must_===(z.lefts(0)) else zd.focus must_===(z.rights.last) } ) getOrElse((z.lefts.isEmpty must_==(true)) and (z.rights.isEmpty must_==(true))) } "deleteLeftCOr should return Some of deleteLeftC or an alternative" ! forAll { (z: Zipper[Int], alt: Zipper[Int]) => val zd = z.deleteLeftCOr(alt) if (z.lefts.length == 0 && z.rights.length == 0) zd must_===(alt) else z.deleteLeftC must_===(Some(zd)) } "deleteRightOr should return Some of deleteLeft or an alternative" ! forAll { (z: Zipper[Int], alt: Zipper[Int]) => val zd = z.deleteRightOr(alt) if (z.lefts.length == 0 && z.rights.length == 0) zd must_===(alt) else if (z.rights.length != 0){ zd.rights must_===(z.rights.tail) zd.lefts must_===(z.lefts) }else{ zd.rights.isEmpty must_==(true) zd.lefts must_===(z.lefts.tail) } } "DeleteLeft Affects Lengths and Moves Right if at start" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.toZipper; zn <- z.deleteLeft) yield zn.rights.length must_===(z.rights.length - 1) ) getOrElse (xs.length mustBe_<(2)) } "deleteLeftOr should return Some of deleteLeft or an alternative" ! forAll { (z: Zipper[Int], alt: Zipper[Int]) => if (z.lefts.length == 0 && z.rights.length == 0) z.deleteLeftOr(alt) must_===(alt) else { val zd = z.deleteLeftOr(alt) if (z.lefts.length != 0){ zd.lefts must_===(z.lefts.tail) zd.rights must_===(z.rights) }else{ zd.lefts.isEmpty must_==(true) zd.rights must_===(z.rights.tail) } } } "DeleteRightC Affects Lengths and Cycles to Start if at end" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.zipperEnd; zn <- z.deleteRightC) yield zn.rights.length must_===(z.lefts.length - 1) ) getOrElse (xs.length mustBe_<(2)) } "DeleteLeftC Affects Lengths and Cycles to end if at start" ! forAll { (xs: Stream[Int]) => ( for (z <- xs.toZipper; zn <- z.deleteLeftC) yield zn.lefts.length must_===(z.rights.length - 1) ) getOrElse (xs.length mustBe_<(2)) } "Move" ! forAll { (xs: Stream[Int], ys: Stream[Int], f: Int, n: Short) => zipper(xs, f, ys).move(n) map { (z: Zipper[Int]) => z.lefts.length must_===(xs.length + n) z.rights.length must_===(ys.length - n) if(n > 0) ys(n - 1) must_===(z.focus) else if(n < 0) xs(-(n + 1)) must_===(z.focus) else f must_===(z.focus) } getOrElse { val okay = xs.length < -n || ys.length < n okay must_==(true) } } "move should not cause a stackoverflow error" in { val size = 32 * 1024 val n = size - 1 val f = for { z <- Stream.from(1).take(size).toZipper zm <- z.move(n) } yield zm.focus f must_===(Some(size)) } "moveOr should return some of move or an alternative" ! forAll { (l: Stream[Int], f: Int, r: Stream[Int], n: Short, alt: Zipper[Int]) => val z = zipper(l, f, r).moveOr(n, alt) if (l.length < (-n) || r.length < n) z must_===(alt) else { z.lefts.length must_===(l.length + n) z.rights.length must_===(r.length - n) if(n > 0) r(n - 1) must_===(z.focus) else if(n < 0) l(-(n + 1)) must_===(z.focus) else f must_===(z.focus) } } "Length should return the size of the zipper" ! forAll { (l: Stream[Int], f: Int, r: Stream[Int]) => zipper(l, f, r).length must_===(l.length + 1 + r.length) } "The zipper should be atStart when the lefts stream is empty" ! forAll { (l: Stream[Int], f: Int, r: Stream[Int]) => if (zipper(l, f, r).atStart) l.isEmpty must_==(true) else l.isEmpty must_==(false) } "withFocus should pair only the focus with true, false otherwise" ! forAll { z: Zipper[Int] => val zf = z.withFocus zf.lefts.find(_._2).isEmpty must_==(true) zf.focus._2 must_==(true) zf.rights.find(_._2).isEmpty must_==(true) } "start should set the zipper at the start" ! forAll { z: Zipper[Int] => val zs = z.start zs.toStream must_===(z.toStream) zs.index must_===(0) } "end should set the zipper at the end" ! forAll { z: Zipper[Int] => val ze = z.end ze.toStream must_===(z.toStream) ze.index must_===(ze.length - 1) } "The zipper should be atEnd when the right stream is empty" ! forAll { (l: Stream[Int], f: Int, r: Stream[Int]) => if (zipper(l, f, r).atEnd) r.isEmpty else !r.isEmpty } "Find" ! forAll { (xs: Stream[Int], ys: Stream[Int], f: Int, n: Int, m: Int) => val p = (i: Int) => i < n && i > m zipper(xs, f, ys).findZ(p) map { z => p(z.focus) } getOrElse !(xs.find(p).isDefined || ys.find(p).isDefined || p(f)) } "findZ shouldn't change elements" ! forAll { (xs: Stream[Int], ys: Stream[Int], f: Int, n: Int, m: Int) => val p = (i: Int) => i < n && i > m zipper(xs, f, ys).findZ(p).map { z => z.toStream == zipper(xs, f, ys).toStream } getOrElse !(xs.find(p).isDefined || ys.find(p).isDefined || p(f)) } "findZor returns some of find or an alternative" ! forAll { (z: Zipper[Int], n: Int, m: Int, alt: Zipper[Int]) => val p = (i: Int) => i < n && i > m if (z.lefts.find(p).isDefined || p(z.focus) || z.rights.find(p).isDefined) { p(z.findZor(p, alt).focus) must_==(true) } else { z.findZor(p, alt) must_===(alt) } } "findZ should not cause a stackoverflow error" in { val size = 32 * 1024 val elem = size - 1 val r = for { z <- Stream.from(1).take(size).toZipper zf <- z.findZ(_ == elem) } yield zf.focus r must_===(Some(elem)) } "findBy if given a function that returns None should not return anything" ! forAll { z: Zipper[Int] => z.findBy(z => None)(x => x == z.focus).isEmpty } val intZipperWithExistingElement: Gen[(Zipper[Int], Int)] = for { z <- arbitrary[Zipper[Int]] stream = z.toStream i <- Gen.choose(0, stream.length -1) } yield (z, stream(i)) "given nextC findBy should return Some if the element exists" ! forAll(intZipperWithExistingElement) { case (z, e) => z.findBy(z => some(z.nextC))(x => x == e).isDefined } "findBy should not blow the stack" ! prop { z: Zipper[Int] => var limit = 10 * 1000 z.findBy(z => if (limit > 0) { limit -= 1; some(z.nextC) } else none)(x => false) true } def minSizeIntZipper(size: Int): Gen[Zipper[Int]] = for { leftSize <- Gen.choose(0, size - 2) rightSize = size - 1 - leftSize lefts <- Gen.containerOfN[Stream,Int](leftSize, implicitly[Arbitrary[Int]].arbitrary) rights <- Gen.containerOfN[Stream,Int](rightSize, implicitly[Arbitrary[Int]].arbitrary) focus <- arbitrary[Int] } yield zipper(lefts, focus, rights) "findNext should not blow the stack" ! forAll(minSizeIntZipper(10 * 1000)) { z => var limit = 10 * 1000 z.start.findNext { x => limit -= 1; limit > 0 } true } "findPrevious should not blow the stack" ! forAll(minSizeIntZipper(10 * 1000)) { z => var limit = 10 * 1000 z.end.findPrevious { x => limit -= 1; limit > 0 } true } "Update Modifies Zipper Correctly" ! forAll { (xs: Stream[Int], ys: Stream[Int], f: Int, u: Int) => zipper(xs, f, ys).update(u) must_===(zipper(xs, u, ys)) } "Modify Modifies Zipper Correctly" ! forAll { (xs: Stream[Int], ys: Stream[Int], f: Int, u: Int) => val modF: Int => Int = _ + u zipper(xs, f, ys).modify(modF) must_===(zipper(xs, f + u, ys)) } "Start" ! forAll { (xs: Stream[Int], ys: Stream[Int], f: Int) => val zo = zipper(xs, f, ys) val z = zo.start z.lefts.length must_===(0) z.rights.length must_===(z.length - 1) zo.move(-xs.length) must_===(Some(z)) ((z.move(xs.length) == Some(zo)) || z.length == 0) must_==(true) } "End" ! forAll { (xs: Stream[Int], ys: Stream[Int], f: Int) => val zo = zipper(xs, f, ys) val z = zo.end z.lefts.length must_===(z.length - 1) z.rights.length must_===(0) zo.move(ys.length) must_===(Some(z)) (z.move(-ys.length) == Some(zo) || (z.length == 0)) must_==(true) } "positions should return a zippers with focus on this" ! forAll { z: Zipper[Int] => z.positions.focus must_===(z) } "positions should return a zippers with all possible positions of a zipper" ! forAll { z: Zipper[Int] => val indeces = z.positions.map { _.index }.toStream indeces.min must_===(0) indeces.max must_===(z.length -1) indeces.sorted must_===(indeces) z.positions.map { _.toStream }.toStream.distinct.length must_===(1) } "index returns the position of the focus" ! forAll { (l: Stream[Int], f: Int, r: Stream[Int]) => zipper(l, f, r).index must_===(l.length) } checkAll("Zipper", equal.laws[Zipper[Int]]) checkAll("Zipper", traverse1.laws[Zipper]) checkAll("Zipper", FoldableTests.anyAndAllLazy[Zipper]) checkAll("Zipper", comonad.laws[Zipper]) { implicit def zipperEqual[A: Equal]: Equal[Zipper[A]] = new Equal[Zipper[A]] { import std.stream.streamEqual def streamEqualApprox = streamEqual[A].contramap((_: Stream[A]).take(1000)) def equal(a1: Zipper[A], a2: Zipper[A]) = streamEqualApprox.equal(a1.lefts, a2.lefts) && Equal[A].equal(a1.focus, a2.focus) && streamEqualApprox.equal(a1.rights, a2.rights) } checkAll("Zipper", applicative.laws[Zipper]) } } // vim: expandtab:ts=2:sw=2 Other Scala examples (source code examples)Here is a short list of links related to this Scala ZipperTest.scala source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.