/**
  * Creates a mock from the target class
  *
  * @param string $class
  * @param array $args
  * @param array $spec
  *
  * @return \PHPUnit_Framework_MockObject_MockObject
  */
 private function _setupTarget_setupMock($class, $args, $spec)
 {
     /*
      * $spec = ['method', 'method', ...]
      * $spec = [
      *      'method' => int,
      *      'method' => [ 'count' => int, 'with' => mixed, 'return' => mixed ]
      * ],
      *
      */
     if (is_string($spec)) {
         $mock = $this->{$spec}();
     } else {
         $call = function ($spec) {
             $cb = [$this, $spec[0]];
             $args = isset($spec[1]) ? (array) $spec[1] : false;
             if ($args) {
                 return call_user_func_array($cb, $args);
             }
             return $this->{$cb}();
         };
         $methods = [];
         $methodMocks = [];
         foreach ($spec as $method => $methodSpec) {
             if (is_int($method)) {
                 $methods[] = $methodSpec;
                 continue;
             }
             if (is_string($methodSpec)) {
                 $methodSpec = $this->{$methodSpec}();
             }
             $methods[] = $method;
             $methodMocks[$method] = ['expects' => isset($methodSpec['count']) ? $this->exactly($methodSpec['count']) : $this->any(), 'with' => isset($methodSpec['@with']) ? $call($methodSpec['@with']) : (isset($methodSpec['with']) ? $methodSpec['with'] : null), 'return' => isset($methodSpec['@return']) ? $call($methodSpec['@return']) : (isset($methodSpec['return']) ? '__self__' == $methodSpec['return'] ? $this->returnSelf() : $this->returnValue($methodSpec['return']) : null)];
         }
         $mockBuilder = $this->getMockBuilder($class)->setMethods($methods);
         if (false === $args) {
             $mockBuilder->disableOriginalConstructor();
         } else {
             $mockBuilder->setConstructorArgs(InstanceCreator::mapArray($args));
         }
         $mock = $mockBuilder->getMock();
         foreach ($methodMocks as $method => $mockSpec) {
             $methodMock = $mock->expects($mockSpec['expects'])->method($method);
             if ($mockSpec['with']) {
                 $methodMock->with($mockSpec['with']);
             }
             if ($mockSpec['return']) {
                 $methodMock->will($mockSpec['return']);
             }
         }
     }
     return $mock;
 }
 /**
  * @testdox      Allows setting and/or getting object property values.
  * @dataProvider propertiesProvider
  */
 public function testSetterAndGetter($name, $spec)
 {
     $errTmpl = __METHOD__ . ': ' . get_class($this);
     if (!property_exists($this, 'target') || !is_object($this->target) && !isset($spec['target'])) {
         throw new \PHPUnit_Framework_Exception($errTmpl . ' must define the property "target" and the value must be an object.');
     }
     if (!is_array($spec)) {
         $spec = ['value' => $spec];
     }
     if (isset($spec['@value'])) {
         $spec['value'] = InstanceCreator::fromSpec($spec['@value'], InstanceCreator::FORCE_INSTANTIATION);
     }
     /* Value could be 'null', so we need to use array_key_exists here. */
     if (!array_key_exists('value', $spec)) {
         if (!array_key_exists('default', $spec)) {
             throw new \PHPUnit_Framework_Exception($errTmpl . ': Specification must contain the key "value" or "default".');
         }
         $spec['value'] = null;
         $spec['ignore_getter'] = true;
         $spec['ignore_setter'] = true;
     }
     if (isset($spec['target'])) {
         $this->target = is_object($spec['target']) ? $spec['target'] : InstanceCreator::fromSpec($spec['target'], InstanceCreator::FORCE_INSTANTIATION);
     }
     if (isset($spec['@default'])) {
         $spec['default'] = InstanceCreator::fromSpec($spec['@default'], InstanceCreator::FORCE_INSTANTIATION);
     } else {
         if (isset($spec['default@'])) {
             $spec['default'] = '@' . $spec['default@'];
         }
     }
     if (is_string($spec['value']) && 0 === strpos($spec['value'], '@')) {
         $spec['value'] = InstanceCreator::newClass($spec['value']);
     }
     $this->_setterGetter_triggerHook('pre', $spec);
     $getterMethod = isset($spec['getter_method']) ? str_replace('*', $name, $spec['getter_method']) : "get{$name}";
     $setterMethod = isset($spec['setter_method']) ? str_replace('*', $name, $spec['setter_method']) : "set{$name}";
     $getterArgs = isset($spec['getter_args']) ? $spec['getter_args'] : false;
     $setterArgs = isset($spec['setter_args']) ? $spec['setter_args'] : false;
     if (isset($spec['setter_exception'])) {
         $this->_setterGetter_assertSetterGetterException($setterMethod, $spec['setter_exception'], $spec['value'], $setterArgs);
         return;
     }
     if (isset($spec['default'])) {
         $defaultGetterArgs = isset($spec['default_args']) ? $spec['default_args'] : $getterArgs;
         $assert = isset($spec['default_assert']) ? $spec['default_assert'] : null;
         $this->_setterGetter_assertGetterValue($getterMethod, $spec['default'], $defaultGetterArgs, $assert, true);
     }
     if (!isset($spec['ignore_setter']) || !$spec['ignore_setter']) {
         $assert = isset($spec['setter_assert']) ? $spec['setter_assert'] : null;
         $this->_setterGetter_assertSetterValue($setterMethod, $spec['value'], $setterArgs, $assert, array_key_exists('setter_value', $spec) ? $spec['setter_value'] : '__FLUENT_INTERFACE__');
     }
     if (isset($spec['getter_exception'])) {
         $this->_setterGetter_assertSetterGetterException($getterMethod, $spec['getter_exception'], '__GETTER_EXCEPTION__', $getterArgs);
         return;
     }
     if (isset($spec['expect_property'])) {
         $assert = isset($spec['property_assert']) ? $spec['property_assert'] : null;
         $this->_setterGetter_assertPropertyValue($name, $spec['expect_property'], $assert);
     } else {
         if (!isset($spec['ignore_getter']) || !$spec['ignore_getter']) {
             $assert = isset($spec['getter_assert']) ? $spec['getter_assert'] : null;
             $this->_setterGetter_assertGetterValue($getterMethod, isset($spec['expect']) ? $spec['expect'] : $spec['value'], $getterArgs, $assert);
         }
     }
     $this->_setterGetter_triggerHook('post', $spec);
 }