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