David Garamond wrote:
> For deterministic functions/methods, the same set of inputs should 
> always produces the same output. What about adding something like:
> 
>  assert_follows_spec(method_or_class_name, spec)
> 
> Where spec is an array of input and output pairs (and optionally an 
> exception, if the input should not be accepted):
> 
>  [{input => [1, 1, 1], output => 1},
>   {input => [8, 1, 2], output => 4},
>   {input => [8, 3, 4], output => 6},
>   {input => [4, 3, 2], output => 6},
>   {input => [1, 2, nil], exception => ArgumentError},
>   {input => [1, 2, 0], exception => ZeroDivisionError}]

Of course the above should be written as :input, :output, etc. Too much 
writing YAML, I guess :-).

Some more ideas:

* max_delta for floats:

  {:input => [1, 3.0], :output    => 0.333333333333333,
                       :max_delta => 0.000000000000001}

* support for non-deterministic func/methods, like 'output_in' (multiple 
possible outputs), 'output_class' and 'output_range' (for any acceptable 
output or a certain clas and inside a certain range). e.g. for testing 
Kernel#rand:

  [{:input => [1], :output => 0},
   {:input => [3], :output_in => [0, 1, 2]},
   {:input => [],  :output_class => Float,
                   :output_range => 0...1.0}]

Basically, I'm seeing assert_follows_spec (or assert_calls, or whatever) 
as simply an aggregate of lots of simpler asserts (assert_equals, 
assert_raises, etc) as one big assert. The difference is, it's shorter 
(it saves some keystrokes), nicer/tidier, and the "spec" itself is a 
data structure and can be changed/manipulated/displayed/etc more easily.

Of course, this "spec" in many cases cannot cover all aspects of the 
testing, only simpler ones. So perhaps a better name for "spec" is desired.

-- 
dave