       if expectations[outer].equals( expectations[inner] )
         _throw_duplicate_expectation("#{expectations[outer].method_name}(#{expectations[outer]._args})") 
 
-_find_expectation = (object, method_name, args...) ->
-  for expectation in Expectation._all_expectations when expectation.matches(object, method_name, args...)
-    return expectation
-  undefined
+_build_errors = (expectation) ->
+  # TODO: use a mapping function?
+  errors = ""
+  for expectation in expectation._all_expectations when expectation.called == false
+    errors += "'#{expectation.method_name}(#{expectation._args})' was never called\n"
+  errors
+
+_throw_args_usage = ->
+  throw "you need to supply at least one argument to args(), e.g. my_mock.expects('my_method').args(42)"
+
+_throw_args_called_more_than_once = ->
+  throw new Error("you called args() more than once, e.g. my_mock.expects('my_method').args(1).args(2); call it just once")
+
+_throw_returns_usage = ->
+  throw "you need to supply an argument to returns(), e.g. my_mock.expects('my_method').returns(123)"
+
+_throw_returns_called_more_than_once = ->
+  throw new Error("you called returns() more than once, e.g. my_mock.expects('my_method').returns(1).returns(2); call it just once")
+
+_throw_throws_usage = ->
+  throw "you need to supply an argument to throws(), e.g. my_mock.expects('my_method').throws('an error')"
+
+_throw_throws_called_more_than_once = ->
+  throw new Error("you called throws() more than once, e.g. my_mock.expects('my_method').throws('something').throws('something else'); call it just once")
+
+_throw_returns_and_throws_both_called = ->
+  throw new Error("you called returns() and throws() on the same expectation; use one or the other but not both")
+
+_throw_duplicate_expectation = (expectation) ->
+  throw "#{expectation} is a duplicate expectation"
+
+_throw_unknown_expectation = (expectation) ->
+  throw "#{expectation} does not match any expectations"
+
+
+
+expects = (method_name) ->
+  _check_expects_usage(method_name)
+  if @[ method_name ]? and typeof @[ method_name ] != 'function'
+    throw new Error("'#{method_name}' is an existing property; you can only mock functions")
+  if typeof @ == 'function' and not @.prototype[ method_name ]?
+    throw new Error("'#{method_name}' is not an existing method; you can only mock existing methods on classes")
+  _start_new_expectation(@, method_name)
+
+_check_expects_usage = (method_name) ->
+  _throw_expects_usage() unless method_name?
+  _throw_reserved_word(method_name) if _is_reserved_word(method_name)
+
+_is_reserved_word = (word) ->
+  word in [ "expects", "args", "returns", "check" ]
+
+_throw_expects_usage = ->
+  throw "you need to supply a method name to expects(), e.g. my_mock.expects('my_method')"
+
+_throw_reserved_word = (reserved) ->
+  throw "you cannot do my_mock.expects('#{reserved}'); '#{reserved}' is a reserved method name"
 
 _start_new_expectation = (object, method_name) ->
   new Expectation(object, method_name)
-
-_throw_expects_usage = ->
-  throw "you need to supply a method name to expects(), e.g. my_mock.expects('my_method')"
-
-_throw_reserved_word = (reserved) ->
-  throw "you cannot do my_mock.expects('#{reserved}'); '#{reserved}' is a reserved method name"
-
-_throw_duplicate_expectation = (expectation) ->
-  throw "#{expectation} is a duplicate expectation"
-
-_throw_unknown_expectation = (expectation) ->
-  throw "#{expectation} does not match any expectations"
 
 
 

#
# Expectation represents a mocked method that we expect to be called.
# It stores the method name, the arguments that we expect to be called
# with, a value to return or throw, and whether it has actually been
# called.  For example, the following:
#
#   my_mock = new Mock()
#   expectation = my_mock.expects("my_method").args(1,2,3).returns(42)
#
# would result in a Expectation with @method_name = "my_method",
# @_args = [1,2,3], @_returns = 42, @_throws = undefined, and @called =
# false.  Doing:
#
#   my_mock.my_method(1,2,3)
#
# would result in @called = true.  Note that a mocked method can
# either return a value or throw an error but not both, so either
# @returns or @throws (or both) must be undefined.
#
class Expectation
  
  @_all_expectations: []

    throw expectation._throws if expectation._throws?
    expectation._returns

_find_expectation = (object, method_name, args...) ->
  for expectation in Expectation._all_expectations when expectation.matches(object, method_name, args...)
    return expectation
  undefined

_check_for_duplicate_expectations = (mock) ->
  # TODO: use each with index and slice to avoid last element
