У меня есть функции A => Double
. Я хочу проверить, дают ли две такие функции одинаковые результаты (до допуска, используя существующий beCloseTo
matcher) для заданного набора значений.
Я хочу иметь возможность написать:
type TF = A => Double
(f: TF) must computeSameResultsAs(g: TF,tolerance: Double, tests: Set[A])
Я хочу построить этот матчер модульно, а не просто написать Matcher[TF]
с нуля.
Было бы еще лучше, если бы я мог написать:
(f: TF) must computeSameResultsAs(g: TF)
.withTolerance(tolerance)
.onValues(tests: Set[A])
Также я хочу получить разумное описание, когда матчер терпит неудачу.
После сна над этим я пришел к следующему.
def computeSameResultsAs[A](ref: A => Double, tolerance: Double, args: Set[A]): Matcher[A => Double] =
args.map(beCloseOnArg(ref, tolerance, _)).reduce(_ and _)
def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] =
closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg))
Это намного короче, чем решение Эрика, но не дает хорошего сообщения о неудаче. Мне бы хотелось иметь возможность переименовывать сопоставленное значение во втором методе. Что-то вроде следующего (которое не компилируется).
def beCloseOnArg[A](ref: A => Double, tolerance: Double, arg: A): Matcher[A => Double] =
closeTo(ref(arg), tolerance) ^^ ((_: A => Double).apply(arg) aka "result on argument " + arg)