/** * Create a mock object of the given class. * * Return null if users decide not to mock this object. * * @param $className * @param array $arguments * * @return null|object */ public function createMockInstance($className, array $arguments) { // Make sure to update the index if the caller hierarchy changes. // #1 Box\TestScribe\Mock\InjectedMockMgr->createMockInstance() // #2 Box\TestScribe\App::createMockedInstance() // #3 Box\TestScribe\_fixture\ServiceLocator::resolve_internal() // #4 Box\TestScribe\_fixture\ServiceLocator::resolve() // #5 Box\TestScribe\_fixture\_input\CalculatorViaLocator->calculateWithACalculator() $isTheCallFromTheClassBeingTested = $this->callOriginatorChecker->isCallFromTheClassBeingTested(5); if (!$isTheCallFromTheClassBeingTested) { return null; } if (array_key_exists($className, $this->injectedMockedObjects)) { // @TODO (ryang 1/27/15) : in Box webapp the diesel system will return // the same mock object if Diesel::Foo is called multiple times in // the same test and a mock for Foo is registered. // research if this behavior should be assumed for all // service locator systems. $msg = "Instantiating class ( {$className} ) which was mocked." . " Return the same mock object."; $this->output->writeln($msg); /** * @var MockClass $mockClass */ $mockClass = $this->injectedMockedObjects[$className]; return $mockClass->getMockedDynamicClassObj(); } $mockClass = $this->fullMockObjectFactory->createMockObject($className); $this->injectedMockedObjects[$className] = $mockClass; $mockedDynamicClassObj = $mockClass->getMockedDynamicClassObj(); return $mockedDynamicClassObj; }
/** * @param string $str a PHP variable definition string with PHP syntax. * * @return \Box\TestScribe\Input\ExpressionWithMocks */ public function process($str) { // Make sure to reset this member variable // because this class is a singleton. // @TODO (ryang 12/31/14) : investigate why using a local variable // and closure doesn't work. $this->mocks = []; $callback = function ($matches) { $className = $matches[0]; $mockClass = $this->fullMockObjectFactory->createMockObject($className); $replacementStr = "\$" . $mockClass->getMockObjectName(); $this->mocks[] = $mockClass; return $replacementStr; }; // Need to escape '\' multiple times to make regex work. // The first \ is to escape PHP string '\' to allow it to be passed to regex engine. // preg_quote doesn't work since it escapes ^ incorrectly. // Test if the input is a string by testing if it starts with // a ' or " character. $isString = preg_match('#^\\s*[\'"]#', $str); if ($isString === 1) { $rc = new ExpressionWithMocks($str, []); return $rc; } // Match an identifier that starts with a '\' character // followed by letters or digits or '\' // and check if it is not part of a string // by looking ahead to see if it sees a ' or " character // or encounters a ',' character first. // e.g. [\Foo, "a"] should detect \Foo // e.g. ["\Foo"] should not detect \Foo // e.g. ["a\"b"] should not detect \" $regExpressionPattern = '#\\\\[a-zA-Z0-9_\\\\]+(?![^,]*[\'"])#'; $replacedStr = preg_replace_callback($regExpressionPattern, $callback, $str); if ($replacedStr === null) { throw new \RuntimeException("Failed to replace class name references in the input string."); } $rc = new ExpressionWithMocks($replacedStr, $this->mocks); return $rc; }