/** * Return the specsPerMethod for the given method. * * If the method key doesn't exist, an empty spec set * will be returned. * * @param $methodName * * @return \Box\TestScribe\Spec\SpecsPerMethod */ public function getSpecsPerMethodByName($methodName) { $default = new SpecsPerMethod($methodName, []); /** @var SpecsPerMethod $specsPerMethod */ $specsPerMethod = ArrayUtil::lookupValueByKey($methodName, $this->specs, $default); return $specsPerMethod; }
/** * @param \Box\TestScribe\Mock\MockClass $mockClass * @param string $injectMethodName * * @return string */ public function genInjectedMockStatement(MockClass $mockClass, $injectMethodName) { $createMockObjectStatement = $this->mockRenderer->renderAMock($mockClass); $injectStatement = $this->genInjectionStatement($mockClass, $injectMethodName); // @TODO (ryang 8/6/14) : better handling of indentations. $combinedStatements = ArrayUtil::joinNonEmptyStringsWithNewLine([$createMockObjectStatement, $injectStatement], 1); return $combinedStatements; }
/** * Generate the test method as a string. * * @param \Box\TestScribe\Execution\ExecutionResult $executionResult * * @return string */ public function renderMethodBody(ExecutionResult $executionResult) { $objectInjectionStatements = $this->injectedMocksRenderer->renderObjectInjectionStatements(); $exceptionExpectationStatements = $this->exceptionRenderer->genExceptionExpectation($executionResult); $methodInvocationStatements = $this->invocationRenderer->renderMethodInvocation($executionResult); // @TODO (ryang 6/3/15) : move exception expectation statement after all the mocks statements. $methodBody = ArrayUtil::joinNonEmptyStringsWithNewLine([$objectInjectionStatements, $exceptionExpectationStatements, $methodInvocationStatements], 2); return $methodBody; }
/** * Generate statements for setting up the mocks of the objects * injected by the dependency management system. * * @return string */ public function renderObjectInjectionStatements() { $objectInjectionStatements = $this->injectedMockObjectsRenderer->genMockedObjectStatements(); $mockClassInjectionStatements = $this->injectedMockClassesRenderer->genMockedClassesStatements(); $combinedStatements = ArrayUtil::joinNonEmptyStringsWithNewLine([$objectInjectionStatements, $mockClassInjectionStatements], 2); $comment = "// Setup mocks injected by the dependency management system.\n\n"; $result = Util::appendStringIfNotEmpty($comment, $combinedStatements); return $result; }
/** * Return the last used raw input string for the item. * * @param string $sectionName * either method name of the class under test * or dependent class name * * @param string $itemName * either parameter name * or dependent class's method name * * @return string */ public function getInputStringFromHistory($sectionName, $itemName) { $inputString = ''; $sectionArray = ArrayUtil::lookupValueByKey($sectionName, $this->data, null); if ($sectionArray !== null) { $inputString = ArrayUtil::lookupValueByKey($itemName, $sectionArray, ''); } return $inputString; }
/** * Return the statements that sets the expectations and * return values of the method invocation of the mocked * object. * * @param MockClass $mock * * @return string */ public function renderMethodExpectations(MockClass $mock) { $mockedExpectationsArray = []; foreach ($mock->getMethodInvocations() as $invocation) { list($methodObj, $arguments, $value) = $invocation; $mockedOneExpectation = $this->mockMethodExpectationRenderer->renderOneMethodExpectation($methodObj, $arguments, $value); $mockedExpectationsArray[] = $mockedOneExpectation; } $mockedExpectations = ArrayUtil::joinNonEmptyStringsWithNewLine($mockedExpectationsArray, 2); return $mockedExpectations; }
/** * Generate all injection statements for either mock classes or mock objects. * * @param array $mocks * class name string => MockClass * @param string $injectMethodName * * @return string */ public function genInjectionStatements($mocks, $injectMethodName) { $statementArray = []; /* @var $mock \Box\TestScribe\Mock\MockClass */ foreach ($mocks as $mock) { $statement = $this->oneInjectedMockRenderer->genInjectedMockStatement($mock, $injectMethodName); $statementArray[] = $statement; } $combinedStatements = ArrayUtil::joinNonEmptyStringsWithNewLine($statementArray, 2); return $combinedStatements; }
/** * Return statements for invoking the test and verifying the result. * * @param \Box\TestScribe\Execution\ExecutionResult $executionResult * * @param string $targetObjectName * * @return string */ public function genExecutionAndVerification(ExecutionResult $executionResult, $targetObjectName) { $exception = $executionResult->getException(); $isReturnTypeVoid = $this->globalComputedConfig->isReturnTypeVoid(); $shouldVerifyResult = $exception === null && !$isReturnTypeVoid; $methodArguments = $executionResult->getMethodArguments(); $argumentsString = $this->argumentsRenderer->renderArgumentsAsStringInCode($methodArguments); $executionStatements = $this->executionRenderer->genExecutionStatements($shouldVerifyResult, $argumentsString, $targetObjectName); $resultValidationStatements = $this->resultValidationRenderer->genResultValidation($shouldVerifyResult, $executionResult); $result = ArrayUtil::joinNonEmptyStringsWithNewLine([$executionStatements, $resultValidationStatements], 2); return $result; }
/** * Generate the argument list as a string and * its referenced mock statements. * * @param \Box\TestScribe\ArgumentInfo\Arguments $argsObj * * @return \Box\TestScribe\Renderers\ArgumentsRenderResult */ public function renderArguments(Arguments $argsObj) { $expressions = $argsObj->getExpressions(); $argumentsString = implode(', ', $expressions); $mocks = $argsObj->getMocks(); $mockObjectStatementArray = []; foreach ($mocks as $mock) { $mockObjectStatement = $this->mockRenderer->renderAMock($mock); $mockObjectStatementArray[] = $mockObjectStatement; } $mockObjectStatementsString = ArrayUtil::joinNonEmptyStringsWithNewLine($mockObjectStatementArray, 2); $result = new ArgumentsRenderResult($argumentsString, $mockObjectStatementsString); return $result; }
/** * @param array $data * * @return \Box\TestScribe\Spec\OneSpec */ public function loadOneSpec($data) { $testName = $data[self::TEST_NAME]; $methodParameters = $data[self::METHOD_PARAM]; $result = $data[self::RESULT_KEY]; $mocksData = ArrayUtil::lookupValueByKey(self::MOCK, $data, []); $mockSpecs = []; foreach ($mocksData as $oneMockData) { $oneMockSpec = $this->mockSpecPersistence->loadMockSpec($oneMockData); $mockSpecs[] = $oneMockSpec; } $constructorParameters = ArrayUtil::lookupValueByKey(self::CONSTRUCTOR_PARAM, $data, []); $oneSpec = new OneSpec($testName, $result, $constructorParameters, $methodParameters, $mockSpecs); return $oneSpec; }
/** * Generate assertions of an object. * * @param string $variableName name without '$' prefix * @param \object $value * * @return string */ public function generateForAnObject($variableName, $value) { $objectTypeString = get_class($value); $isMockObject = $this->mockClassUtil->isMockClass($objectTypeString); $typeCheckStatement = $this->renderObjectTypeAssertion($isMockObject, $variableName, $value); if ($isMockObject) { // Calling methods on mocked object at the rendering phase can // confuse users where the call comes from. // Don't call json_encode() method here. // @TODO (ryang 12/19/14) : re-evaluate when we start supporting non shmock based mocking // frameworks $valueCheckStatement = ''; } else { $valueCheckStatement = $this->renderObjectValueAssertion($variableName, $value); } $statements = ArrayUtil::joinNonEmptyStringsWithNewLine([$typeCheckStatement, $valueCheckStatement], 2); return $statements; }
/** * @param \Symfony\Component\Console\Input\InputInterface $input * @param string $inSourceFile * * @return \Box\TestScribe\Config\Options */ public function getOptions(InputInterface $input, $inSourceFile) { $configFilePath = $this->configHelper->getConfigFilePath($input); $generateSpec = false; $testBaseClassName = self::DEFAULT_TEST_BASE_CLASS_NAME; if ($configFilePath) { $data = $this->yamlUtil->loadYamlFile($configFilePath); $generateSpec = ArrayUtil::lookupBoolValue(self::GENERATE_SPEC_KEY, $data, false); $testBaseClassName = ArrayUtil::lookupStringValue(self::TEST_BASE_CLASS_NAME_KEY, $data, self::DEFAULT_TEST_BASE_CLASS_NAME); } $overwriteExistingDestinationFile = $input->getOption(CmdOption::OVERWRITE_EXISTING_DESTINATION_FILE_OPTION); $testFileRoot = $this->configHelper->getTestRootPath($input); $sourceFileRoot = $this->configHelper->getSourceFileRoot($input, $testFileRoot, $inSourceFile); $sourceFilePathRelativeToSourceRoot = $this->configHelper->getSourceFilePathRelativeToSourceRoot($sourceFileRoot, $inSourceFile); $outSourceFileDir = PathUtil::getPathUnderRoot($testFileRoot, $sourceFilePathRelativeToSourceRoot); $inputOptions = new Options($overwriteExistingDestinationFile, $testFileRoot, $sourceFileRoot, $outSourceFileDir, $sourceFilePathRelativeToSourceRoot, $generateSpec, $testBaseClassName); return $inputOptions; }
/** * @param int $distanceFromThisCall * e.g. * bar calls foo, foo calls this method * To get information about foo, specify 1. * To get information about bar, specify 2. * * @return \Box\TestScribe\Utils\CallInfo * @throws \Box\TestScribe\Exception\TestScribeException */ public function getCallerInfoAt($distanceFromThisCall) { // This call frame and // $this->stackTraceFunctionWrapper->debugBacktrace() // add two frames on top. // Note that the frameIndex is 0 based. // And the file and line information refer to the caller // of the method in the frame. // Thus they offset each other. $frameIndex = $distanceFromThisCall; $stackFrames = $this->stackTraceFunctionWrapper->debugBacktrace(); $totalFrames = count($stackFrames); if ($totalFrames <= $frameIndex) { $exceptionMsg = "Requested frame ( {$frameIndex} ) is out of range." . " Total frames ( {$totalFrames} )"; throw new TestScribeException($exceptionMsg); } $targetFrame = $stackFrames[$frameIndex]; $fileName = ArrayUtil::lookupValueByKey('file', $targetFrame, 'unknown'); $lineNumberString = ArrayUtil::lookupValueByKey('line', $targetFrame, 'unknown'); $callerInfo = new CallInfo($fileName, $lineNumberString); return $callerInfo; }
/** * @param \Box\TestScribe\Mock\MockClass $mock * * @return string * * Define this method in a separate class causes circular dependencies. * i.e. these two methods depend on each other. */ public function renderMockedReturnValue(MockClass $mock) { $statementsArray = []; $mocks = $mock->getMockedReturnValues(); if ($mocks) { $statementsArray[] = "// Set up mocks of return values."; foreach ($mocks as $mockedReturnValueObj) { $oneMockStatement = $this->renderAMock($mockedReturnValueObj); $statementsArray[] = $oneMockStatement; } } $statementsString = ArrayUtil::joinNonEmptyStringsWithNewLine($statementsArray, 2); return $statementsString; }
/** * @param $testName * * @return OneSpec|null */ public function getSpecForTest($testName) { /** @var OneSpec $spec */ $spec = ArrayUtil::lookupValueByKey($testName, $this->specs, null); return $spec; }
/** * Return statements for invoking the test and verifying the result. * * @param \Box\TestScribe\Execution\ExecutionResult $executionResult * * @return string */ public function renderMethodInvocation(ExecutionResult $executionResult) { $mockClassUnderTest = $executionResult->getMockClassUnderTest(); $config = $this->globalComputedConfig; $inMethod = $config->getInMethod(); $reflectionMethod = $inMethod->getReflectionMethod(); $isStatic = $reflectionMethod->isStatic(); $fullyQualifiedClassName = $config->getFullClassName(); $constructorArguments = $executionResult->getConstructorArguments(); $constructorArgumentsRenderedResult = $this->argumentsRenderer->renderArguments($constructorArguments); $constructorArgumentsString = $constructorArgumentsRenderedResult->getArgumentString(); $mockObjectForConstructorStatements = $constructorArgumentsRenderedResult->getMockStatements(); if ($mockObjectForConstructorStatements) { $mockObjectForConstructorStatements = "// Setup mocks for parameters to the constructor.\n\n" . $mockObjectForConstructorStatements; } $methodArguments = $executionResult->getMethodArguments(); $argumentsToTheMethodRenderedResult = $this->argumentsRenderer->renderArguments($methodArguments); $mockMethodArgumentsStatements = $argumentsToTheMethodRenderedResult->getMockStatements(); if ($mockMethodArgumentsStatements) { $mockMethodArgumentsStatements = "// Setup mocks for parameters to the method under test.\n\n" . $mockMethodArgumentsStatements; } $mockAndComment = ArrayUtil::joinNonEmptyStringsWithNewLine(["{$mockMethodArgumentsStatements}", "// Execute the method under test."], 2); $isPartialMocking = $this->partialMockUtil->isClassUnderTestPartiallyMocked($mockClassUnderTest); $createObjectWithMocksStatement = ''; $targetObjectName = ''; if (!$isStatic) { if ($isPartialMocking) { // @TODO (ryang 3/4/15) : move the generated mock statements for the constructor into this scope. $createObjectWithMocksStatement = $this->mockRenderer->renderPartialMock($mockClassUnderTest, $constructorArgumentsString, $mockObjectForConstructorStatements); $targetObjectName = $mockClassUnderTest->getMockObjectName(); } else { $targetObjectName = 'objectUnderTest'; $createObjectStatement = "\${$targetObjectName} = new {$fullyQualifiedClassName}({$constructorArgumentsString});"; $createObjectWithMocksStatement = ArrayUtil::joinNonEmptyStringsWithNewLine([$mockObjectForConstructorStatements, $createObjectStatement], 2); } } $invocationStatement = $this->executionAndVerificationRenderer->genExecutionAndVerification($executionResult, $targetObjectName); $result = ArrayUtil::joinNonEmptyStringsWithNewLine([$mockAndComment, $createObjectWithMocksStatement, $invocationStatement], 2); return $result; }
/** * @covers \Box\TestScribe\Utils\ArrayUtil::lookupBoolValue * @covers \Box\TestScribe\Utils\ArrayUtil */ public function test_wrong_default_value_type_raise_exception() { $this->setExpectedException('Box\\TestScribe\\Exception\\TestScribeException'); // Execute the method under test. \Box\TestScribe\Utils\ArrayUtil::lookupBoolValue('k', ['another' => true], 'a'); }