Ejemplo n.º 1
0
    public function testCreate()
    {
        $before = <<<'EOD'
unchanged
replaced
unchanged
removed
EOD;
        $after = <<<'EOD'
added
unchanged
replacement
unchanged
EOD;
        $diff = [['added', 1], ['unchanged', 0], ['replaced', 2], ['replacement', 1], ['unchanged', 0], ['removed', 2]];
        $lines = [new Line(Line::ADDED, 'added', -1), new Line(Line::UNCHANGED, 'unchanged', 0), new Line(Line::REMOVED, 'replaced', 1), new Line(Line::ADDED, 'replacement', 1), new Line(Line::UNCHANGED, 'unchanged', 2), new Line(Line::REMOVED, 'removed', 3)];
        $differ = new Differ();
        $array_diff = $differ->diffToArray($before, $after);
        $this->assertEquals($diff, $array_diff);
        $result = Line::createArray($diff);
        $this->assertEquals($lines, $result);
        try {
            $diff[] = ['invalid', 3];
            Line::createArray($diff);
            $this->assertTrue(false, 'An exception was not thrown');
        } catch (\RuntimeException $e) {
            $this->assertEquals('Unsupported diff line type.', $e->getMessage());
        }
    }
Ejemplo n.º 2
0
 /**
  * @inheritDoc
  */
 public function merge($base, $remote, $local)
 {
     // Skip merging if there is nothing to do.
     if ($merged = PhpMergeBase::simpleMerge($base, $remote, $local)) {
         return $merged;
     }
     $remoteDiff = Line::createArray($this->differ->diffToArray($base, $remote));
     $localDiff = Line::createArray($this->differ->diffToArray($base, $local));
     $baseLines = Line::createArray(array_map(function ($l) {
         return [$l, 0];
     }, explode("\n", $base)));
     $remoteHunks = Hunk::createArray($remoteDiff);
     $localHunks = Hunk::createArray($localDiff);
     $conflicts = [];
     $merged = PhpMerge::mergeHunks($baseLines, $remoteHunks, $localHunks, $conflicts);
     if ($conflicts) {
         throw new MergeException('A merge conflict has occured.', $conflicts, $merged);
     }
     return $merged;
 }
Ejemplo n.º 3
0
 public function diff($t1, $t2)
 {
     $t1 = str_replace(['<dd>', '</dd>'], [PHP_EOL, ''], $t1);
     $t2 = str_replace(['<dd>', '</dd>'], [PHP_EOL, ''], $t2);
     $differ = new Differ();
     $diffs = $differ->diffToArray($t1, $t2);
     $folders = [new ContextFolder(), new ReplacesFolder(), new TypeFolder(PHP_EOL), new DiffFolder()];
     foreach ($folders as $folder) {
         $diffs = $folder->fold($diffs);
     }
     return $diffs;
 }
Ejemplo n.º 4
0
 /**
  * Returns the diff between two arrays or strings as string.
  *
  * @param array|string $from
  * @param array|string $to
  * @param int          $contextLines
  *
  * @return string
  */
 public function difference($from, $to, $contextLines = 3)
 {
     $tool = new Differ('');
     $diff = $tool->diffToArray($from, $to);
     $inOld = false;
     $i = 0;
     $old = array();
     foreach ($diff as $line) {
         if ($line[1] === 0) {
             if ($inOld === false) {
                 $inOld = $i;
             }
         } else {
             if ($inOld !== false) {
                 if ($i - $inOld > $contextLines) {
                     $old[$inOld] = $i - 1;
                 }
                 $inOld = false;
             }
         }
         ++$i;
     }
     $start = isset($old[0]) ? $old[0] : 0;
     $end = count($diff);
     if ($tmp = array_search($end, $old)) {
         $end = $tmp;
     }
     $contextLinesCounter = 0;
     $contextPreSet = false;
     $buffer = $this->initBuffer();
     for ($i = $start; $i < $end; $i++) {
         if (isset($old[$i])) {
             $i = $old[$i];
         }
         if ($diff[$i][1] === 1) {
             $buffer[] = $this->highlightAdded($diff[$i][0]);
         } else {
             if ($diff[$i][1] === 2) {
                 $buffer[] = $this->highlightRemoved($diff[$i][0]);
                 $contextPreSet = true;
             } else {
                 if ($contextPreSet && $contextLinesCounter >= $contextLines) {
                     break;
                 }
                 $buffer[] = $this->highlightContext($diff[$i][0]);
                 ++$contextLinesCounter;
             }
         }
     }
     return $this->implodeBuffer($buffer);
 }
Ejemplo n.º 5
0
 public function getPrettyDiff()
 {
     $prettyDiff = [];
     $differ = new Differ();
     $diffArr = $differ->diffToArray($this->fileChanges[0], $this->fileChanges[1]);
     $buffer = [];
     $lastMutation = false;
     foreach ($diffArr as $i => $diffToken) {
         if ($lastMutation !== false && $i - 3 === $lastMutation) {
             $prettyDiff = array_merge($prettyDiff, $buffer);
             $buffer = [];
         }
         if ($diffToken[1] !== 0) {
             $prettyDiff = array_merge($prettyDiff, $buffer);
             $buffer = [];
             $prettyDiff[] = $this->getPrettyMutation($diffToken);
             $lastMutation = $i;
         } else {
             $buffer[] = $this->getPrettyMutation($diffToken);
         }
         $buffer = array_slice($buffer, -3);
     }
     return implode("\n", $prettyDiff);
 }
Ejemplo n.º 6
0
 /**
  * @param array  $expected
  * @param string $from
  * @param string $to
  * @dataProvider arrayProvider
  * @covers       SebastianBergmann\Diff\Differ::diffToArray
  * @covers       SebastianBergmann\Diff\LCS\MemoryEfficientImplementation
  */
 public function testArrayRepresentationOfDiffCanBeRenderedUsingMemoryEfficientLcsImplementation(array $expected, $from, $to)
 {
     $this->assertEquals($expected, $this->differ->diffToArray($from, $to, new MemoryEfficientImplementation()));
 }
Ejemplo n.º 7
0
 public function foldReplaces()
 {
     $marker = chr(1);
     $marker2 = chr(2);
     $del = $this->foldChunks($this->delete, $marker);
     $ins = $this->foldChunks($this->insert, $marker);
     $replacer = function ($match) use($marker2) {
         return str_replace(' ', $marker2, $match[1]);
     };
     $del = preg_replace_callback('#(<\\w+([^>]+)>)#i', $replacer, $del);
     $ins = preg_replace_callback('#(<\\w+([^>]+)>)#i', $replacer, $ins);
     $del = str_replace([' ', '><'], [PHP_EOL, '>' . PHP_EOL . '<'], $del);
     $ins = str_replace([' ', '><'], [PHP_EOL, '>' . PHP_EOL . '<'], $ins);
     $differ = new \SebastianBergmann\Diff\Differ();
     $diffs = $differ->diffToArray($del, $ins);
     $folded = FolderChain::fold([new TypeFolder(' '), new ContextTypeRemover(), new DiffFolder(' ')], $diffs);
     $folded = str_replace($marker, PHP_EOL, $folded);
     $folded = str_replace($marker2, ' ', $folded);
     $this->chunk(3, $folded);
     $this->clearBuffer('delete');
     $this->clearBuffer('insert');
 }
Ejemplo n.º 8
0
 /**
  * Get the conflicts from a file which is left with merge conflicts.
  *
  * @param string $file
  *   The file name.
  * @param string $baseText
  *   The original text used for merging.
  * @param string $remoteText
  *   The first chaned text.
  * @param string $localText
  *   The second changed text.
  * @param MergeConflict[] $conflicts
  *   The merge conflicts will be apended to this array.
  * @param string[] $merged
  *   The merged text resolving conflicts by using the first set of changes.
  */
 protected static function getConflicts($file, $baseText, $remoteText, $localText, &$conflicts, &$merged)
 {
     $raw = new \ArrayObject(explode("\n", file_get_contents($file)));
     $lineIterator = $raw->getIterator();
     $state = 'unchanged';
     $conflictIndicator = ['<<<<<<< HEAD' => 'local', '||||||| merged common ancestors' => 'base', '=======' => 'remote', '>>>>>>> original' => 'end conflict'];
     // Create hunks from the text diff.
     $differ = new Differ();
     $remoteDiff = Line::createArray($differ->diffToArray($baseText, $remoteText));
     $localDiff = Line::createArray($differ->diffToArray($baseText, $localText));
     $remote_hunks = new \ArrayObject(Hunk::createArray($remoteDiff));
     $local_hunks = new \ArrayObject(Hunk::createArray($localDiff));
     $remoteIterator = $remote_hunks->getIterator();
     $localIterator = $local_hunks->getIterator();
     $base = [];
     $remote = [];
     $local = [];
     $lineNumber = -1;
     $newLine = 0;
     $skipedLines = 0;
     $addingConflict = false;
     // Loop over all the lines in the file.
     while ($lineIterator->valid()) {
         $line = $lineIterator->current();
         if (array_key_exists(trim($line), $conflictIndicator)) {
             // Check for a line matching a conflict indicator.
             $state = $conflictIndicator[trim($line)];
             $skipedLines++;
             if ($state == 'end conflict') {
                 // We just treated a merge conflict.
                 $conflicts[] = new MergeConflict($base, $remote, $local, $lineNumber, $newLine);
                 if ($lineNumber == -1) {
                     $lineNumber = 0;
                 }
                 $lineNumber += count($base);
                 $newLine += count($remote);
                 $base = [];
                 $remote = [];
                 $local = [];
                 $remoteIterator->next();
                 $localIterator->next();
                 if ($addingConflict) {
                     // Advance the counter for conflicts with adding.
                     $lineNumber++;
                     $newLine++;
                     $addingConflict = false;
                 }
                 $state = 'unchanged';
             }
         } else {
             switch ($state) {
                 case 'local':
                     $local[] = $line;
                     $skipedLines++;
                     break;
                 case 'base':
                     $base[] = $line;
                     $skipedLines++;
                     if ($lineNumber == -1) {
                         $lineNumber = 0;
                     }
                     break;
                 case 'remote':
                     $remote[] = $line;
                     $merged[] = $line;
                     break;
                 case 'unchanged':
                     if ($lineNumber == -1) {
                         $lineNumber = 0;
                     }
                     $merged[] = $line;
                     /** @var Hunk $r */
                     $r = $remoteIterator->current();
                     /** @var Hunk $l */
                     $l = $localIterator->current();
                     if ($r == $l) {
                         // If they are the same, treat only one.
                         $localIterator->next();
                         $l = $localIterator->current();
                     }
                     // A hunk has been successfully merged, so we can just
                     // tally the lines added and removed and skip forward.
                     if ($r && $r->getStart() == $lineNumber) {
                         if (!$r->hasIntersection($l)) {
                             $lineNumber += count($r->getRemovedLines());
                             $newLine += count($r->getAddedLines());
                             $lineIterator->seek($newLine + $skipedLines - 1);
                             $remoteIterator->next();
                         } else {
                             // If the conflict occurs on added lines, the
                             // next line in the merge will deal with it.
                             if ($r->getType() == Hunk::ADDED && $l->getType() == Hunk::ADDED) {
                                 $addingConflict = true;
                             } else {
                                 $lineNumber++;
                                 $newLine++;
                             }
                         }
                     } elseif ($l && $l->getStart() == $lineNumber) {
                         if (!$l->hasIntersection($r)) {
                             $lineNumber += count($l->getRemovedLines());
                             $newLine += count($l->getAddedLines());
                             $lineIterator->seek($newLine + $skipedLines - 1);
                             $localIterator->next();
                         } else {
                             $lineNumber++;
                             $newLine++;
                         }
                     } else {
                         $lineNumber++;
                         $newLine++;
                     }
                     break;
             }
         }
         $lineIterator->next();
     }
 }