jenkins-bot has submitted this change and it was merged. Change subject: Added preliminary diff merger functionality ......................................................................
Added preliminary diff merger functionality Change-Id: I7caae3f29ddc498ae2fa470059855e466f7f4c32 --- M Diff.classes.php M RELEASE-NOTES A includes/Merger/DiffMerger.php A includes/Merger/ListDiffMerger.php A includes/Merger/MapDiffMerger.php A includes/Merger/MultipleDiffMerger.php A tests/phpunit/Merger/ListDiffMergerTest.php A tests/phpunit/Merger/MapDiffMergerTest.php A tests/phpunit/Merger/MultipleDiffMergerTest.php 9 files changed, 613 insertions(+), 1 deletion(-) Approvals: Daniel Kinzler: Looks good to me, approved jenkins-bot: Verified diff --git a/Diff.classes.php b/Diff.classes.php index 3152655..0fe086d 100644 --- a/Diff.classes.php +++ b/Diff.classes.php @@ -36,6 +36,11 @@ 'Diff\DiffOpChange' => 'includes/diffop/DiffOpChange.php', 'Diff\DiffOpRemove' => 'includes/diffop/DiffOpRemove.php', + 'Diff\Merger\DiffMerger' => 'includes/Merger/DiffMerger.php', + 'Diff\Merger\ListDiffMerger' => 'includes/Merger/ListDiffMerger.php', + 'Diff\Merger\MapDiffMerger' => 'includes/Merger/MapDiffMerger.php', + 'Diff\Merger\MultipleDiffMerger' => 'includes/Merger/MultipleDiffMerger.php', + 'Diff\ListPatcher' => 'includes/patcher/ListPatcher.php', 'Diff\MapPatcher' => 'includes/patcher/MapPatcher.php', 'Diff\Patcher' => 'includes/patcher/Patcher.php', diff --git a/RELEASE-NOTES b/RELEASE-NOTES index c5995a4..6288dfb 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -3,6 +3,9 @@ Extension page on mediawiki.org: https://www.mediawiki.org/wiki/Extension:Diff Latest version of the release notes: https://gerrit.wikimedia.org/r/gitweb?p=mediawiki/extensions/Diff.git;a=blob;f=RELEASE-NOTES +* Added Diff\Merger component with functionality to merge diffs together +* Added @covers tags to the unit tests to improve coverage report accuracy + === Version 0.7 === (dev) @@ -119,4 +122,4 @@ * Classes to represent diff operations: Diff, MapDiff, ListDiff, DiffOpAdd, DiffOpChange, DiffOpRemove * Methods to compute list and maps diffs * Support for recursive diffs of arbitrary depth -* Works as MediaWiki extension or as standalone library \ No newline at end of file +* Works as MediaWiki extension or as standalone library diff --git a/includes/Merger/DiffMerger.php b/includes/Merger/DiffMerger.php new file mode 100644 index 0000000..ddcedac --- /dev/null +++ b/includes/Merger/DiffMerger.php @@ -0,0 +1,35 @@ +<?php + +namespace Diff\Merger; + +use Diff\Diff; + +/** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @since 0.7 + * + * @file + * @ingroup Diff + * + * @licence GNU GPL v2+ + * @author Jeroen De Dauw < jeroended...@gmail.com > + */ +interface DiffMerger { + + public function merge( Diff $firstDiff, Diff $secondDiff ); + +} diff --git a/includes/Merger/ListDiffMerger.php b/includes/Merger/ListDiffMerger.php new file mode 100644 index 0000000..67f14e7 --- /dev/null +++ b/includes/Merger/ListDiffMerger.php @@ -0,0 +1,58 @@ +<?php + +namespace Diff\Merger; + +use Diff\Diff; +use Diff\ListDiffer; + +/** + * Note: this class has not been fully implemented yet. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @since 0.7 + * + * @file + * @ingroup Diff + * + * @licence GNU GPL v2+ + * @author Jeroen De Dauw < jeroended...@gmail.com > + */ +class ListDiffMerger implements DiffMerger { + + public function merge( Diff $firstDiff, Diff $secondDiff ) { + $firstDiff = clone $firstDiff; + + foreach ( $secondDiff as $diffOp ) { + $firstDiff[] = $diffOp; + } + + return $firstDiff; + } + +// protected function getDiffWithoutRemovedAdditions( Diff $diff ) { +// $simplifiedDiff = new Diff(); +// +// array_diff( $diff->getAddedValues(), $diff->getRemovedValues() ); +// +// foreach ( ) { +// +// } +// +// return $simplifiedDiff; +// } + +} diff --git a/includes/Merger/MapDiffMerger.php b/includes/Merger/MapDiffMerger.php new file mode 100644 index 0000000..0d1c097 --- /dev/null +++ b/includes/Merger/MapDiffMerger.php @@ -0,0 +1,39 @@ +<?php + +namespace Diff\Merger; + +use Diff\Diff; + +/** + * Note: this class has not been fully implemented yet. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @since 0.7 + * + * @file + * @ingroup Diff + * + * @licence GNU GPL v2+ + * @author Jeroen De Dauw < jeroended...@gmail.com > + */ +class MapDiffMerger implements DiffMerger { + + public function merge( Diff $firstDiff, Diff $secondDiff ) { + return new Diff(); + } + +} diff --git a/includes/Merger/MultipleDiffMerger.php b/includes/Merger/MultipleDiffMerger.php new file mode 100644 index 0000000..d99df88 --- /dev/null +++ b/includes/Merger/MultipleDiffMerger.php @@ -0,0 +1,86 @@ +<?php + +namespace Diff\Merger; + +use Diff\Diff; + +/** + * Can merge multiple diffs together. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @since 0.7 + * + * @file + * @ingroup Diff + * + * @licence GNU GPL v2+ + * @author Jeroen De Dauw < jeroended...@gmail.com > + */ +class MultipleDiffMerger { + + protected $listMergingStrategy; + protected $mapMergingStrategy; + + public function __construct( DiffMerger $listMergingStrategy, DiffMerger $mapMergingStrategy ) { + $this->listMergingStrategy = $listMergingStrategy; + $this->mapMergingStrategy = $mapMergingStrategy; + } + + public function merge() { + $diffs = func_get_args(); + + if ( empty( $diffs ) ) { + return new Diff(); + } + + $this->validateInput( $diffs ); + + $mergedDiff = new Diff(); + + foreach ( $diffs as $diff ) { + $mergedDiff = $this->mergeDiffs( $mergedDiff, $diff ); + } + + return $mergedDiff; + } + + protected function validateInput( array $arguments ) { + foreach ( $arguments as $argument ) { + if ( !( $argument instanceof Diff ) ) { + throw new \InvalidArgumentException( + 'The merge method only accepts Diff\Diff objects as arguments' + ); + } + } + } + + protected function mergeDiffs( Diff $firstDiff, Diff $secondDiff ) { + if ( $firstDiff->isAssociative() !== $secondDiff->isAssociative() ) { + throw new \InvalidArgumentException( + 'Cannot merge an associative diff with a non-associative diff' + ); + } + + if ( $firstDiff->isAssociative() ) { + throw new \Exception( 'not implemented yet' ); + } + else { + return $this->listMergingStrategy->merge( $firstDiff, $secondDiff ); + } + } + +} diff --git a/tests/phpunit/Merger/ListDiffMergerTest.php b/tests/phpunit/Merger/ListDiffMergerTest.php new file mode 100644 index 0000000..d7f7b7f --- /dev/null +++ b/tests/phpunit/Merger/ListDiffMergerTest.php @@ -0,0 +1,160 @@ +<?php + +namespace Diff\Tests\Merger; + +use Diff\Diff; +use Diff\DiffOpAdd; +use Diff\DiffOpRemove; +use Diff\Merger\ListDiffMerger; + +/** + * @covers Diff\Merger\ListDiffMerger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @since 0.7 + * + * @ingroup DiffTest + * + * @group Diff + * @group DiffMerger + * + * @licence GNU GPL v2+ + * @author Jeroen De Dauw < jeroended...@gmail.com > + */ +class ListDiffMergerTest extends \PHPUnit_Framework_TestCase { + + public function testConstruct() { + new ListDiffMerger(); + $this->assertTrue( true ); + } + + /** + * @dataProvider mergeProvider + */ + public function testMerge( Diff $firstInput, Diff $secondInput, Diff $expectedDiff, $message ) { + $merger = new ListDiffMerger(); + + $mergedDiff = $merger->merge( $firstInput, $secondInput ); + + $this->assertEquals( $expectedDiff, $mergedDiff,$message ); + } + + public function mergeProvider() { + $argLists = array(); + + $firstInput = new Diff(); + $secondInput = new Diff(); + $expected = new Diff(); + + $argLists[] = array( + $firstInput, $secondInput, $expected, + 'Two empty diffs merged together result into one empty diff' + ); + + + $firstInput = new Diff(); + $secondInput = new Diff( array( new DiffOpAdd( 42 ), new DiffOpRemove( 9001 ) ) ); + $expected = $secondInput; + + $argLists[] = array( + $firstInput, $secondInput, $expected, + 'An empty diff plus a non-empty diff results in the non-empty diff' + ); + + + $firstInput = new Diff( array( new DiffOpAdd( 42 ), new DiffOpRemove( 9001 ) ) ); + $secondInput = new Diff(); + $expected = $firstInput; + + $argLists[] = array( + $firstInput, $secondInput, $expected, + 'A non-empty diff plus an empty diff results in the non-empty diff' + ); + + + $firstInput = new Diff( array( new DiffOpAdd( 42 ) ) ); + $secondInput = new Diff( array( new DiffOpAdd( 9001 ) ) ); + $expected = new Diff( array( new DiffOpAdd( 42 ), new DiffOpAdd( 9001 ) ) ); + + $argLists[] = array( + $firstInput, $secondInput, $expected, + 'Merging diffs with a single add operation together should result in' + . 'a single non-associative diff with two add operations' + ); + + + $firstInput = new Diff( array( new DiffOpAdd( 42 ), new DiffOpAdd( 42 ) ) ); + $secondInput = new Diff( array( new DiffOpAdd( 42 ), new DiffOpAdd( 42 ) ) ); + $expected = new Diff( array( + new DiffOpAdd( 42 ), + new DiffOpAdd( 42 ), + new DiffOpAdd( 42 ), + new DiffOpAdd( 42 ), + ) ); + + $argLists[] = array( + $firstInput, $secondInput, $expected, + 'Merging diffs with the same add operations should result in the ' + . 'add operations being there multiple times' + ); + + + $firstInput = new Diff( array( new DiffOpRemove( 42 ), new DiffOpRemove( 42 ) ) ); + $secondInput = new Diff( array( new DiffOpRemove( 42 ), new DiffOpRemove( 42 ) ) ); + $expected = new Diff( array( + new DiffOpRemove( 42 ), + new DiffOpRemove( 42 ), + new DiffOpRemove( 42 ), + new DiffOpRemove( 42 ), + ) ); + + $argLists[] = array( + $firstInput, $secondInput, $expected, + 'Merging diffs with the same remove operations should result in the ' + . 'remove operations being there multiple times' + ); + + +// $firstInput = new Diff( array( new DiffOpAdd( 42 ) ) ); +// $secondInput = new Diff( array( new DiffOpRemove( 42 ) ) ); +// $expected = new Diff( array() ); +// +// $argLists[] = array( +// $firstInput, $secondInput, $expected, +// 'A diff with add(x) merged with rem(x) should result in an empty diff' +// ); + + return $argLists; + } + + public function testInputIsNotModified() { + $merger = new ListDiffMerger(); + + $firstInput = new Diff( array( new DiffOpAdd( 23 ) ) ); + $secondInput = new Diff( array( new DiffOpAdd( 42 ) ) ); + + $originalFirstInput = clone $firstInput; + $originalSecondInput = clone $secondInput; + + $merger->merge( $firstInput, $secondInput ); + + $this->assertEquals( $originalFirstInput, $firstInput ); + $this->assertEquals( $originalSecondInput, $secondInput ); + } + +} diff --git a/tests/phpunit/Merger/MapDiffMergerTest.php b/tests/phpunit/Merger/MapDiffMergerTest.php new file mode 100644 index 0000000..1e0e3f8 --- /dev/null +++ b/tests/phpunit/Merger/MapDiffMergerTest.php @@ -0,0 +1,72 @@ +<?php + +namespace Diff\Tests\Merger; + +use Diff\Diff; +use Diff\DiffOpAdd; +use Diff\DiffOpRemove; +use Diff\Merger\MapDiffMerger; + +/** + * @covers Diff\Merger\MapDiffMerger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @since 0.7 + * + * @ingroup DiffTest + * + * @group Diff + * @group DiffMerger + * + * @licence GNU GPL v2+ + * @author Jeroen De Dauw < jeroended...@gmail.com > + */ +class MapDiffMergerTest extends \PHPUnit_Framework_TestCase { + + public function testConstruct() { + new MapDiffMerger(); + $this->assertTrue( true ); + } + + /** + * @dataProvider mergeProvider + */ + public function testMerge( Diff $firstInput, Diff $secondInput, Diff $expectedDiff, $message ) { + $merger = new MapDiffMerger(); + + $mergedDiff = $merger->merge( $firstInput, $secondInput ); + + $this->assertEquals( $expectedDiff, $mergedDiff,$message ); + } + + public function mergeProvider() { + $argLists = array(); + + $firstInput = new Diff(); + $secondInput = new Diff(); + $expected = new Diff(); + + $argLists[] = array( + $firstInput, $secondInput, $expected, + 'Two empty diffs merged together result into one empty diff' + ); + + return $argLists; + } + +} diff --git a/tests/phpunit/Merger/MultipleDiffMergerTest.php b/tests/phpunit/Merger/MultipleDiffMergerTest.php new file mode 100644 index 0000000..7f05c44 --- /dev/null +++ b/tests/phpunit/Merger/MultipleDiffMergerTest.php @@ -0,0 +1,154 @@ +<?php + +namespace Diff\Tests\Merger; + +use Diff\Diff; +use Diff\DiffOpAdd; +use Diff\DiffOpRemove; +use Diff\Merger\MultipleDiffMerger; + +/** + * @covers Diff\Merger\MultipleDiffMerger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @since 0.7 + * + * @ingroup DiffTest + * + * @group Diff + * @group DiffMerger + * + * @licence GNU GPL v2+ + * @author Jeroen De Dauw < jeroended...@gmail.com > + */ +class MultipleDiffMergerTest extends \PHPUnit_Framework_TestCase { + + public function testConstruct() { + $this->newMergerWithMocks(); + $this->assertTrue( true ); + } + + protected function newMergerWithMocks() { + $mergingStrategy = $this->getMock( 'Diff\Merger\DiffMerger' ); + + $mergingStrategy->expects( $this->any() ) + ->method( 'merge' ) + ->will( $this->returnValue( new Diff() ) ); + + return new MultipleDiffMerger( + $mergingStrategy, + $mergingStrategy + ); + } + + public function testMergeNone() { + $merger = $this->newMergerWithMocks(); + + $mergedDiff = $merger->merge(); + + $this->assertInstanceOf( 'Diff\Diff', $mergedDiff ); + $this->assertCount( 0, $mergedDiff ); + } + + public function testMergeOneEmpty() { + $merger = $this->newMergerWithMocks(); + + $inputDiff = new Diff(); + + $mergedDiff = $merger->merge( $inputDiff ); + + $this->assertEquals( $inputDiff, $mergedDiff ); + + $this->assertFalse( + $inputDiff === $mergedDiff, + 'When providing only one diff, the result should still be a new diff instance' + ); + } + + /** + * @dataProvider invalidInputProvider + */ + public function testOnlyAcceptsDiffs() { + $this->setExpectedException( 'InvalidArgumentException' ); + + $merger = $this->newMergerWithMocks(); + + $merger->merge( func_get_args() ); + } + + public function invalidInputProvider() { + $argLists = array(); + + $argLists[] = array( 1 ); + + $argLists[] = array( 'foo' ); + + $argLists[] = array( array() ); + + $argLists[] = array( new DiffOpRemove( 42 ) ); + + $argLists[] = array( new Diff(), 42 ); + + return $argLists; + } + + /** + * @dataProvider mergeDiffsProvider + */ + public function testMerge() { + $diffs = func_get_args(); + + $mergingStrategy = $this->getMock( 'Diff\Merger\DiffMerger' ); + + $mergingStrategy->expects( $this->exactly( count( $diffs ) ) ) + ->method( 'merge' ) + ->will( $this->returnValue( new Diff() ) );; + + $merger = new MultipleDiffMerger( + $mergingStrategy, + $mergingStrategy + ); + + call_user_func_array( array( $merger, 'merge' ), $diffs ); + } + + public function mergeDiffsProvider() { + $argLists[] = array( + new Diff( array( new DiffOpAdd( 42 ) ) ), + new Diff( array( new DiffOpAdd( 9001 ) ) ), + ); + + $argLists[] = array( + new Diff( array( new DiffOpAdd( 42 ) ) ), + new Diff( array( new DiffOpAdd( 9001 ) ) ), + new Diff( array( new DiffOpAdd( 1 ), new DiffOpAdd( 2 ) ) ), + ); + + $argLists[] = array( + new Diff( array( new DiffOpAdd( 42 ) ) ), + new Diff( array( new DiffOpAdd( 9001 ) ) ), + new Diff( array( new DiffOpAdd( 1 ), new DiffOpAdd( 2 ) ) ), + new Diff( array( new DiffOpAdd( 42 ) ) ), + new Diff( array( new DiffOpAdd( 9001 ) ) ), + new Diff( array( new DiffOpAdd( 1 ), new DiffOpAdd( 2 ) ) ), + ); + + return $argLists; + } + +} -- To view, visit https://gerrit.wikimedia.org/r/63690 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I7caae3f29ddc498ae2fa470059855e466f7f4c32 Gerrit-PatchSet: 11 Gerrit-Project: mediawiki/extensions/Diff Gerrit-Branch: master Gerrit-Owner: Jeroen De Dauw <jeroended...@gmail.com> Gerrit-Reviewer: Anja Jentzsch <a...@anjeve.de> Gerrit-Reviewer: Ataherivand <abraham.taheriv...@wikimedia.de> Gerrit-Reviewer: Aude <aude.w...@gmail.com> Gerrit-Reviewer: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Daniel Werner <daniel.wer...@wikimedia.de> Gerrit-Reviewer: Denny Vrandecic <denny.vrande...@wikimedia.de> Gerrit-Reviewer: Henning Snater <henning.sna...@wikimedia.de> Gerrit-Reviewer: Jens Ohlig <jens.oh...@wikimedia.de> Gerrit-Reviewer: Jeroen De Dauw <jeroended...@gmail.com> Gerrit-Reviewer: John Erling Blad <jeb...@gmail.com> Gerrit-Reviewer: Lydia Pintscher <lydia.pintsc...@wikimedia.de> Gerrit-Reviewer: Markus Kroetzsch <mar...@semantic-mediawiki.org> Gerrit-Reviewer: Nikola Smolenski <smole...@eunet.rs> Gerrit-Reviewer: Silke Meyer <silke.me...@wikimedia.de> Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits