jenkins-bot has submitted this change and it was merged.

Change subject: FindAndReplaceDialog tests
......................................................................


FindAndReplaceDialog tests

Tests find and replace all functionality.

Bonus: Fixes bug in regex find where matches which overran
into elements were discarded.

Change-Id: Ib691455adb9c1dcd6ccfc726b499e1a878ae77c6
---
M build/modules.json
M src/dm/ve.dm.Document.js
M tests/index.html
A tests/ui/dialogs/ve.ui.FindAndReplaceDialog.test.js
4 files changed, 169 insertions(+), 12 deletions(-)

Approvals:
  Divec: Looks good to me, approved
  Jforrester: Looks good to me, but someone else must approve
  jenkins-bot: Verified



diff --git a/build/modules.json b/build/modules.json
index f30e65e..7e07885 100644
--- a/build/modules.json
+++ b/build/modules.json
@@ -554,6 +554,7 @@
                        "tests/ui/actions/ve.ui.ListAction.test.js",
                        "tests/ui/actions/ve.ui.TableAction.test.js",
                        
"tests/ui/datatransferhandlers/ve.ui.DSVFileTransferHandler.test.js",
+                       "tests/ui/dialogs/ve.ui.FindAndReplaceDialog.test.js",
                        "tests/ce/ve.ce.TestRunner.js",
                        "tests/ce/ve.ce.imetests.test.js",
                        "tests/ce/imetests/backspace-chromium-ubuntu-none.js",
diff --git a/src/dm/ve.dm.Document.js b/src/dm/ve.dm.Document.js
index 4c251f2..d426d29 100644
--- a/src/dm/ve.dm.Document.js
+++ b/src/dm/ve.dm.Document.js
@@ -1261,7 +1261,7 @@
  * @return {ve.Range[]} List of ranges where the string was found
  */
 ve.dm.Document.prototype.findText = function ( query, caseSensitive, 
noOverlaps ) {
-       var len, match, offset,
+       var i, l, len, match, offset, lines,
                ranges = [],
                text = this.data.getText(
                        true,
@@ -1269,19 +1269,25 @@
                );
 
        if ( query instanceof RegExp ) {
-               if ( !caseSensitive ) {
-                       query = new RegExp( query.source, 'i' );
-               }
+               query = new RegExp( query.source, caseSensitive ? 'g' : 'gi' );
                offset = 0;
-               while ( ( match = query.exec( text.substr( offset ) ) ) !== 
null ) {
-                       offset = offset + match.index;
-                       len = match[0].length;
-                       // Newlines may match some expressions, but are not 
allowed
-                       // as they represent elements
-                       if ( match[0].indexOf( '\n' ) === -1 ) {
-                               ranges.push( new ve.Range( offset, offset + len 
) );
+               // Avoid multi-line matching by only matching within newlines
+               lines = text.split( '\n' );
+               for ( i = 0, l = lines.length; i < l; i++ ) {
+                       while ( lines[i] && ( match = query.exec( lines[i] ) ) 
!== null ) {
+                               // Skip empty string matches (e.g. with .*)
+                               if ( query.lastIndex === match.index ) {
+                                       // Increment to avoid infinite loop
+                                       query.lastIndex++;
+                                       continue;
+                               }
+                               ranges.push( new ve.Range( offset + 
match.index, offset + query.lastIndex ) );
+                               if ( !noOverlaps ) {
+                                       query.lastIndex = match.index + 1;
+                               }
                        }
-                       offset += noOverlaps ? len : 1;
+                       offset += lines[i].length + 1;
+                       query.lastIndex = 0;
                }
        } else {
                if ( !caseSensitive ) {
diff --git a/tests/index.html b/tests/index.html
index 84b38a8..e818c74 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -402,6 +402,7 @@
                <script 
src="../tests/ui/actions/ve.ui.ListAction.test.js"></script>
                <script 
src="../tests/ui/actions/ve.ui.TableAction.test.js"></script>
                <script 
src="../tests/ui/datatransferhandlers/ve.ui.DSVFileTransferHandler.test.js"></script>
+               <script 
src="../tests/ui/dialogs/ve.ui.FindAndReplaceDialog.test.js"></script>
                <script src="../tests/ce/ve.ce.TestRunner.js"></script>
                <script src="../tests/ce/ve.ce.imetests.test.js"></script>
                <script 
src="../tests/ce/imetests/backspace-chromium-ubuntu-none.js"></script>
diff --git a/tests/ui/dialogs/ve.ui.FindAndReplaceDialog.test.js 
b/tests/ui/dialogs/ve.ui.FindAndReplaceDialog.test.js
new file mode 100644
index 0000000..971623e
--- /dev/null
+++ b/tests/ui/dialogs/ve.ui.FindAndReplaceDialog.test.js
@@ -0,0 +1,149 @@
+/*!
+ * VisualEditor UserInterface FindAndReplaceDialog tests.
+ *
+ * @copyright 2011-2015 VisualEditor Team and others; see 
http://ve.mit-license.org
+ */
+
+QUnit.module( 've.ui.FindAndReplaceDialog' );
+
+/* Tests */
+
+QUnit.test( 'find fragments', function ( assert ) {
+       var done = assert.async(),
+               surface = ve.test.utils.createSurfaceFromHtml( '<p>Foo bar 
fooq.</p><p>baz foob</p>' ),
+               cases = [
+                       {
+                               msg: 'Simple case insensitive',
+                               find: 'Foo',
+                               ranges: [
+                                       new ve.Range( 1, 4 ),
+                                       new ve.Range( 9, 12 ),
+                                       new ve.Range( 20, 23 )
+                               ]
+                       },
+                       {
+                               msg: 'Simple case sensitive',
+                               find: 'Foo',
+                               matchCase: true,
+                               ranges: [
+                                       new ve.Range( 1, 4 )
+                               ]
+                       },
+                       {
+                               msg: 'Case insensitive regex',
+                               find: 'fo[^ ]+',
+                               regex: true,
+                               ranges: [
+                                       new ve.Range( 1, 4 ),
+                                       new ve.Range( 9, 14 ),
+                                       new ve.Range( 20, 24 )
+                               ]
+                       },
+                       {
+                               msg: 'Case sensitive regex',
+                               find: 'fo[^ ]+',
+                               regex: true,
+                               matchCase: true,
+                               ranges: [
+                                       new ve.Range( 9, 14 ),
+                                       new ve.Range( 20, 24 )
+                               ]
+                       },
+                       {
+                               msg: 'Regex to end of line',
+                               find: 'q.*',
+                               regex: true,
+                               ranges: [
+                                       new ve.Range( 12, 14 )
+                               ]
+                       },
+                       {
+                               msg: 'Overlapping regex',
+                               find: '.*',
+                               regex: true,
+                               ranges: [
+                                       new ve.Range( 1, 14 ),
+                                       new ve.Range( 16, 24 )
+                               ]
+                       },
+                       {
+                               msg: 'Invalid regex',
+                               find: '(.*',
+                               regex: true,
+                               ranges: []
+                       }
+               ];
+
+       QUnit.expect( cases.length );
+
+       surface.getToolbarDialogs().getWindow( 'findAndReplace' ).done( 
function ( dialog ) {
+               dialog.open( {
+                       surface: surface,
+                       fragment: surface.getModel().getFragment()
+               } ).done( function () {
+                       var i, ranges;
+                       for ( i = 0; i < cases.length; i++ ) {
+                               dialog.matchCaseToggle.setValue( 
!!cases[i].matchCase );
+                               dialog.regexToggle.setValue( !!cases[i].regex );
+                               dialog.findText.setValue( cases[i].find );
+                               /* jshint loopfunc:true */
+                               ranges = dialog.fragments.map( function ( 
fragment ) {
+                                       return 
fragment.getSelection().getRange();
+                               } );
+                               assert.deepEqual( ranges, cases[i].ranges, 
cases[i].msg );
+                               dialog.findText.setValue( '' );
+                       }
+                       done();
+               } );
+       } );
+
+} );
+
+QUnit.test( 'replace all', function ( assert ) {
+       var done = assert.async(),
+               surface = ve.test.utils.createSurfaceFromHtml( '<p>Foo bar 
fooq.</p><p>baz foob</p>' ),
+               cases = [
+                       {
+                               msg: 'Simple case insensitive',
+                               find: 'Foo',
+                               replace: 'baz',
+                               expected: 'baz bar bazq.baz bazb'
+                       },
+                       {
+                               msg: 'Recursive',
+                               find: 'baz',
+                               replace: 'foofoo',
+                               expected: 'foofoo bar foofooq.foofoo foofoob'
+                       },
+                       {
+                               msg: 'Regex',
+                               find: '(foo)+',
+                               replace: 'X',
+                               regex: true,
+                               expected: 'X bar Xq.X Xb'
+                       }
+               ];
+
+       QUnit.expect( cases.length );
+
+       surface.getToolbarDialogs().getWindow( 'findAndReplace' ).done( 
function ( dialog ) {
+               dialog.open( {
+                       surface: surface,
+                       fragment: surface.getModel().getFragment()
+               } ).done( function () {
+                       var i;
+                       for ( i = 0; i < cases.length; i++ ) {
+                               dialog.matchCaseToggle.setValue( 
!!cases[i].matchCase );
+                               dialog.regexToggle.setValue( !!cases[i].regex );
+                               dialog.findText.setValue( cases[i].find );
+                               dialog.replaceText.setValue( cases[i].replace );
+                               dialog.onReplaceAllButtonClick();
+                               assert.strictEqual( 
surface.getModel().getDocument().data.getText(), cases[i].expected, 
cases[i].msg );
+                               dialog.findText.setValue( '' );
+                               dialog.replaceText.setValue( '' );
+                       }
+                       done();
+               } );
+       } );
+
+} );

-- 
To view, visit https://gerrit.wikimedia.org/r/215632
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ib691455adb9c1dcd6ccfc726b499e1a878ae77c6
Gerrit-PatchSet: 5
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Divec <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to