# Untitled

By: a guest on May 26th, 2012  |  syntax: None  |  size: 3.32 KB  |  hits: 10  |  expires: Never
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
1. Creating a Specs2 matcher in a modular way
2. type TF = A => Double
3. (f: TF) must computeSameResultsAs(g: TF,tolerance: Double, tests: Set[A])
4.
5. (f: TF) must computeSameResultsAs(g: TF)
6.                .withTolerance(tolerance)
7.                .onValues(tests: Set[A])
8.
9. def computeSameResultsAs[A](ref: A => Double, tolerance: Double, args: Set[A]): Matcher[A => Double] =
10.   args.map(beCloseOnArg(ref, tolerance, _)).reduce(_ and _)
11.
12. def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] =
13.   closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg))
14.
15. def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] =
16.   closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg) aka "result on argument " + arg)
17.
18. def computeSameResultsAs[A](g: A => Double,
19.                             tolerance: Double = 0.0,
20.                             values: Seq[A] = Seq()) = TFMatcher(g, tolerance, values)
21.
22. case class TFMatcher[A](g: A => Double,
23.                         tolerance: Double = 0.0,
24.                         values: Seq[A] = Seq()) extends Matcher[A => Double] {
25.
26.   def apply[S <: A => Double](f: Expectable[S]) = {
27.     // see definition below
28.   }
29.
30.   def withTolerance(t: Double) = TFMatcher(g, t, values)
31.   def onValues(tests: A*) = TFMatcher(g, tolerance, tests)
32. }
33.
34. val f = (i: Int) => i.toDouble
35. val g = (i: Int) => i.toDouble + 0.1
36.
37. "f must be close to another similar function with a tolerance" in {
38.   f must computeSameResultsAs[Int](g).withTolerance(0.5).onValues(1, 2, 3)
39. }
40.
41. def apply[S <: A => Double](f: Expectable[S]) = {
42.   val res = ((v: A) => beCloseTo(g(v) +/- tolerance).apply(theValue(f.value(v)))).forall(values)
43.
44.   val message = "f is "+(if (res.isSuccess) "" else "not ")+
45.                 "close to g with a tolerance of "+tolerance+" "+
46.                 "on values "+values.mkString(",")+": "+res.message
47.    result(res.isSuccess, message, message, f)
48.  }
49.
50. ((v: A) => beCloseTo(g(v) +/- tolerance).apply(theValue(f.value(v)))).forall(values)
51.
52. val f = (i: Int) => i.toDouble
53. val g = (i: Int) => i.toDouble + 1.0
54.
55. "f must be close to another similar function with a tolerance" in {
56.   f must computeSameResultsAs[Int](g, tolerance = 0.5, values = Seq(1, 2, 3))
57. }
58.
59. def computeSameResultsAs[A](ref: A => Double, tolerance: Double, values: Seq[A]): Matcher[A => Double] = (f: A => Double) => {
60.   verifyFunction((a: A) => (beCloseTo(ref(a) +/- tolerance)).apply(theValue(f(a)))).forall(values)
61. }
62.
63. In the sequence '1, 2, 3', the 1st element is failing: 1.0 is not close to 2.0 +/- 0.5
64.
65. implicit def functionResultToMatcher[T](f: T => MatchResult[_]): Matcher[T] = (t: T) => {
66.   val result = f(t)
67.   (result.isSuccess, result.message)
68. }
69.
70. 1.0 is not close to 2.0 +/- 0.5; 2.0 is not close to 3.0 +/- 0.5; 3.0 is not close to 4.0 +/- 0.5
71.
72. def computeSameResultsAs[A](ref: A => Double, tolerance: Double, values: Seq[A]): Matcher[A => Double] = (f: A => Double) => {
73.   ((a: A) => beCloseTo(ref(a) +/- tolerance) ^^ f).forall(values)
74. }
75.
76. def computeSameResultsAs[A](ref: A => Double, tolerance: Double, values: Seq[A]): Matcher[A => Double] = (f: A => Double) => {
77.   ((a: A) => beCloseTo(ref(a) +/- tolerance) ^^ ((a1: A) => f(a) aka "the value")).forall(values)
78. }
79.
80. In the sequence '1, 2, 3', the 1st element is failing: the value '1.0' is not close to 2.0 +/- 0.5