<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>tests/mock/multiple_listento.stest.php</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -8,7 +8,7 @@
  * the name of the class is unknown
  * @param $obj an instance of an object
  **/
-function SNAP_calStatic($obj, $method, $params = array()) {
+function SNAP_callStatic($obj, $method, $params = array()) {
     
     $params = (is_array($params)) ? $params : array($params);
     $obj_name = (is_object($obj)) ? get_class($obj) : strval($obj);
@@ -26,17 +26,19 @@ function SNAP_calStatic($obj, $method, $params = array()) {
  */
 class Snap_MockObject {
     
-    protected $requires_inheritance;
-    protected $interface_names;
     protected $mocked_class;
+    protected $interface_names;
+    protected $has_constructor;
     protected $requires_magic_methods;
     protected $requires_static_methods;
-    protected $has_constructor;
+    protected $requires_inheritance;
+    
+    protected $methods;
+    protected $signatures;
+    protected $counters;
+    protected $constructed_object;
     
-    public $methods;
-    public $signatures;
     public $constructor_args;
-    public $counters;
     public $mock_output;
 
     /**
@@ -58,6 +60,7 @@ class Snap_MockObject {
         $this-&gt;constructor_args = array();
         $this-&gt;counters = array();
         $this-&gt;mocked_class = $class_name;
+        $this-&gt;constructed_object = null;
         
         // do some quick reflection on the class
         $reflected_class = new ReflectionClass($this-&gt;mocked_class);
@@ -193,47 +196,6 @@ class Snap_MockObject {
         $this-&gt;logMethodSignature($method_name, $method_signature, $method_params);
         return $this;
     }
-        
-    /**
-     * Record the method name, signature, and expectations
-     * @param string $method_name the name of the method to record a signature for
-     * @param string $method_signature the signature of the method
-     * @param array $method_params the array of expectations that make up this signature
-     * @return void
-     */
-    protected function logMethodSignature($method_name, $method_signature, $method_params) {
-        if (!isset($this-&gt;signatures[$method_name])) {
-            $this-&gt;signatures[$method_name] = array();
-        }
-        
-        $this-&gt;methods[$method_signature]['count'] = 0;
-        $this-&gt;methods[$method_signature]['exec_count'] = 0;
-        
-        $this-&gt;signatures[$method_name][$method_signature] = array(
-            'params'    =&gt; $method_params,
-        );
-    }
-    
-    /**
-     * Check parameter list, and wrap parameter in a MockObject_Expectation class if necessary
-     * @access protected
-     * @param array $method_params the method arguments
-     * @return array the processed parameter list
-     */
-    protected function handleMethodParameters($method_params) {
-        foreach ($method_params as $idx =&gt; $param) {
-            if (is_object($param) &amp;&amp; ($param instanceof Snap_Expectation)) {
-                continue;
-            }
-        
-            if ((substr($param, 0, 1) == '/') &amp;&amp; (substr($param, -1, 1) == '/')) {
-                $method_params[$idx] = new Snap_Regex_Expectation($param);
-            }
-            
-            $method_params[$idx] = new Snap_Equals_Expectation($param);
-        }
-        return $method_params;
-    }
     
     /**
      * Generate the method's signature based on its params
@@ -373,31 +335,17 @@ class Snap_MockObject {
 
         // add a runConstructor call if this is refection+extension
         if ($this-&gt;isInherited() || $this-&gt;hasConstructor()) {
+            $get_mock = '$this-&gt;'.$this-&gt;class_signature.'_getMock';
+            
             $output .= 'public function '.$constructor_method_name.'() {'.$endl;
-            $output .= '    $parent_methods = get_class_methods(get_parent_class($this));'.$endl;
-            $output .= '    $method_signature = $this-&gt;'.$this-&gt;class_signature.'_findSignature(\'__construct\', $this-&gt;mock-&gt;constructor_args);'.$endl;
-            $output .= '    $default_signature = $this-&gt;'.$this-&gt;class_signature.'_findSignature(\'__construct\', array());'.$endl;
-            $output .= '    if ($method_signature != $default_signature) {'.$endl;
-            $output .= '        $this-&gt;'.$this-&gt;class_signature.'_tallyMethod($default_signature, FALSE);'.$endl;
-            $output .= '    }'.$endl;
-            $output .= '    if ($method_signature != NULL) {'.$endl;
-            $output .= '        $this-&gt;'.$this-&gt;class_signature.'_tallyMethod($method_signature);'.$endl;
-            $output .= '    }'.$endl;
-            $output .= '    if (is_array($parent_methods) &amp;&amp; in_array(\'__construct\', $parent_methods)) {'.$endl;
-            $output .= '        return call_user_func_array(array($this, \'parent::__construct\'), $this-&gt;mock-&gt;constructor_args);'.$endl;
-            $output .= '    }'.$endl;
+            $output .= '    $mock = '.$get_mock.'();'.$endl;
+            $output .= '    return $mock-&gt;invokeMethod(\'__construct\', $mock-&gt;constructor_args);'.$endl;
             $output .= '}'.$endl;
         }
         
         // add the handler for all methods
         $output .= $this-&gt;buildInvokeMethod($this-&gt;class_signature, FALSE);
         
-        // finds the signature for a method name and params
-        $output .= $this-&gt;buildFindSignature($this-&gt;class_signature, FALSE);
-        
-        // tally method for counting
-        $output .= $this-&gt;buildTallyMethod($this-&gt;class_signature, FALSE);
-        
         // build the getmock methods
         $output .= $this-&gt;buildGetMock($this-&gt;class_signature, FALSE);
         
@@ -414,15 +362,15 @@ class Snap_MockObject {
             $output .= '}'.$endl;
             
             $output .= $this-&gt;buildInvokeMethod($this-&gt;class_signature, TRUE);
-            $output .= $this-&gt;buildFindSignature($this-&gt;class_signature, TRUE);
-            $output .= $this-&gt;buildTallyMethod($this-&gt;class_signature, TRUE);
             $output .= $this-&gt;buildGetMock($this-&gt;class_signature, TRUE);
         }
         
         // ending } for class
         $output .= '}'.$endl;
         
-        // echo $output;
+        // if (defined('LOCALDEBUG')) {
+        //     echo $output;
+        // }
         // echo &quot;\n\n----------\n\n&quot;;
         //var_dump($this-&gt;methods);
         //echo &quot;\n\n----------\n\n&quot;;
@@ -435,257 +383,204 @@ class Snap_MockObject {
         return $this-&gt;buildClassInstantiation($mock_class, $setmock_method_name, $constructor_method_name);
     }
     
-    protected function generateClassName() {
-        $keys = array_keys($this-&gt;methods);
-        sort($keys);
-        $this-&gt;class_signature = 'c'.md5(strtolower(serialize($keys)));
+    /**
+     * invokes a method on the mock object, tallying and intercepting for return values
+     * this method is called usually from the mock object itself, asking the mock
+     * that created it to provide the return value for the method invocation
+     * @param string $method_name the name of the method to invoke
+     * @param array $method_params the parameters to pass to the method
+     * @return mixed
+     **/
+    public function invokeMethod($method_name, $method_params) {
+        // get all matching signatures
+        $sigs = $this-&gt;mockFindSignatures($method_name, $method_params);
+        $sigs_default = $this-&gt;mockFindDefaultSignature($method_name);
+        
+        // tally all methods
+        foreach ($sigs as $sig) {
+            $this-&gt;mockTallyMethod($sig);
+        }
+        $this-&gt;mockTallyMethod($sigs_default);
+        
+        // we've got a lot of possible sigs, do any of them have return values @ call count?
+        $returns_at_call_count = array();
+        $returns_at_default = array();
+        foreach ($sigs as $sig) {
+            if (isset($this-&gt;methods[$sig]['returns'][$this-&gt;mockGetTallyCount($sig)])) {
+                $returns_at_call_count[] = $sig;
+            }
+            if (isset($this-&gt;methods[$sig]['returns']['default'])) {
+                $returns_at_default[] = $sig;
+            }
+        }
         
-        $mock_class = 'mock_'.$this-&gt;mocked_class.'_'.$this-&gt;class_signature;
+        // &gt; 1 return is an exception
+        if (count($returns_at_call_count) &gt; 1) {
+            // error here
+            throw new Snap_UnitTestException('setup_ambiguous_return', $this-&gt;mocked_class.'::'.$method_name.' has ambiguous return values.');
+        }
         
-        // add suffixes if there is inheritance / interface
-        if ($this-&gt;isInherited()) {
-            $mock_class .= '_ri';
+        // exactly one, that's our match
+        if (count($returns_at_call_count) == 1) {
+            return $returns_at_call_count[0];
         }
-        if (count($this-&gt;getInterfaces()) &gt; 0) {
-            $mock_class .= '_if';
+        
+        // &gt; 1 defaults is an exception
+        if (count($returns_at_default) &gt; 1) {
+            // error here
+            throw new Snap_UnitTestException('setup_ambiguous_return', $this-&gt;mocked_class.'::'.$method_name.' has ambiguous default return values.');
         }
         
-        // add iterations until we get a unique name for mock_class
-        $mock_class_test = $mock_class;
-        $class_counter = 1;
-        while (class_exists($mock_class_test)) {
-            $mock_class_test = $mock_class . '_' . $class_counter;
-            $class_counter++;
+        // exactly one is a match
+        if (count($returns_at_default) == 1) {
+            return $returns_at_default[0];
         }
         
-        return $mock_class_test;
-    }
-    
-    protected function locateAllMethods($class_list) {
-        $methods = array();
-
-        foreach ($class_list as $class_name) {
-            // reflect the class
-            $reflected_class = new ReflectionClass($class_name);
-            foreach ($reflected_class-&gt;getMethods() as $method) {
-                if ($method-&gt;isConstructor() || strtolower($method-&gt;getName()) == '__construct') {
-                    // special constructor stuff here
-                    $methods[$method-&gt;getName()] = array(
-                        'class' =&gt; $class_name,
-                        'scope' =&gt; 'public',
-                    );
-                    $this-&gt;requiresConstructor();
-                    continue;
-                }
-
-                // __call magic method
-                if (strtolower($method-&gt;getName()) == '__call') {
-                    $this-&gt;requiresMagicMethods();
-                }
-
-                // skip all other magic methods
-                if (strpos($method-&gt;getName(), '__') === 0) {
-                    continue;
-                }
-            
-                // skip all final methods
-                if ($method-&gt;isFinal() &amp;&amp; $this-&gt;isInherited()) {
-                    // cannot be overridden
-                    continue;
-                }
-            
-                // if static methods are required, add a flag
-                if ($method-&gt;isStatic()) {
-                    $this-&gt;requiresStaticMethods();
-                }
-            
-                if ($method-&gt;isPublic()) {
-                    $methods[$method-&gt;getName()] = array(
-                        'class' =&gt; $class_name,
-                        'scope' =&gt; 'public',
-                    );
-                }
-                if ($method-&gt;isProtected()) {
-                    $methods[$method-&gt;getName()] = array(
-                        'class' =&gt; $class_name,
-                        'scope' =&gt; 'protected',
-                    );
+        // no specialized returns. Check now, for a call count at the default
+        // if that exists, use it
+        if (isset($this-&gt;methods[$sigs_default]['returns'][$this-&gt;mockGetTallyCount($sigs_default)])) {
+            return $this-&gt;methods[$sigs_default]['returns'][$this-&gt;mockGetTallyCount($sigs_default)];
+        }
+        
+        // no call count default look for a really default
+        if (isset($this-&gt;methods[$sigs_default]['returns']['default'])) {
+            return $this-&gt;methods[$sigs_default]['returns']['default'];
+        }
+        
+        // no default. If it is inherited, fall to original
+        if ($this-&gt;isInherited()) {
+            $method_call = $this-&gt;class_signature.'_'.$method_name.'_original';
+            if ($this-&gt;hasStaticMethods()) {
+                if (method_exists(get_class($this-&gt;constructed_object), $method_call)) {
+                    return call_user_func_array(array(get_class($this-&gt;constructed_object), $method_call), $method_params);
                 }
-                if ($method-&gt;isPrivate()) {
-                    $methods[$method-&gt;getName()] = array(
-                        'class' =&gt; $class_name,
-                        'scope' =&gt; 'private',
-                    );
+            }
+            else {
+                if (method_exists($this-&gt;constructed_object, $method_call)) {
+                    return call_user_func_array(array($this-&gt;constructed_object, $method_call), $method_params);
                 }
             }
         }
-
-        return $methods;
+        
+        return NULL;
     }
     
     /**
-     * Builds and instantiates a named mock class
-     * In addition to instantiating the mock class, it injects the mock object
-     * and runs the constructor if required
-     * @return Object the mocked object, ready for use
-     * @param string $mock_class the mock class name
-     * @param string $setmock_method the method to call for setting the mock object
-     * @param string $constructor_method the constructor to call if required
-     **/
-    protected function buildClassInstantiation($mock_class, $setmock_method, $constructor_method) {
-        global $SNAP_MockObject;
-        $SNAP_MockObject = $this;
-        $setmock_method_static = $setmock_method . '_static';
+     * Record the method name, signature, and expectations
+     * @param string $method_name the name of the method to record a signature for
+     * @param string $method_signature the signature of the method
+     * @param array $method_params the array of expectations that make up this signature
+     * @return void
+     */
+    protected function logMethodSignature($method_name, $method_signature, $method_params) {
+        if (!isset($this-&gt;signatures[$method_name])) {
+            $this-&gt;signatures[$method_name] = array();
+        }
         
-        // make the arguments for the ready class
-        $ready_class = '';
-        if (count($this-&gt;constructor_args) &gt; 0) {
-            $arg_output = &quot;&quot;;
-            
-            foreach ($this-&gt;constructor_args as $idx =&gt; $arg) {
-                $arg_output .= '$this-&gt;constructor_args['.$idx.'],';
+        $this-&gt;methods[$method_signature]['count'] = 0;
+        $this-&gt;methods[$method_signature]['exec_count'] = 0;
+        
+        $this-&gt;signatures[$method_name][$method_signature] = array(
+            'params'    =&gt; $method_params,
+        );
+    }
+    
+    /**
+     * Check parameter list, and wrap parameter in a MockObject_Expectation class if necessary
+     * @access protected
+     * @param array $method_params the method arguments
+     * @return array the processed parameter list
+     */
+    protected function handleMethodParameters($method_params) {
+        foreach ($method_params as $idx =&gt; $param) {
+            if (is_object($param) &amp;&amp; ($param instanceof Snap_Expectation)) {
+                continue;
+            }
+        
+            if ((substr($param, 0, 1) == '/') &amp;&amp; (substr($param, -1, 1) == '/')) {
+                $method_params[$idx] = new Snap_Regex_Expectation($param);
             }
-            $arg_output = trim($arg_output, ',');
             
-            $ready_class = 'return new '.$mock_class.'('.$arg_output.');';
+            $method_params[$idx] = new Snap_Equals_Expectation($param);
         }
-        else {
-            $ready_class = 'return new '.$mock_class.'();';
+        return $method_params;
+    }
+    
+    protected function mockFindSignatures($method_name, $method_params = array()) {
+        if (!is_array($method_params)) {
+            $method_params = array();
         }
-
-        $ready_class = eval($ready_class);
         
-        // inject the mock class
-        $ready_class-&gt;$setmock_method($this);
+        if (!isset($this-&gt;signatures[$method_name]) || count($method_params) == 0) {
+            return array();
+        }
         
-        if ($this-&gt;hasStaticMethods()) {
-            call_user_func_array(array(get_class($ready_class), $setmock_method_static), array($this));
+        $sigs = array();
+        foreach ($this-&gt;signatures[$method_name] as $signature =&gt; $details) {
+            $params = $details['params'];
+            
+            if (count($params) == 0) {
+                // default, move on
+                continue;
+            }
+            
+            $param_match = TRUE;
+            foreach ($params as $idx =&gt; $param) {
+                // more params in sig than sent to us
+                if (!isset($method_params[$idx])) {
+                    $param_match = FALSE;
+                    break;
+                }
+                
+                // run a match, if it fails, it is a non match
+                if (!$param-&gt;match($method_params[$idx])) {
+                    $param_match = FALSE;
+                    break;
+                }
+            }
+            
+            // if we match, it's good
+            if ($param_match) {
+                $sigs[] = $signature;
+            }
         }
+        
+        return $sigs;
+    }
 
-        // call a real constructor if required
-        if ($this-&gt;isInherited() || $this-&gt;hasConstructor()) {
-            $ready_class-&gt;$constructor_method();        
+    protected function mockFindDefaultSignature($method_name) {
+        if (!isset($this-&gt;signatures[$method_name])) {
+            return NULL;
+        }
+        foreach ($this-&gt;signatures[$method_name] as $signature =&gt; $details) {
+            if (count($details['params']) == 0) {
+                return $signature;
+            }
         }
-        
-        // clean up that global
-        unset($SNAP_MockObject);
-        
-        // return the ready class
-        return $ready_class;
     }
     
-    protected function buildInvokeMethod($class_signature, $is_static) {
-        $endl = &quot;\n&quot;;
-        $output = '';
-        
-        $func_name = 'public '.(($is_static) ? 'static ' : '').'function '.$class_signature.'_invokeMethod'.(($is_static) ? '_static' : '');
-        $find_signature = (($is_static) ? 'self::'.$class_signature : '$this-&gt;'.$class_signature).'_findSignature'.(($is_static) ? '_static' : '');
-        $tally_method = (($is_static) ? 'self::'.$class_signature : '$this-&gt;'.$class_signature).'_tallyMethod'.(($is_static) ? '_static' : '');
-        $get_mock = (($is_static) ? 'self::'.$class_signature : '$this-&gt;'.$class_signature).'_getMock'.(($is_static) ? '_static' : '');
-        $call_parent = ($is_static) ? 'return call_user_func_array(array(\'self\', \''.$class_signature.'_\'.$method_name.\'_original\'), $method_params);'
-                                    : 'return call_user_func_array(array($this, \'parent::\'.$method_name), $method_params);';
-        
-        $output .= $func_name . '($method_name, $method_params) {'.$endl;
-        $output .= '    $method_signature = '.$find_signature.'($method_name, $method_params);'.$endl;
-        $output .= '    $default_signature = '.$find_signature.'($method_name, array());'.$endl;
-        $output .= '    $mock = '.$get_mock.'();'.$endl;
-        $output .= '    if ($method_signature != $default_signature) {'.$endl;
-        $output .= '        '.$tally_method.'($default_signature, FALSE);'.$endl;
-        $output .= '    }'.$endl;
-        $output .= '    // if we have a match, tally on it'.$endl;
-        $output .= '    if ($method_signature != NULL) {'.$endl;
-        $output .= '        $call_count = '.$tally_method.'($method_signature);'.$endl;
-        $output .= '        // if we have a return value, return that'.$endl;
-        $output .= '        if (isset($mock-&gt;methods[$method_signature][\'returns\'][$call_count])) {'.$endl;
-        $output .= '            return $mock-&gt;methods[$method_signature][\'returns\'][$call_count];'.$endl;
-        $output .= '        }'.$endl;
-        $output .= '        if (isset($mock-&gt;methods[$method_signature][\'returns\'][\'default\'])) {'.$endl;
-        $output .= '            return $mock-&gt;methods[$method_signature][\'returns\'][\'default\'];'.$endl;
-        $output .= '        }'.$endl;
-        $output .= '    }'.$endl;
-        $output .= '    // if we have a return value for the default signature, return that (option 2)'.$endl;
-        $output .= '    if (isset($mock-&gt;methods[$default_signature][\'returns\'][$call_count])) {'.$endl;
-        $output .= '        return $mock-&gt;methods[$default_signature][\'returns\'][$call_count];'.$endl;
-        $output .= '    }'.$endl;
-        $output .= '    if (isset($mock-&gt;methods[$default_signature][\'returns\'][\'default\'])) {'.$endl;
-        $output .= '        return $mock-&gt;methods[$default_signature][\'returns\'][\'default\'];'.$endl;
-        $output .= '    }'.$endl;
-        $output .= '    // if this is an inherited method, return parent method call'.$endl;
-        $output .= '    if ($mock-&gt;isInherited()) {'.$endl;
-        $output .= '        '.$call_parent.$endl;
-        $output .= '    }'.$endl;
-        $output .= '}'.$endl;
-        return $output;
+    protected function mockTallyMethod($method_signature) {
+        if (!isset($this-&gt;methods[$method_signature]['count'])) {
+            $this-&gt;methods[$method_signature]['count'] = 0;
+        }
+        $this-&gt;methods[$method_signature]['count']++;
     }
     
-    protected function buildFindSignature($class_signature, $is_static) {
-        $endl = &quot;\n&quot;;
-        $output = '';
-        
-        $func_name = 'public '.(($is_static) ? 'static ' : '').'function '.$class_signature.'_findSignature'.(($is_static) ? '_static' : '');
-        $get_mock = (($is_static) ? 'self::'.$class_signature : '$this-&gt;'.$class_signature).'_getMock'.(($is_static) ? '_static' : '');
-        
-        $output .= $func_name.'($method_name, $method_params = array()) {'.$endl;
-        $output .= '    $mock = '.$get_mock.'();'.$endl;
-        $output .= '    if (!is_array($method_params)) {'.$endl;
-        $output .= '        $method_params = array();'.$endl;
-        $output .= '    }'.$endl;
-        $output .= '    if (!isset($mock-&gt;signatures[$method_name])) {'.$endl;
-        $output .= '        $mock-&gt;signatures[$method_name] = array();'.$endl;
-        $output .= '    }'.$endl;
-        $output .= '    $method_signature = NULL;'.$endl;
-        $output .= '    foreach ($mock-&gt;signatures[$method_name] as $signature =&gt; $details) {'.$endl;
-        $output .= '        $signature_params = $details[\'params\'];'.$endl;
-        $output .= '        // default params'.$endl;
-        $output .= '        if (count($signature_params) == 0) {'.$endl;
-        $output .= '            $default_method_signature = $signature;'.$endl;
-        $output .= '            continue;'.$endl;
-        $output .= '        }'.$endl;
-        $output .= '        // non default, if all params match, use it'.$endl;
-        $output .= '        $param_match = TRUE;'.$endl;
-        $output .= '        foreach ($signature_params as $idx=&gt;$param) {'.$endl;
-        $output .= '            // method param does not exist, just exit'.$endl;
-        $output .= '            if (!isset($method_params[$idx])) {'.$endl;
-        $output .= '                $param_match = FALSE;'.$endl;
-        $output .= '                break;'.$endl;
-        $output .= '            }'.$endl;
-        $output .= '            // do match. On no matches, fail entire list'.$endl;
-        $output .= '            if (!$param-&gt;match($method_params[$idx])) {'.$endl;
-        $output .= '                $param_match = FALSE;'.$endl;
-        $output .= '                break;'.$endl;
-        $output .= '            }'.$endl;
-        $output .= '        }'.$endl;
-        $output .= '        // if we match'.$endl;
-        $output .= '        if ($param_match) {'.$endl;
-        $output .= '            $method_signature = $signature;'.$endl;
-        $output .= '        }'.$endl;
-        $output .= '    }'.$endl;
-        $output .= '    // if there was a default, but no method match, use the default'.$endl;
-        $output .= '    if (isset($default_method_signature) &amp;&amp; !isset($method_signature)) {'.$endl;
-        $output .= '        $method_signature = $default_method_signature;'.$endl;
-        $output .= '    }'.$endl;
-        $output .= '    return $method_signature;'.$endl;
-        $output .= '}'.$endl;
-        
-        return $output;
+    protected function mockGetTallyCount($method_signature) {
+        return $this-&gt;methods[$method_signature]['count'];
     }
     
-    protected function buildTallyMethod($class_signature, $is_static) {
+    protected function buildInvokeMethod($class_signature, $is_static) {
         $endl = &quot;\n&quot;;
         $output = '';
         
-        $func_name = 'public '.(($is_static) ? 'static ' : '').'function '.$class_signature.'_tallyMethod'.(($is_static) ? '_static' : '');
+        $func_name = 'public '.(($is_static) ? 'static ' : '').'function '.$class_signature.'_invokeMethod'.(($is_static) ? '_static' : '');
         $get_mock = (($is_static) ? 'self::'.$class_signature : '$this-&gt;'.$class_signature).'_getMock'.(($is_static) ? '_static' : '');
         
-        $output .= $func_name.'($method_signature, $is_execute = TRUE) {'.$endl;
+        $output .= $func_name . '($method_name, $method_params) {'.$endl;
         $output .= '    $mock = '.$get_mock.'();'.$endl;
-        $output .= '    $mock-&gt;methods[$method_signature][\'count\']++;'.$endl;
-        $output .= '    if ($is_execute) {'.$endl;
-        $output .= '        $mock-&gt;methods[$method_signature][\'exec_count\']++;'.$endl;
-        $output .= '    }';
-        $output .= '    return $mock-&gt;methods[$method_signature][\'exec_count\'];'.$endl;
+        $output .= '    return $mock-&gt;invokeMethod($method_name, $method_params);'.$endl;
         $output .= '}'.$endl;
-        
         return $output;
     }
     
@@ -748,7 +643,7 @@ class Snap_MockObject {
         // if this is static, AND we need the original methods, copy them
         // please replace with late static bindings once PHP 5.3 becomes
         // a baseline
-        if ($is_static &amp;&amp; $this-&gt;isInherited()) {
+        if ($this-&gt;isInherited()) {
             
             $contents = file($method-&gt;getFileName());
             $start_line = $method-&gt;getStartLine();
@@ -759,14 +654,25 @@ class Snap_MockObject {
             $matches = array();
             preg_match('/.*?function[\s]+'.$method_name.'.*?\{([\s\S]*)\}/i', $contents, $matches);
             
+            // no matches, this was an interface
+            if (!$matches) {
+                $matches = array('1' =&gt; '');
+            }
+            
             // map self:: and parent:: to proper things
             $replaces = array(
                 // self is implied, since it's in the new class, it resolves correctly
                 'parent::' =&gt; get_parent_class($this-&gt;mocked_class).'::',
             );
+            
             $contents = trim(str_replace(array_keys($replaces), array_values($replaces), $matches[1]));
             
-            $output .= 'public static function '.$this-&gt;class_signature.'_'.$method_name.'_original('.$param_string.') {'.$endl;
+            if ($is_static) {
+                $output .= 'public static function '.$this-&gt;class_signature.'_'.$method_name.'_original('.$param_string.') {'.$endl;
+            }
+            else {
+                $output .= 'public function '.$this-&gt;class_signature.'_'.$method_name.'_original('.$param_string.') {'.$endl;
+            }
             
             // add the original method's guts here
             $output .= $endl.$contents.$endl;
@@ -789,7 +695,147 @@ class Snap_MockObject {
         $output .= '}'.$endl;
         return $output;
     }
+    
+    protected function generateClassName() {
+        $keys = array_keys($this-&gt;methods);
+        sort($keys);
+        $this-&gt;class_signature = 'c'.md5(strtolower(serialize($keys)));
+        
+        $mock_class = 'mock_'.$this-&gt;mocked_class.'_'.$this-&gt;class_signature;
+        
+        // add suffixes if there is inheritance / interface
+        if ($this-&gt;isInherited()) {
+            $mock_class .= '_ri';
+        }
+        if (count($this-&gt;getInterfaces()) &gt; 0) {
+            $mock_class .= '_if';
+        }
+        
+        // add iterations until we get a unique name for mock_class
+        $mock_class_test = $mock_class;
+        $class_counter = 1;
+        while (class_exists($mock_class_test)) {
+            $mock_class_test = $mock_class . '_' . $class_counter;
+            $class_counter++;
+        }
+        
+        return $mock_class_test;
+    }
+    
+    protected function locateAllMethods($class_list) {
+        $methods = array();
+
+        foreach ($class_list as $class_name) {
+            // reflect the class
+            $reflected_class = new ReflectionClass($class_name);
+            foreach ($reflected_class-&gt;getMethods() as $method) {
+                if ($method-&gt;isConstructor() || strtolower($method-&gt;getName()) == '__construct') {
+                    // special constructor stuff here
+                    $methods[$method-&gt;getName()] = array(
+                        'class' =&gt; $class_name,
+                        'scope' =&gt; 'public',
+                    );
+                    $this-&gt;requiresConstructor();
+                    continue;
+                }
+
+                // __call magic method
+                if (strtolower($method-&gt;getName()) == '__call') {
+                    $this-&gt;requiresMagicMethods();
+                }
+
+                // skip all other magic methods
+                if (strpos($method-&gt;getName(), '__') === 0) {
+                    continue;
+                }
+            
+                // skip all final methods
+                if ($method-&gt;isFinal() &amp;&amp; $this-&gt;isInherited()) {
+                    // cannot be overridden
+                    continue;
+                }
+            
+                // if static methods are required, add a flag
+                if ($method-&gt;isStatic()) {
+                    $this-&gt;requiresStaticMethods();
+                }
+            
+                if ($method-&gt;isPublic()) {
+                    $methods[$method-&gt;getName()] = array(
+                        'class' =&gt; $class_name,
+                        'scope' =&gt; 'public',
+                    );
+                }
+                if ($method-&gt;isProtected()) {
+                    $methods[$method-&gt;getName()] = array(
+                        'class' =&gt; $class_name,
+                        'scope' =&gt; 'protected',
+                    );
+                }
+                if ($method-&gt;isPrivate()) {
+                    $methods[$method-&gt;getName()] = array(
+                        'class' =&gt; $class_name,
+                        'scope' =&gt; 'private',
+                    );
+                }
+            }
+        }
+
+        return $methods;
+    }
+    
+    /**
+     * Builds and instantiates a named mock class
+     * In addition to instantiating the mock class, it injects the mock object
+     * and runs the constructor if required
+     * @return Object the mocked object, ready for use
+     * @param string $mock_class the mock class name
+     * @param string $setmock_method the method to call for setting the mock object
+     * @param string $constructor_method the constructor to call if required
+     **/
+    protected function buildClassInstantiation($mock_class, $setmock_method, $constructor_method) {
+        global $SNAP_MockObject;
+        $SNAP_MockObject = $this;
+        $setmock_method_static = $setmock_method . '_static';
+        
+        // make the arguments for the ready class
+        $ready_class = '';
+        if (count($this-&gt;constructor_args) &gt; 0) {
+            $arg_output = &quot;&quot;;
+            
+            foreach ($this-&gt;constructor_args as $idx =&gt; $arg) {
+                $arg_output .= '$this-&gt;constructor_args['.$idx.'],';
+            }
+            $arg_output = trim($arg_output, ',');
+            
+            $ready_class = 'return new '.$mock_class.'('.$arg_output.');';
+        }
+        else {
+            $ready_class = 'return new '.$mock_class.'();';
+        }
 
+        $ready_class = eval($ready_class);
+        
+        // inject the mock class
+        $ready_class-&gt;$setmock_method($this);
+        
+        if ($this-&gt;hasStaticMethods()) {
+            call_user_func_array(array(get_class($ready_class), $setmock_method_static), array($this));
+        }
+        
+        $this-&gt;constructed_object = $ready_class;
+
+        // call a real constructor if required
+        if ($this-&gt;isInherited() || $this-&gt;hasConstructor()) {
+            $ready_class-&gt;$constructor_method();        
+        }
+        
+        // clean up that global
+        unset($SNAP_MockObject);
+        
+        // return the ready class
+        return $ready_class;
+    }
 }
 
 </diff>
      <filename>core/mock/mock.php</filename>
    </modified>
    <modified>
      <diff>@@ -35,7 +35,7 @@ class Snap_FileAnalyzer {
      * @param $data the data up to the point of failure
      **/
     public function onThreadFail($file, $data) {
-        $this-&gt;results[$file] = FALSE;
+        $this-&gt;results[$file] = trim($data);
     }
     
     /**</diff>
      <filename>core/util/analyzer/analyzer.php</filename>
    </modified>
    <modified>
      <diff>@@ -98,8 +98,8 @@ unset($analyzer);
 // build a master test key list
 $master_test_key_list = array();
 foreach ($master_test_list as $file =&gt; $classes) {
-    if ($classes == FALSE) {
-        die (&quot;File $file could not be read due to a fatal error.\n&quot;);
+    if (!is_array($classes)) {
+        die (&quot;File $file could not be read due to a fatal error:\n&quot;.$classes.&quot;\n&quot;);
     }
     foreach ($classes as $klass =&gt; $tests) {
         foreach ($tests as $test) {</diff>
      <filename>snaptest.php</filename>
    </modified>
    <modified>
      <diff>@@ -225,7 +225,7 @@ class Snap_MockObject_Test_MockGenerationWithStaticMethods extends Snap_UnitTest
     }
     
     public function testProtectedMethodCallsCopiedCorrectly() {
-        return $this-&gt;assertTrue(SNAP_calStatic($this-&gt;mocked_obj, 'getProtectedTrue'));
+        return $this-&gt;assertTrue(SNAP_callStatic($this-&gt;mocked_obj, 'getProtectedTrue'));
     }
 }
 
@@ -245,7 +245,7 @@ class Snap_MockObject_Test_MockGenerationWithStaticMethodsAndOverriding extends
     }
     
     public function testProtectedMethodCallsCopiedCorrectly() {
-        return $this-&gt;assertFalse(SNAP_calStatic($this-&gt;mocked_obj, 'getProtectedTrue'));
+        return $this-&gt;assertFalse(SNAP_callStatic($this-&gt;mocked_obj, 'getProtectedTrue'));
     }
 }
 
@@ -270,7 +270,7 @@ class Snap_MockObject_Test_MockGenerationWithStaticMethodsAndExtension extends S
     
     // Despite overriding getTrue, this is a call to parent::, so it should not be overriden
     public function testProtectedMethodCallsCopiedCorrectly() {
-        return $this-&gt;assertTrue(SNAP_calStatic($this-&gt;mocked_obj, 'getProtectedParentTrue'));
+        return $this-&gt;assertTrue(SNAP_callStatic($this-&gt;mocked_obj, 'getProtectedParentTrue'));
     }
 }
 </diff>
      <filename>tests/mock/mock.stest.php</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>feb7b71e379ee190af6c3aa7e4331beff28f842b</id>
    </parent>
  </parents>
  <author>
    <name>Jakob Heuser</name>
    <email>jakob@felocity.org</email>
  </author>
  <url>http://github.com/Jakobo/snaptest/commit/91a0c1d01d3cc5261e896adff84965e5d16291ef</url>
  <id>91a0c1d01d3cc5261e896adff84965e5d16291ef</id>
  <committed-date>2008-05-14T19:42:55-07:00</committed-date>
  <authored-date>2008-05-14T19:42:55-07:00</authored-date>
  <message>new mock object with less eval footprint, minor fixes. also addresses #15

Signed-off-by: Jakob Heuser &lt;jakob@felocity.org&gt;</message>
  <tree>99a3e6cb6401051432faab0cf389360f999b8191</tree>
  <committer>
    <name>Jakob Heuser</name>
    <email>jakob@felocity.org</email>
  </committer>
</commit>
