StrictUnifiedDiffOutputBuilderTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of sebastian/diff.
  4. *
  5. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace SebastianBergmann\Diff\Output;
  11. use PHPUnit\Framework\TestCase;
  12. use SebastianBergmann\Diff\ConfigurationException;
  13. use SebastianBergmann\Diff\Differ;
  14. use SebastianBergmann\Diff\Utils\UnifiedDiffAssertTrait;
  15. /**
  16. * @covers SebastianBergmann\Diff\Output\StrictUnifiedDiffOutputBuilder
  17. *
  18. * @uses SebastianBergmann\Diff\Differ
  19. */
  20. final class StrictUnifiedDiffOutputBuilderTest extends TestCase
  21. {
  22. use UnifiedDiffAssertTrait;
  23. /**
  24. * @param string $expected
  25. * @param string $from
  26. * @param string $to
  27. * @param array $options
  28. *
  29. * @dataProvider provideOutputBuildingCases
  30. */
  31. public function testOutputBuilding(string $expected, string $from, string $to, array $options): void
  32. {
  33. $diff = $this->getDiffer($options)->diff($from, $to);
  34. $this->assertValidDiffFormat($diff);
  35. $this->assertSame($expected, $diff);
  36. }
  37. /**
  38. * @param string $expected
  39. * @param string $from
  40. * @param string $to
  41. * @param array $options
  42. *
  43. * @dataProvider provideSample
  44. */
  45. public function testSample(string $expected, string $from, string $to, array $options): void
  46. {
  47. $diff = $this->getDiffer($options)->diff($from, $to);
  48. $this->assertValidDiffFormat($diff);
  49. $this->assertSame($expected, $diff);
  50. }
  51. /**
  52. * {@inheritdoc}
  53. */
  54. public function assertValidDiffFormat(string $diff): void
  55. {
  56. $this->assertValidUnifiedDiffFormat($diff);
  57. }
  58. /**
  59. * {@inheritdoc}
  60. */
  61. public function provideOutputBuildingCases(): array
  62. {
  63. return StrictUnifiedDiffOutputBuilderDataProvider::provideOutputBuildingCases();
  64. }
  65. /**
  66. * {@inheritdoc}
  67. */
  68. public function provideSample(): array
  69. {
  70. return StrictUnifiedDiffOutputBuilderDataProvider::provideSample();
  71. }
  72. /**
  73. * @param string $expected
  74. * @param string $from
  75. * @param string $to
  76. *
  77. * @dataProvider provideBasicDiffGeneration
  78. */
  79. public function testBasicDiffGeneration(string $expected, string $from, string $to): void
  80. {
  81. $diff = $this->getDiffer([
  82. 'fromFile' => 'input.txt',
  83. 'toFile' => 'output.txt',
  84. ])->diff($from, $to);
  85. $this->assertValidDiffFormat($diff);
  86. $this->assertSame($expected, $diff);
  87. }
  88. public function provideBasicDiffGeneration(): array
  89. {
  90. return StrictUnifiedDiffOutputBuilderDataProvider::provideBasicDiffGeneration();
  91. }
  92. /**
  93. * @param string $expected
  94. * @param string $from
  95. * @param string $to
  96. * @param array $config
  97. *
  98. * @dataProvider provideConfiguredDiffGeneration
  99. */
  100. public function testConfiguredDiffGeneration(string $expected, string $from, string $to, array $config = []): void
  101. {
  102. $diff = $this->getDiffer(\array_merge([
  103. 'fromFile' => 'input.txt',
  104. 'toFile' => 'output.txt',
  105. ], $config))->diff($from, $to);
  106. $this->assertValidDiffFormat($diff);
  107. $this->assertSame($expected, $diff);
  108. }
  109. public function provideConfiguredDiffGeneration(): array
  110. {
  111. return [
  112. [
  113. '--- input.txt
  114. +++ output.txt
  115. @@ -1 +1 @@
  116. -a
  117. \ No newline at end of file
  118. +b
  119. \ No newline at end of file
  120. ',
  121. 'a',
  122. 'b',
  123. ],
  124. [
  125. '',
  126. "1\n2",
  127. "1\n2",
  128. ],
  129. [
  130. '',
  131. "1\n",
  132. "1\n",
  133. ],
  134. [
  135. '--- input.txt
  136. +++ output.txt
  137. @@ -4 +4 @@
  138. -X
  139. +4
  140. ',
  141. "1\n2\n3\nX\n5\n6\n7\n8\n9\n0\n",
  142. "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n",
  143. [
  144. 'contextLines' => 0,
  145. ],
  146. ],
  147. [
  148. '--- input.txt
  149. +++ output.txt
  150. @@ -3,3 +3,3 @@
  151. 3
  152. -X
  153. +4
  154. 5
  155. ',
  156. "1\n2\n3\nX\n5\n6\n7\n8\n9\n0\n",
  157. "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n",
  158. [
  159. 'contextLines' => 1,
  160. ],
  161. ],
  162. [
  163. '--- input.txt
  164. +++ output.txt
  165. @@ -1,10 +1,10 @@
  166. 1
  167. 2
  168. 3
  169. -X
  170. +4
  171. 5
  172. 6
  173. 7
  174. 8
  175. 9
  176. 0
  177. ',
  178. "1\n2\n3\nX\n5\n6\n7\n8\n9\n0\n",
  179. "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n",
  180. [
  181. 'contextLines' => 999,
  182. ],
  183. ],
  184. [
  185. '--- input.txt
  186. +++ output.txt
  187. @@ -1,0 +1,2 @@
  188. +
  189. +A
  190. ',
  191. '',
  192. "\nA\n",
  193. ],
  194. [
  195. '--- input.txt
  196. +++ output.txt
  197. @@ -1,2 +1,0 @@
  198. -
  199. -A
  200. ',
  201. "\nA\n",
  202. '',
  203. ],
  204. [
  205. '--- input.txt
  206. +++ output.txt
  207. @@ -1,5 +1,5 @@
  208. 1
  209. -X
  210. +2
  211. 3
  212. -Y
  213. +4
  214. 5
  215. @@ -8,3 +8,3 @@
  216. 8
  217. -X
  218. +9
  219. 0
  220. ',
  221. "1\nX\n3\nY\n5\n6\n7\n8\nX\n0\n",
  222. "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n",
  223. [
  224. 'commonLineThreshold' => 2,
  225. 'contextLines' => 1,
  226. ],
  227. ],
  228. [
  229. '--- input.txt
  230. +++ output.txt
  231. @@ -2 +2 @@
  232. -X
  233. +2
  234. @@ -4 +4 @@
  235. -Y
  236. +4
  237. @@ -9 +9 @@
  238. -X
  239. +9
  240. ',
  241. "1\nX\n3\nY\n5\n6\n7\n8\nX\n0\n",
  242. "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n",
  243. [
  244. 'commonLineThreshold' => 1,
  245. 'contextLines' => 0,
  246. ],
  247. ],
  248. ];
  249. }
  250. public function testReUseBuilder(): void
  251. {
  252. $differ = $this->getDiffer([
  253. 'fromFile' => 'input.txt',
  254. 'toFile' => 'output.txt',
  255. ]);
  256. $diff = $differ->diff("A\nB\n", "A\nX\n");
  257. $this->assertSame(
  258. '--- input.txt
  259. +++ output.txt
  260. @@ -1,2 +1,2 @@
  261. A
  262. -B
  263. +X
  264. ',
  265. $diff
  266. );
  267. $diff = $differ->diff("A\n", "A\n");
  268. $this->assertSame(
  269. '',
  270. $diff
  271. );
  272. }
  273. public function testEmptyDiff(): void
  274. {
  275. $builder = new StrictUnifiedDiffOutputBuilder([
  276. 'fromFile' => 'input.txt',
  277. 'toFile' => 'output.txt',
  278. ]);
  279. $this->assertSame(
  280. '',
  281. $builder->getDiff([])
  282. );
  283. }
  284. /**
  285. * @param array $options
  286. * @param string $message
  287. *
  288. * @dataProvider provideInvalidConfiguration
  289. */
  290. public function testInvalidConfiguration(array $options, string $message): void
  291. {
  292. $this->expectException(ConfigurationException::class);
  293. $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote($message, '#')));
  294. new StrictUnifiedDiffOutputBuilder($options);
  295. }
  296. public function provideInvalidConfiguration(): array
  297. {
  298. $time = \time();
  299. return [
  300. [
  301. ['collapseRanges' => 1],
  302. 'Option "collapseRanges" must be a bool, got "integer#1".',
  303. ],
  304. [
  305. ['contextLines' => 'a'],
  306. 'Option "contextLines" must be an int >= 0, got "string#a".',
  307. ],
  308. [
  309. ['commonLineThreshold' => -2],
  310. 'Option "commonLineThreshold" must be an int > 0, got "integer#-2".',
  311. ],
  312. [
  313. ['commonLineThreshold' => 0],
  314. 'Option "commonLineThreshold" must be an int > 0, got "integer#0".',
  315. ],
  316. [
  317. ['fromFile' => new \SplFileInfo(__FILE__)],
  318. 'Option "fromFile" must be a string, got "SplFileInfo".',
  319. ],
  320. [
  321. ['fromFile' => null],
  322. 'Option "fromFile" must be a string, got "<null>".',
  323. ],
  324. [
  325. [
  326. 'fromFile' => __FILE__,
  327. 'toFile' => 1,
  328. ],
  329. 'Option "toFile" must be a string, got "integer#1".',
  330. ],
  331. [
  332. [
  333. 'fromFile' => __FILE__,
  334. 'toFile' => __FILE__,
  335. 'toFileDate' => $time,
  336. ],
  337. 'Option "toFileDate" must be a string or <null>, got "integer#' . $time . '".',
  338. ],
  339. [
  340. [],
  341. 'Option "fromFile" must be a string, got "<null>".',
  342. ],
  343. ];
  344. }
  345. /**
  346. * @param string $expected
  347. * @param string $from
  348. * @param string $to
  349. * @param int $threshold
  350. *
  351. * @dataProvider provideCommonLineThresholdCases
  352. */
  353. public function testCommonLineThreshold(string $expected, string $from, string $to, int $threshold): void
  354. {
  355. $diff = $this->getDiffer([
  356. 'fromFile' => 'input.txt',
  357. 'toFile' => 'output.txt',
  358. 'commonLineThreshold' => $threshold,
  359. 'contextLines' => 0,
  360. ])->diff($from, $to);
  361. $this->assertValidDiffFormat($diff);
  362. $this->assertSame($expected, $diff);
  363. }
  364. public function provideCommonLineThresholdCases(): array
  365. {
  366. return [
  367. [
  368. '--- input.txt
  369. +++ output.txt
  370. @@ -2,3 +2,3 @@
  371. -X
  372. +B
  373. C12
  374. -Y
  375. +D
  376. @@ -7 +7 @@
  377. -X
  378. +Z
  379. ',
  380. "A\nX\nC12\nY\nA\nA\nX\n",
  381. "A\nB\nC12\nD\nA\nA\nZ\n",
  382. 2,
  383. ],
  384. [
  385. '--- input.txt
  386. +++ output.txt
  387. @@ -2 +2 @@
  388. -X
  389. +B
  390. @@ -4 +4 @@
  391. -Y
  392. +D
  393. ',
  394. "A\nX\nV\nY\n",
  395. "A\nB\nV\nD\n",
  396. 1,
  397. ],
  398. ];
  399. }
  400. /**
  401. * @param string $expected
  402. * @param string $from
  403. * @param string $to
  404. * @param int $contextLines
  405. * @param int $commonLineThreshold
  406. *
  407. * @dataProvider provideContextLineConfigurationCases
  408. */
  409. public function testContextLineConfiguration(string $expected, string $from, string $to, int $contextLines, int $commonLineThreshold = 6): void
  410. {
  411. $diff = $this->getDiffer([
  412. 'fromFile' => 'input.txt',
  413. 'toFile' => 'output.txt',
  414. 'contextLines' => $contextLines,
  415. 'commonLineThreshold' => $commonLineThreshold,
  416. ])->diff($from, $to);
  417. $this->assertValidDiffFormat($diff);
  418. $this->assertSame($expected, $diff);
  419. }
  420. public function provideContextLineConfigurationCases(): array
  421. {
  422. $from = "A\nB\nC\nD\nE\nF\nX\nG\nH\nI\nJ\nK\nL\nM\n";
  423. $to = "A\nB\nC\nD\nE\nF\nY\nG\nH\nI\nJ\nK\nL\nM\n";
  424. return [
  425. 'EOF 0' => [
  426. "--- input.txt\n+++ output.txt\n@@ -3 +3 @@
  427. -X
  428. \\ No newline at end of file
  429. +Y
  430. \\ No newline at end of file
  431. ",
  432. "A\nB\nX",
  433. "A\nB\nY",
  434. 0,
  435. ],
  436. 'EOF 1' => [
  437. "--- input.txt\n+++ output.txt\n@@ -2,2 +2,2 @@
  438. B
  439. -X
  440. \\ No newline at end of file
  441. +Y
  442. \\ No newline at end of file
  443. ",
  444. "A\nB\nX",
  445. "A\nB\nY",
  446. 1,
  447. ],
  448. 'EOF 2' => [
  449. "--- input.txt\n+++ output.txt\n@@ -1,3 +1,3 @@
  450. A
  451. B
  452. -X
  453. \\ No newline at end of file
  454. +Y
  455. \\ No newline at end of file
  456. ",
  457. "A\nB\nX",
  458. "A\nB\nY",
  459. 2,
  460. ],
  461. 'EOF 200' => [
  462. "--- input.txt\n+++ output.txt\n@@ -1,3 +1,3 @@
  463. A
  464. B
  465. -X
  466. \\ No newline at end of file
  467. +Y
  468. \\ No newline at end of file
  469. ",
  470. "A\nB\nX",
  471. "A\nB\nY",
  472. 200,
  473. ],
  474. 'n/a 0' => [
  475. "--- input.txt\n+++ output.txt\n@@ -7 +7 @@\n-X\n+Y\n",
  476. $from,
  477. $to,
  478. 0,
  479. ],
  480. 'G' => [
  481. "--- input.txt\n+++ output.txt\n@@ -6,3 +6,3 @@\n F\n-X\n+Y\n G\n",
  482. $from,
  483. $to,
  484. 1,
  485. ],
  486. 'H' => [
  487. "--- input.txt\n+++ output.txt\n@@ -5,5 +5,5 @@\n E\n F\n-X\n+Y\n G\n H\n",
  488. $from,
  489. $to,
  490. 2,
  491. ],
  492. 'I' => [
  493. "--- input.txt\n+++ output.txt\n@@ -4,7 +4,7 @@\n D\n E\n F\n-X\n+Y\n G\n H\n I\n",
  494. $from,
  495. $to,
  496. 3,
  497. ],
  498. 'J' => [
  499. "--- input.txt\n+++ output.txt\n@@ -3,9 +3,9 @@\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n",
  500. $from,
  501. $to,
  502. 4,
  503. ],
  504. 'K' => [
  505. "--- input.txt\n+++ output.txt\n@@ -2,11 +2,11 @@\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n",
  506. $from,
  507. $to,
  508. 5,
  509. ],
  510. 'L' => [
  511. "--- input.txt\n+++ output.txt\n@@ -1,13 +1,13 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n",
  512. $from,
  513. $to,
  514. 6,
  515. ],
  516. 'M' => [
  517. "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n M\n",
  518. $from,
  519. $to,
  520. 7,
  521. ],
  522. 'M no linebreak EOF .1' => [
  523. "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n-M\n+M\n\\ No newline at end of file\n",
  524. $from,
  525. \substr($to, 0, -1),
  526. 7,
  527. ],
  528. 'M no linebreak EOF .2' => [
  529. "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n-M\n\\ No newline at end of file\n+M\n",
  530. \substr($from, 0, -1),
  531. $to,
  532. 7,
  533. ],
  534. 'M no linebreak EOF .3' => [
  535. "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n M\n",
  536. \substr($from, 0, -1),
  537. \substr($to, 0, -1),
  538. 7,
  539. ],
  540. 'M no linebreak EOF .4' => [
  541. "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n M\n\\ No newline at end of file\n",
  542. \substr($from, 0, -1),
  543. \substr($to, 0, -1),
  544. 10000,
  545. 10000,
  546. ],
  547. 'M+1' => [
  548. "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n M\n",
  549. $from,
  550. $to,
  551. 8,
  552. ],
  553. 'M+100' => [
  554. "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n M\n",
  555. $from,
  556. $to,
  557. 107,
  558. ],
  559. '0 II' => [
  560. "--- input.txt\n+++ output.txt\n@@ -12 +12 @@\n-X\n+Y\n",
  561. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nX\nM\n",
  562. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nY\nM\n",
  563. 0,
  564. 999,
  565. ],
  566. '0\' II' => [
  567. "--- input.txt\n+++ output.txt\n@@ -12 +12 @@\n-X\n+Y\n",
  568. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nX\nM\nA\nA\nA\nA\nA\n",
  569. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nY\nM\nA\nA\nA\nA\nA\n",
  570. 0,
  571. 999,
  572. ],
  573. '0\'\' II' => [
  574. "--- input.txt\n+++ output.txt\n@@ -12,2 +12,2 @@\n-X\n-M\n\\ No newline at end of file\n+Y\n+M\n",
  575. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nX\nM",
  576. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nY\nM\n",
  577. 0,
  578. ],
  579. '0\'\'\' II' => [
  580. "--- input.txt\n+++ output.txt\n@@ -12,2 +12,2 @@\n-X\n-X1\n+Y\n+Y2\n",
  581. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nX\nX1\nM\nA\nA\nA\nA\nA\n",
  582. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nY\nY2\nM\nA\nA\nA\nA\nA\n",
  583. 0,
  584. 999,
  585. ],
  586. '1 II' => [
  587. "--- input.txt\n+++ output.txt\n@@ -11,3 +11,3 @@\n K\n-X\n+Y\n M\n",
  588. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nX\nM\n",
  589. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nY\nM\n",
  590. 1,
  591. ],
  592. '5 II' => [
  593. "--- input.txt\n+++ output.txt\n@@ -7,7 +7,7 @@\n G\n H\n I\n J\n K\n-X\n+Y\n M\n",
  594. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nX\nM\n",
  595. "A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nY\nM\n",
  596. 5,
  597. ],
  598. [
  599. '--- input.txt
  600. +++ output.txt
  601. @@ -1,28 +1,28 @@
  602. A
  603. -X
  604. +B
  605. V
  606. -Y
  607. +D
  608. 1
  609. A
  610. 2
  611. A
  612. 3
  613. A
  614. 4
  615. A
  616. 8
  617. A
  618. 9
  619. A
  620. 5
  621. A
  622. A
  623. A
  624. A
  625. A
  626. A
  627. A
  628. A
  629. A
  630. A
  631. A
  632. ',
  633. "A\nX\nV\nY\n1\nA\n2\nA\n3\nA\n4\nA\n8\nA\n9\nA\n5\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\n",
  634. "A\nB\nV\nD\n1\nA\n2\nA\n3\nA\n4\nA\n8\nA\n9\nA\n5\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\n",
  635. 9999,
  636. 99999,
  637. ],
  638. ];
  639. }
  640. /**
  641. * Returns a new instance of a Differ with a new instance of the class (DiffOutputBuilderInterface) under test.
  642. *
  643. * @param array $options
  644. *
  645. * @return Differ
  646. */
  647. private function getDiffer(array $options = []): Differ
  648. {
  649. return new Differ(new StrictUnifiedDiffOutputBuilder($options));
  650. }
  651. }