ConfigurationResolverTest.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. <?php
  2. /*
  3. * This file is part of PHP CS Fixer.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. namespace PhpCsFixer\Tests\Console;
  12. use PhpCsFixer\Config;
  13. use PhpCsFixer\Console\ConfigurationResolver;
  14. use PhpCsFixer\Finder;
  15. use PhpCsFixer\Fixer;
  16. use PhpCsFixer\Test\AccessibleObject;
  17. use Symfony\Component\Finder\SplFileInfo;
  18. /**
  19. * @author Katsuhiro Ogawa <ko.fivestar@gmail.com>
  20. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  21. *
  22. * @internal
  23. */
  24. final class ConfigurationResolverTest extends \PHPUnit_Framework_TestCase
  25. {
  26. protected $config;
  27. protected $resolver;
  28. protected function setUp()
  29. {
  30. $fixer = new Fixer();
  31. $this->config = new Config();
  32. $this->resolver = new ConfigurationResolver();
  33. $this->resolver
  34. ->setDefaultConfig($this->config)
  35. ;
  36. }
  37. protected function tearDown()
  38. {
  39. unset(
  40. $this->config,
  41. $this->resolver
  42. );
  43. }
  44. public function testSetOption()
  45. {
  46. $this->resolver->setOption('path', '.');
  47. $property = AccessibleObject::create($this->resolver)->options;
  48. $this->assertSame('.', $property['path']);
  49. }
  50. /**
  51. * @expectedException \PhpCsFixer\ConfigurationException\InvalidConfigurationException
  52. * @expectedExceptionMessageRegExp /^Unknown option name: "foo"\.$/
  53. */
  54. public function testSetOptionWithUndefinedOption()
  55. {
  56. $this->resolver->setOption('foo', 'bar');
  57. }
  58. public function testSetOptions()
  59. {
  60. $this->resolver->setOptions(array(
  61. 'path' => '.',
  62. 'config' => 'config.php_cs',
  63. ));
  64. $property = AccessibleObject::create($this->resolver)->options;
  65. $this->assertSame('.', $property['path']);
  66. $this->assertSame('config.php_cs', $property['config']);
  67. }
  68. public function testCwd()
  69. {
  70. $this->resolver->setCwd('foo');
  71. $property = AccessibleObject::create($this->resolver)->cwd;
  72. $this->assertSame('foo', $property);
  73. }
  74. protected function makeFixersTest($expectedFixers, $resolvedFixers)
  75. {
  76. $this->assertCount(count($expectedFixers), $resolvedFixers);
  77. foreach ($expectedFixers as $fixer) {
  78. $this->assertContains($fixer, $resolvedFixers);
  79. }
  80. }
  81. public function testResolveFixersReturnsEmptyArrayByDefault()
  82. {
  83. $this->makeFixersTest(array(), $this->resolver->getFixers());
  84. }
  85. public function testResolveProgressWithPositiveConfigAndPositiveOption()
  86. {
  87. $this->config->hideProgress(true);
  88. $this->resolver
  89. ->setOption('progress', true)
  90. ->resolve()
  91. ;
  92. $this->assertFalse($this->resolver->getProgress());
  93. }
  94. public function testResolveProgressWithPositiveConfigAndNegativeOption()
  95. {
  96. $this->config->hideProgress(true);
  97. $this->resolver
  98. ->setOption('progress', false)
  99. ->resolve()
  100. ;
  101. $this->assertFalse($this->resolver->getProgress());
  102. }
  103. public function testResolveProgressWithNegativeConfigAndPositiveOption()
  104. {
  105. $this->config->hideProgress(false);
  106. $this->resolver
  107. ->setOption('progress', true)
  108. ->resolve()
  109. ;
  110. $this->assertTrue($this->resolver->getProgress());
  111. }
  112. public function testResolveProgressWithNegativeConfigAndNegativeOption()
  113. {
  114. $this->config->hideProgress(false);
  115. $this->resolver
  116. ->setOption('progress', false)
  117. ->resolve()
  118. ;
  119. $this->assertFalse($this->resolver->getProgress());
  120. }
  121. public function testResolveConfigFileDefault()
  122. {
  123. $this->resolver
  124. ->resolve();
  125. $this->assertNull($this->resolver->getConfigFile());
  126. $this->assertInstanceOf('\\PhpCsFixer\\ConfigInterface', $this->resolver->getConfig());
  127. }
  128. public function testResolveConfigFileByPathOfFile()
  129. {
  130. $dir = __DIR__.'/../Fixtures/ConfigurationResolverConfigFile/case_1';
  131. $this->resolver
  132. ->setOption('path', $dir.DIRECTORY_SEPARATOR.'foo.php')
  133. ->resolve();
  134. $this->assertSame($dir.DIRECTORY_SEPARATOR.'.php_cs.dist', $this->resolver->getConfigFile());
  135. $this->assertInstanceOf('Test1Config', $this->resolver->getConfig());
  136. }
  137. public function testResolveConfigFileSpecified()
  138. {
  139. $file = __DIR__.'/../Fixtures/ConfigurationResolverConfigFile/case_4/my.php_cs';
  140. $this->resolver
  141. ->setOption('config', $file)
  142. ->resolve();
  143. $this->assertSame($file, $this->resolver->getConfigFile());
  144. $this->assertInstanceOf('Test4Config', $this->resolver->getConfig());
  145. }
  146. /**
  147. * @dataProvider provideResolveConfigFileDefaultCases
  148. */
  149. public function testResolveConfigFileChooseFile($expectedFile, $expectedClass, $path, $cwdPath = null)
  150. {
  151. $resolver = $this->resolver
  152. ->setOption('path', $path)
  153. ;
  154. if (null !== $cwdPath) {
  155. $resolver->setCwd($cwdPath);
  156. }
  157. $resolver->resolve();
  158. $this->assertSame($expectedFile, $this->resolver->getConfigFile());
  159. $this->assertInstanceOf($expectedClass, $this->resolver->getConfig());
  160. }
  161. public function provideResolveConfigFileDefaultCases()
  162. {
  163. $dirBase = __DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'ConfigurationResolverConfigFile'.DIRECTORY_SEPARATOR;
  164. return array(
  165. array(
  166. $dirBase.'case_1'.DIRECTORY_SEPARATOR.'.php_cs.dist',
  167. 'Test1Config',
  168. $dirBase.'case_1',
  169. ),
  170. array(
  171. $dirBase.'case_2'.DIRECTORY_SEPARATOR.'.php_cs',
  172. 'Test2Config',
  173. $dirBase.'case_2',
  174. ),
  175. array(
  176. $dirBase.'case_3'.DIRECTORY_SEPARATOR.'.php_cs',
  177. 'Test3Config',
  178. $dirBase.'case_3',
  179. ),
  180. array(
  181. $dirBase.'case_6'.DIRECTORY_SEPARATOR.'.php_cs.dist',
  182. 'Test6Config',
  183. $dirBase.'case_6'.DIRECTORY_SEPARATOR.'subdir',
  184. $dirBase.'case_6',
  185. ),
  186. array(
  187. $dirBase.'case_6'.DIRECTORY_SEPARATOR.'.php_cs.dist',
  188. 'Test6Config',
  189. $dirBase.'case_6'.DIRECTORY_SEPARATOR.'subdir/empty_file.php',
  190. $dirBase.'case_6',
  191. ),
  192. );
  193. }
  194. /**
  195. * @expectedException \PhpCsFixer\ConfigurationException\InvalidConfigurationException
  196. * @expectedExceptionMessageRegExp /^The config file: ".+[\/\\]Fixtures[\/\\]ConfigurationResolverConfigFile[\/\\]case_5[\/\\].php_cs.dist" does not return a "PhpCsFixer\\ConfigInterface" instance\. Got: "string"\.$/
  197. */
  198. public function testResolveConfigFileChooseFileWithInvalidFile()
  199. {
  200. $dirBase = realpath(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'ConfigurationResolverConfigFile'.DIRECTORY_SEPARATOR);
  201. $this->resolver
  202. ->setOption('path', $dirBase.'/case_5')
  203. ->resolve();
  204. }
  205. public function testResolvePathRelative()
  206. {
  207. $this->resolver
  208. ->setCwd(__DIR__)
  209. ->setOption('path', 'Command')
  210. ->resolve();
  211. $this->assertSame(__DIR__.DIRECTORY_SEPARATOR.'Command', $this->resolver->getPath());
  212. $this->resolver
  213. ->setCwd(dirname(__DIR__))
  214. ->setOption('path', basename(__DIR__))
  215. ->resolve();
  216. $this->assertSame(__DIR__, $this->resolver->getPath());
  217. }
  218. public function testResolvePathWithFileThatIsExcludedDirectly()
  219. {
  220. $this->config->getFinder()
  221. ->in(__DIR__)
  222. ->notPath(basename(__FILE__));
  223. $this->resolver
  224. ->setOption('path', __FILE__)
  225. ->resolve();
  226. $this->assertCount(0, $this->resolver->getConfig()->getFinder());
  227. }
  228. public function testResolvePathWithFileThatIsExcludedByDir()
  229. {
  230. $dir = dirname(__DIR__);
  231. $this->config->getFinder()
  232. ->in($dir)
  233. ->exclude(basename(__DIR__));
  234. $this->resolver
  235. ->setOption('path', __FILE__)
  236. ->resolve();
  237. $this->assertCount(0, $this->resolver->getConfig()->getFinder());
  238. }
  239. public function testResolvePathWithFileThatIsNotExcluded()
  240. {
  241. $dir = __DIR__;
  242. $this->config->getFinder()
  243. ->in($dir)
  244. ->notPath('foo-'.basename(__FILE__));
  245. $this->resolver
  246. ->setOption('path', __FILE__)
  247. ->resolve();
  248. $this->assertCount(1, $this->resolver->getConfig()->getFinder());
  249. }
  250. /**
  251. * @dataProvider provideResolveIntersectionOfPathsCases
  252. */
  253. public function testResolveIntersectionOfPaths($expectedIntersectionItems, $configFinder, $option)
  254. {
  255. $this->config->finder($configFinder);
  256. $this->resolver
  257. ->setOption('path', $option)
  258. ->resolve()
  259. ;
  260. $intersectionItems = array_map(
  261. function (SplFileInfo $file) {
  262. return $file->getRealPath();
  263. },
  264. iterator_to_array($this->resolver->getConfig()->getFinder(), false)
  265. );
  266. sort($expectedIntersectionItems);
  267. sort($intersectionItems);
  268. $this->assertSame($expectedIntersectionItems, $intersectionItems);
  269. }
  270. public function provideResolveIntersectionOfPathsCases()
  271. {
  272. $dir = __DIR__.'/../Fixtures/ConfigurationResolverPathsIntersection';
  273. $cb = function (array $items) use ($dir) {
  274. return array_map(
  275. function ($item) use ($dir) {
  276. return realpath($dir.'/'.$item);
  277. },
  278. $items
  279. );
  280. };
  281. return array(
  282. // configured only by finder
  283. array(
  284. $cb(array('a1.php', 'a2.php', 'b/b1.php', 'b/b2.php', 'b_b/b_b1.php', 'c/c1.php', 'c/d/cd1.php')),
  285. Finder::create()
  286. ->in($dir),
  287. null,
  288. ),
  289. // configured only by argument
  290. array(
  291. $cb(array('a1.php', 'a2.php', 'b/b1.php', 'b/b2.php', 'b_b/b_b1.php', 'c/c1.php', 'c/d/cd1.php')),
  292. Finder::create(),
  293. $dir,
  294. ),
  295. // configured by finder, filtered by argument which is dir
  296. array(
  297. $cb(array('c/c1.php', 'c/d/cd1.php')),
  298. Finder::create()
  299. ->in($dir),
  300. $dir.'/c',
  301. ),
  302. // configured by finder, filtered by argument which is file
  303. array(
  304. $cb(array('c/c1.php')),
  305. Finder::create()
  306. ->in($dir),
  307. $dir.'/c/c1.php',
  308. ),
  309. // finder points to one dir while argument to another, not connected
  310. array(
  311. array(),
  312. Finder::create()
  313. ->in($dir.'/b'),
  314. $dir.'/c',
  315. ),
  316. // finder with excluded dir, argument point to excluded file
  317. array(
  318. array(),
  319. Finder::create()
  320. ->in($dir)
  321. ->exclude('c'),
  322. $dir.'/c/d/cd1.php',
  323. ),
  324. // finder with excluded dir, argument point to excluded parent
  325. array(
  326. $cb(array('c/c1.php')),
  327. Finder::create()
  328. ->in($dir)
  329. ->exclude('c/d'),
  330. $dir.'/c',
  331. ),
  332. // finder with excluded file, argument point to excluded parent
  333. array(
  334. $cb(array('c/d/cd1.php')),
  335. Finder::create()
  336. ->in($dir)
  337. ->notPath('c/c1.php'),
  338. $dir.'/c',
  339. ),
  340. // finder with excluded file, argument point to excluded parent
  341. array(
  342. $cb(array('b/b1.php', 'b/b2.php')),
  343. Finder::create()
  344. ->in($dir),
  345. $dir.'/b',
  346. ),
  347. );
  348. }
  349. public function testResolveIsDryRunViaStdIn()
  350. {
  351. $this->resolver
  352. ->setOption('path', '-')
  353. ->setOption('dry-run', false)
  354. ->resolve();
  355. $this->assertTrue($this->resolver->isDryRun());
  356. }
  357. public function testResolveIsDryRunViaNegativeOption()
  358. {
  359. $this->resolver
  360. ->setOption('dry-run', false)
  361. ->resolve();
  362. $this->assertFalse($this->resolver->isDryRun());
  363. }
  364. public function testResolveIsDryRunViaPositiveOption()
  365. {
  366. $this->resolver
  367. ->setOption('dry-run', true)
  368. ->resolve();
  369. $this->assertTrue($this->resolver->isDryRun());
  370. }
  371. public function testResolveUsingCacheWithPositiveConfigAndPositiveOption()
  372. {
  373. $this->config->setUsingCache(true);
  374. $this->resolver
  375. ->setOption('using-cache', 'yes')
  376. ->resolve();
  377. $this->assertTrue($this->config->usingCache());
  378. }
  379. public function testResolveUsingCacheWithPositiveConfigAndNegativeOption()
  380. {
  381. $this->config->setUsingCache(true);
  382. $this->resolver
  383. ->setOption('using-cache', 'no')
  384. ->resolve();
  385. $this->assertFalse($this->config->usingCache());
  386. }
  387. public function testResolveUsingCacheWithNegativeConfigAndPositiveOption()
  388. {
  389. $this->config->setUsingCache(false);
  390. $this->resolver
  391. ->setOption('using-cache', 'yes')
  392. ->resolve();
  393. $this->assertTrue($this->config->usingCache());
  394. }
  395. public function testResolveUsingCacheWithNegativeConfigAndNegativeOption()
  396. {
  397. $this->config->setUsingCache(false);
  398. $this->resolver
  399. ->setOption('using-cache', 'no')
  400. ->resolve();
  401. $this->assertFalse($this->config->usingCache());
  402. }
  403. public function testResolveUsingCacheWithPositiveConfigAndNoOption()
  404. {
  405. $this->config->setUsingCache(true);
  406. $this->resolver
  407. ->resolve();
  408. $this->assertTrue($this->config->usingCache());
  409. }
  410. public function testResolveUsingCacheWithNegativeConfigAndNoOption()
  411. {
  412. $this->config->setUsingCache(false);
  413. $this->resolver
  414. ->resolve();
  415. $this->assertFalse($this->config->usingCache());
  416. }
  417. public function testResolveCacheFileWithoutConfigAndOption()
  418. {
  419. $default = $this->config->getCacheFile();
  420. $this->resolver->resolve();
  421. $this->assertSame($default, $this->config->getCacheFile());
  422. }
  423. public function testResolveCacheFileWithConfig()
  424. {
  425. $cacheFile = 'foo/bar.baz';
  426. $this->config->setCacheFile($cacheFile);
  427. $this->resolver->resolve();
  428. $this->assertSame($cacheFile, $this->config->getCacheFile());
  429. }
  430. public function testResolveCacheFileWithOption()
  431. {
  432. $cacheFile = 'bar.baz';
  433. $this->config->setCacheFile($cacheFile);
  434. $this->resolver->setOption('cache-file', $cacheFile);
  435. $this->resolver->resolve();
  436. $this->assertSame($cacheFile, $this->config->getCacheFile());
  437. }
  438. public function testResolveCacheFileWithConfigAndOption()
  439. {
  440. $configCacheFile = 'foo/bar.baz';
  441. $optionCacheFile = 'bar.baz';
  442. $this->config->setCacheFile($configCacheFile);
  443. $this->resolver->setOption('cache-file', $optionCacheFile);
  444. $this->resolver->resolve();
  445. $this->assertSame($optionCacheFile, $this->config->getCacheFile());
  446. }
  447. public function testResolveAllowRiskyWithPositiveConfigAndPositiveOption()
  448. {
  449. $this->config->setRiskyAllowed(true);
  450. $this->resolver
  451. ->setOption('allow-risky', 'yes')
  452. ->resolve();
  453. $this->assertTrue($this->config->getRiskyAllowed());
  454. }
  455. public function testResolveAllowRiskyWithPositiveConfigAndNegativeOption()
  456. {
  457. $this->config->setRiskyAllowed(true);
  458. $this->resolver
  459. ->setOption('allow-risky', 'no')
  460. ->resolve();
  461. $this->assertFalse($this->config->getRiskyAllowed());
  462. }
  463. public function testResolveAllowRiskyWithNegativeConfigAndPositiveOption()
  464. {
  465. $this->config->setRiskyAllowed(false);
  466. $this->resolver
  467. ->setOption('allow-risky', 'yes')
  468. ->resolve();
  469. $this->assertTrue($this->config->getRiskyAllowed());
  470. }
  471. public function testResolveAllowRiskyWithNegativeConfigAndNegativeOption()
  472. {
  473. $this->config->setRiskyAllowed(false);
  474. $this->resolver
  475. ->setOption('allow-risky', 'no')
  476. ->resolve();
  477. $this->assertFalse($this->config->getRiskyAllowed());
  478. }
  479. public function testResolveAllowRiskyWithPositiveConfigAndNoOption()
  480. {
  481. $this->config->setRiskyAllowed(true);
  482. $this->resolver
  483. ->resolve();
  484. $this->assertTrue($this->config->getRiskyAllowed());
  485. }
  486. public function testResolveAllowRiskyWithNegativeConfigAndNoOption()
  487. {
  488. $this->config->setRiskyAllowed(false);
  489. $this->resolver
  490. ->resolve();
  491. $this->assertFalse($this->config->getRiskyAllowed());
  492. }
  493. public function testResolveRulesWithConfig()
  494. {
  495. $this->config->setRules(array(
  496. 'braces' => true,
  497. 'strict_comparison' => false,
  498. ));
  499. $this->resolver->resolve();
  500. $this->assertSameRules(
  501. array(
  502. 'braces' => true,
  503. ),
  504. $this->resolver->getRules()
  505. );
  506. }
  507. public function testResolveRulesWithOption()
  508. {
  509. $this->resolver->setOption('rules', 'braces,-strict');
  510. $this->resolver->resolve();
  511. $this->assertSameRules(
  512. array(
  513. 'braces' => true,
  514. ),
  515. $this->resolver->getRules()
  516. );
  517. }
  518. public function testResolveRulesWithConfigAndOption()
  519. {
  520. $this->config->setRules(array(
  521. 'braces' => true,
  522. 'strict_comparison' => false,
  523. ));
  524. $this->resolver->setOption('rules', 'blank_line_before_return');
  525. $this->resolver->resolve();
  526. $this->assertSameRules(
  527. array(
  528. 'blank_line_before_return' => true,
  529. ),
  530. $this->resolver->getRules()
  531. );
  532. }
  533. private function assertSameRules(array $expected, array $actual, $message = '')
  534. {
  535. ksort($expected);
  536. ksort($actual);
  537. $this->assertSame($expected, $actual, $message);
  538. }
  539. }