property("no negative output") = forAll { (m: Int, n: Int) => val result: Int = myMagicMathOperation(m, n) result >= 0 } property("actually compressed") = forAll { xs: List[String] => val result: List[String] = myCompressor(xs) result.length <= xs.length } property("is monotonic") = forAll { (n1: Float, n2: Float) => val r1 = myMonotonicFunction(n1) val r2 = myMonotonicFunction(n2) if (n1 > n2) r1 >= r2 else r1 <= r2 }
import org.scalacheck.{Gen, Prop} // A tweet generator val genTweet: Gen[String] = ... // The function under test def rankTweet(tweet: String): Int = ... val propRankTweet = Prop.forAll(genTweet) { tweet => val score = rankTweet(tweet) ... }
val propRankTweet = Prop.forAll(genTweet, genTweet) { (tweet1,tweet2) => val score1 = rankTweet(tweet1) val score2 = rankTweet(tweet2) if (tweet1.length <= tweet2.length) score1 >= score2 else score1 < score2 }
import java.util.HashMap import collection.JavaConversions._ import collection.immutable.IntMap def equalMaps(hm: HashMap[Int,Any], im: IntMap[Any]) = { im.keys.forall(hm.containsKey) && hm.keySet.containsAll(im.keys) && im.keys.forall(k => im(k) == hm(k)) } import org.scalacheck.Gen import org.scalacheck.Arbitrary.arbitrary val genMaps: Gen[(HashMap[Int,Any],IntMap[Any])] = arbitrary[List[Int]] map { xs => val mappings = for(n <- xs) yield (n, new Object) val im = IntMap(mappings: _*) val hm = new HashMap[Int, Any] for((n,x) <- mappings) hm.put(n,x) (hm,im) }
import org.scalacheck.Prop.{forAll, AnyOperators} import org.scalacheck.Properties object IntMapSpec extends Properties("IntMap") { property("size") = forAll(genMaps) { case (hm, im) => im.size ?= hm.size } property("isEmpty") = forAll(genMaps) { case (hm,im) => im.isEmpty ?= hm.isEmpty } property("add") = forAll(genMaps) { case (hm,im) => forAll { (k: Int, v: String) => hm.put(k, v) equalMaps(hm, im + (k -> v)) } } }
import org.scalacheck.Prop.{forAll, BooleanOperators} val propSqrt = forAll { n: Int => (n >= 0) ==> { val m = math.sqrt(n) math.round(m*m) == n } }
import org.scalacheck.Prop.{forAll, BooleanOperators} val propSlice = forAll { (xs: List[Int], n: Int, m: Int) => (m >= n && xs.indices.contains(n) && xs.indices.contains(m) ) ==> { val s = xs.slice(n,m) s.length == (m-n) && xs.containsSlice(s) } }
scala> propSlice.check ! Gave up after only 2 passed tests. 99 tests were discarded.
import org.scalacheck.Prop.{forAll, BooleanOperators} import org.scalacheck.Gen.oneOf val propSlice = forAll { xs: List[Int] => forAll(oneOf(xs.indices), oneOf(xs.indices)) { (m, n) => m >= n ==> { val s = xs.slice(n,m) s.length == (m-n) && xs.containsSlice(s) } } }
scala> propSlice.check + OK, passed 100 tests.
property("reverse inverse") = Prop.forAll { xs: List[Int] => xs.reverse.reverse == xs }
import org.scalacheck.Prop.forAll def encodeBin(n: Int): String = n match { case 0 => "0" case 1 => "1" case n if n % 2 == 1 => encodeBin(n / 2) + "1" case n => encodeBin(n / 2) + "0" } def decodeBin(s: String): Int = if (s.isEmpty) 0 else s.last match { case '0' => 2 * decodeBin(s.substring(0,s.length-1)) case '1' => 2 * decodeBin(s.substring(0,s.length-1)) + 1 } val propDecodeEncode = forAll { n: Int => decodeBin(encodeBin(n)) == n }
scala> propDecodeEncode.check ! Falsified after 2 passed tests. > ARG_0: -1 > ARG_0_ORIGINAL: -927439645
import org.scalacheck.Prop.{forAll, BooleanOperators} val propDecodeEncode = forAll { n: Int => n >= 0 ==> (decodeBin(encodeBin(n)) == n) }
type AST = ... def parse(s: String): AST = ... def prettyPrint(ast: AST): String = ... val astGenerator: Gen[AST] = ... val prop = forAll(astGenerator) { ast => parse(prettyPrint(ast)) == ast }
def runlengthEnc[A](xs: List[A]): List[(Int,A)] = ...
import org.scalacheck.Gen import Gen.{choose, alphaNumChar, sized} val genOutput: Gen[List[(Int,Char)]] = { def rleItem: Gen[(Int,Char)] = for { n <- choose(1,20) c <- alphaNumChar } yield (n,c) def rleList(size: Int): Gen[List[(Int,Char)]] = { if (size <= 1) rleItem.map(List(_)) else for { tail@(_,c1)::_ <- rleList(size-1) head <- rleItem retryUntil (_._2 != c1) } yield head :: tail } sized(rleList) }
def runlengthDec[A](r: List[(Int,A)]): List[A] = r flatMap { case (n,x) => List.fill(n)(x) }
val p = Prop.forAll(genOutput) { r => runlengthEnc(runlengthDec(r)) == r }
For more information about ScalaCheck: The Definitive Guide, please visit: http://www.artima.com/shop/scalacheck and: |
Copyright © 2013-2014 Artima, Inc. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. |