public function testClassesThatDoesNotExtendOtherClassesShouldNotHaveAParentClass() { $file = __DIR__ . '/../../../resources/oop/f1.php'; $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($file); $this->assertCount(1, $result->getClasses()); $class = current($result->getClasses()); $this->assertNull($class->getParent()); }
/** * @dataProvider providesFilesForLcom */ public function testICanCalculateLackOfCohesionOfClass($file, $expected) { $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($file); $classes = $result->getClasses(); $class = $classes[0]; $lcom = new LackOfCohesionOfMethods(); $result = $lcom->calculate($class); $this->assertEquals($expected, $result->getLCOM()); }
public function testAnonymousClassIsFound() { $filename = __DIR__ . '/../../../resources/oop/php7-scalarhint1.php'; $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($filename); $classes = $result->getClasses(); $this->assertEquals(1, sizeof($classes)); $main = $classes[0]; $this->assertEquals(0, sizeof($main->getDependencies())); }
public function testProxyIsDetected() { $filename = __DIR__ . '/../../../../resources/patterns/proxy.php'; $extractor = new Extractor(new Tokenizer()); $result = $extractor->extract($filename); $classes = $result->getClasses(); $class = $classes[2]; $resolved = new ResolvedClass($class); $resolver = new ProxyResolver($classes); $resolver->resolve($resolved); $this->assertEquals(1, sizeof($resolved->getPatterns())); }
public function testCallsAreFoundAsDependencies() { $file = __DIR__ . '/../../../resources/oop/f5.php'; $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($file); $classes = $result->getClasses(); $this->assertCount(1, $classes, 'all classes are found'); $class = $classes[0]; $dependencies = $class->getDependencies(); $expected = array('\\Example\\IAmCalled', '\\IAmCalled'); $this->assertEquals($expected, $dependencies, 'Direct dependencies (calls) are found'); }
public function testCouplingTakesCareOfReturnedValues() { $filename = __DIR__ . '/../../../../../resources/coupling/f1.php'; $extractor = new Extractor(new Tokenizer()); $classmap = new ClassMap(); $classmap->push($filename, $extractor->extract($filename)); $coupling = new Coupling(); $this->result = $coupling->calculate($classmap); $this->assertEquals(0, $this->result->get('\\ClassWhoUseAnother')->getAfferentCoupling()); $this->assertEquals(1, $this->result->get('\\ClassWhoUseAnother')->getEfferentCoupling()); $this->assertEquals(1, $this->result->get('\\ClassWhoIsUsed')->getAfferentCoupling()); $this->assertEquals(0, $this->result->get('\\ClassWhoIsUsed')->getEfferentCoupling()); }
/** * @dataProvider provideAbstractClasses */ public function testAbstractClassesAreFound($filename, $expected) { $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($filename); $found = 0; foreach ($result->getClasses() as $class) { if ($class->isAbstract()) { $found++; $this->assertContains($class->getFullname(), $expected); } } $this->assertEquals(sizeof($expected, COUNT_NORMAL), $found); }
/** * @inheritdoc */ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('Design pattern detector by Jean-François Lépine <https://twitter.com/Halleck45>'); $output->writeln(''); $finder = new Finder($input->getOption('extensions'), $input->getOption('excluded-dirs')); $files = $finder->find($input->getArgument('path')); if (0 == sizeof($files, COUNT_NORMAL)) { throw new \LogicException('No file found'); } // // 1. Extracting classes $output->writeln('<info>Extracting classes</info>'); $progress = new ProgressBar($output); $progress->start(sizeof($files, COUNT_NORMAL)); $collection = array(); $tokenizer = new Tokenizer(new CacheMemory()); $extractor = new Extractor($tokenizer); $nbClasses = 0; foreach ($files as $k => $filename) { $progress->advance(); $collection[] = $classes = $extractor->extract($filename); $nbClasses += sizeof($classes->getClasses()); } $progress->clear(); $progress->finish(); // inform user $output->writeln(''); $output->writeln(''); $output->writeln(sprintf("<info>Found %d classes</info>", $nbClasses)); // // 2. Extracting patterns $output->writeln('<info>Extracting design patterns</info>'); $patterns = array(); foreach ($collection as $oop) { $classes = $oop->getClasses(); $resolver = new PatternResolver($classes); foreach ($classes as $class) { $resolvedClass = new ResolvedClass($class); $resolver->resolve($resolvedClass); if ($resolvedClass->getPatterns()) { $patterns = array_merge($patterns, $resolvedClass->getPatterns()); } } } // inform user $output->writeln(sprintf("<info>Found %d design patterns</info>", sizeof($patterns))); $output->writeln(); foreach ($patterns as $pattern) { $output->writeln(sprintf("\t<info>[%s]</info> %s", $pattern->getName(), $pattern->describe())); } }
/** * @dataProvider providesClasses */ public function testICanCalculateSystemComplexityOfClass($totalDataComplexity, $totalStructureComplexity, $totalSystemComplexity, $code) { $filename = tempnam(sys_get_temp_dir(), 'unit-phpmetrics-syc'); file_put_contents($filename, $code); $extractor = new Extractor(new Tokenizer()); $classes = $extractor->extract($filename)->getClasses(); $class = $classes[0]; $metric = new SystemComplexity(); $result = $metric->calculate($class); $this->assertEquals($totalDataComplexity, $result->getTotalDataComplexity(), 'total data complexity'); $this->assertEquals($totalStructureComplexity, $result->getTotalStructuralComplexity(), 'total structure complexity'); $this->assertEquals($totalSystemComplexity, $result->getTotalSystemComplexity(), 'total system complexity'); unlink($filename); }
public function testReturnedTypeIsFoundEvenOnAbstractMethod() { $filename = __DIR__ . '/../../../resources/oop/php7-return3.php'; $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($filename); $classes = $result->getClasses(); $this->assertEquals(1, sizeof($classes)); $methods = $classes[0]->getMethods(); $this->assertEquals(2, sizeof($methods)); $method = $methods['createSchema']; $expected = new ReflectedReturn(); $expected->setMode(ReflectedReturn::STRICT_TYPE_HINT)->setType('\\Schema'); $this->assertEquals(array($expected), $method->getReturns()); }
public function testUsageOfConstantInParameterDoesNotBreakEngine() { $filename = __DIR__ . '/../../../resources/oop/php7-return-bugfix1.php'; $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($filename); $classes = $result->getClasses(); $this->assertEquals(1, sizeof($classes)); $methods = $classes[0]->getMethods(); $this->assertEquals(1, sizeof($methods)); $method = $methods['register']; $expected = new ReflectedReturn(); $expected->setMode(ReflectedReturn::ESTIMATED_TYPE_HINT)->setType(TypeResolver::TYPE_UNKNWON)->setValue('stream_filter_register($name, $class)'); $this->assertEquals(array($expected), $method->getReturns()); }
public function testGodObjectIsDetected() { $filename = __DIR__ . '/../../../../resources/patterns/godobject.php'; $extractor = new Extractor(new Tokenizer()); $result = $extractor->extract($filename); $classes = $result->getClasses(); $resolver = new GodObjectResolver($classes); $resolved = new ResolvedClass($classes[0]); $resolver->resolve($resolved); $this->assertEquals(1, sizeof($resolved->getPatterns())); $resolved = new ResolvedClass($classes[1]); $resolver->resolve($resolved); $this->assertEquals(0, sizeof($resolved->getPatterns())); }
/** * Run analyze * * @param $filename * @return \Hal\Component\Result\ResultSet */ public function execute($filename) { $rHalstead = $this->halstead->calculate($filename); $rLoc = $this->loc->calculate($filename); $rMcCabe = $this->mcCabe->calculate($filename); $rMyer = $this->myer->calculate($filename); $rMaintenability = $this->maintenabilityIndex->calculate($rHalstead, $rLoc, $rMcCabe); $resultSet = new \Hal\Component\Result\ResultSet($filename); $resultSet->setLoc($rLoc)->setMcCabe($rMcCabe)->setMyer($rMyer)->setHalstead($rHalstead)->setMaintenabilityIndex($rMaintenability); if ($this->withOOP) { $rOOP = $this->extractor->extract($filename); $this->classMap->push($filename, $rOOP); $resultSet->setOOP($rOOP); } return $resultSet; }
/** * @group php7 */ public function testInterfacesAreFound() { // only one contract $filename = __DIR__ . '/../../../resources/oop/interface1.php'; $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($filename); $classes = $result->getClasses(); $this->assertCount(2, $classes); $class = $classes[1]; $this->assertEquals(array('\\Contract1'), $class->getInterfaces(), 'interface of class is found'); // multiple contracts $filename = __DIR__ . '/../../../resources/oop/interface2.php'; $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($filename); $classes = $result->getClasses(); $this->assertCount(3, $classes); $class = $classes[2]; $this->assertEquals(array('\\My\\Contract1', '\\My\\Contract2'), $class->getInterfaces(), 'multiple interfaces of class are found'); }
public function testContentOfMethodIsFound() { $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract(__DIR__ . '/../../../resources/oop/f6.php'); $classes = $result->getClasses(); $class = $classes[0]; $methods = $class->getMethods(); $method = $methods['foo']; $expected = <<<EOT \$a = strtoupper((string)\$a); return \$a; EOT; $this->assertEquals($expected, $method->getContent()); $methods = $class->getMethods(); $method = end($methods); $expected = <<<EOT \$x = 1 * 2; die(); EOT; $this->assertEquals($expected, $method->getContent()); }
public function testReservedWordClassDoesNotCount() { $filename = __DIR__ . '/../../../resources/oop/reserved-word-class.php'; $tokens = (new \Hal\Component\Token\Tokenizer())->tokenize($filename); $extractor = new Extractor(); $result = $extractor->extract($tokens); $classes = $result->getClasses(); $this->assertEquals(1, sizeof($classes)); $class = $classes[0]; $this->assertEquals('\\My\\Test', $class->getFullname()); }
public function testReturningNewStaticIsWellParsed() { $filename = __DIR__ . '/../../../resources/oop/php7-static-as-dep1.php'; $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract($filename); $classes = $result->getClasses(); $this->assertEquals(1, sizeof($classes)); $class = $classes[0]; $this->assertEquals(array('\\My\\MyClass'), $class->getDependencies()); }
public function testSetterAreFound() { $extractor = new Extractor(new \Hal\Component\Token\Tokenizer()); $result = $extractor->extract(__DIR__ . '/../../../resources/oop/f8.php'); $classes = $result->getClasses(); $class = $classes[0]; $methods = $class->getMethods(); $this->assertFalse($methods['getA']->isSetter()); $this->assertFalse($methods['foo']->isSetter()); $this->assertTrue($methods['setA']->isSetter()); $this->assertTrue($methods['setB']->isSetter()); }
public function testMultipleClassesWithSameMethodName() { $filename = __DIR__ . '/../../../resources/oop/php7-6.php'; $tokens = (new \Hal\Component\Token\Tokenizer())->tokenize($filename); $extractor = new Extractor(); $result = $extractor->extract($tokens); $classes = $result->getClasses(); $this->assertEquals(7, sizeof($classes)); $mother = $classes[0]; $class1 = $classes[2]; $class2 = $classes[4]; $this->assertEquals('\\My\\B', $class1->getFullname()); $this->assertEquals('\\My\\C', $class2->getFullname()); $this->assertEquals(array('\\My\\D', '\\My\\A', '\\My\\Mother'), $class1->getDependencies()); }