ArrayComparator.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of sebastian/comparator.
  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\Comparator;
  11. use function array_key_exists;
  12. use function assert;
  13. use function is_array;
  14. use function sort;
  15. use function sprintf;
  16. use function str_replace;
  17. use function trim;
  18. use SebastianBergmann\Exporter\Exporter;
  19. /**
  20. * Arrays are equal if they contain the same key-value pairs.
  21. * The order of the keys does not matter.
  22. * The types of key-value pairs do not matter.
  23. */
  24. class ArrayComparator extends Comparator
  25. {
  26. public function accepts(mixed $expected, mixed $actual): bool
  27. {
  28. return is_array($expected) && is_array($actual);
  29. }
  30. /**
  31. * @throws ComparisonFailure
  32. */
  33. public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void
  34. {
  35. assert(is_array($expected));
  36. assert(is_array($actual));
  37. if ($canonicalize) {
  38. sort($expected);
  39. sort($actual);
  40. }
  41. $remaining = $actual;
  42. $actualAsString = "Array (\n";
  43. $expectedAsString = "Array (\n";
  44. $equal = true;
  45. $exporter = new Exporter;
  46. foreach ($expected as $key => $value) {
  47. unset($remaining[$key]);
  48. if (!array_key_exists($key, $actual)) {
  49. $expectedAsString .= sprintf(
  50. " %s => %s\n",
  51. $exporter->export($key),
  52. $exporter->shortenedExport($value)
  53. );
  54. $equal = false;
  55. continue;
  56. }
  57. try {
  58. $comparator = $this->factory()->getComparatorFor($value, $actual[$key]);
  59. $comparator->assertEquals($value, $actual[$key], $delta, $canonicalize, $ignoreCase, $processed);
  60. $expectedAsString .= sprintf(
  61. " %s => %s\n",
  62. $exporter->export($key),
  63. $exporter->shortenedExport($value)
  64. );
  65. $actualAsString .= sprintf(
  66. " %s => %s\n",
  67. $exporter->export($key),
  68. $exporter->shortenedExport($actual[$key])
  69. );
  70. } catch (ComparisonFailure $e) {
  71. $expectedAsString .= sprintf(
  72. " %s => %s\n",
  73. $exporter->export($key),
  74. $e->getExpectedAsString() ? $this->indent($e->getExpectedAsString()) : $exporter->shortenedExport($e->getExpected())
  75. );
  76. $actualAsString .= sprintf(
  77. " %s => %s\n",
  78. $exporter->export($key),
  79. $e->getActualAsString() ? $this->indent($e->getActualAsString()) : $exporter->shortenedExport($e->getActual())
  80. );
  81. $equal = false;
  82. }
  83. }
  84. foreach ($remaining as $key => $value) {
  85. $actualAsString .= sprintf(
  86. " %s => %s\n",
  87. $exporter->export($key),
  88. $exporter->shortenedExport($value)
  89. );
  90. $equal = false;
  91. }
  92. $expectedAsString .= ')';
  93. $actualAsString .= ')';
  94. if (!$equal) {
  95. throw new ComparisonFailure(
  96. $expected,
  97. $actual,
  98. $expectedAsString,
  99. $actualAsString,
  100. 'Failed asserting that two arrays are equal.'
  101. );
  102. }
  103. }
  104. private function indent(string $lines): string
  105. {
  106. return trim(str_replace("\n", "\n ", $lines));
  107. }
  108. }