jquery.byteLimit: Fix infinite loop if text is longer than max
[lhc/web/wiklou.git] / tests / qunit / suites / resources / jquery / jquery.byteLimit.test.js
index 2990de2..596c57c 100644 (file)
        // Basic sendkey-implementation
        function addChars( $input, charstr ) {
                var c, len;
+
                function x( $input, i ) {
                        // Add character to the value
                        return $input.val() + charstr.charAt( i );
                }
+
                for ( c = 0, len = charstr.length; c < len; c += 1 ) {
                        $input
                                .val( x( $input, c ) )
        /**
         * Test factory for $.fn.byteLimit
         *
-        * @param $input {jQuery} jQuery object in an input element
-        * @param hasLimit {Boolean} Wether a limit should apply at all
-        * @param limit {Number} Limit (if used) otherwise undefined
-        * The limit should be less than 20 (the sample data's length)
+        * @param {Object} options
+        * @param {string} options.description Test name
+        * @param {jQuery} options.$input jQuery object in an input element
+        * @param {string} options.sample Sequence of characters to simulate being
+        *  added one by one
+        * @param {string} options.expected Expected final value of `$input`
         */
        function byteLimitTest( options ) {
-               var opt = $.extend({
+               var opt = $.extend( {
                        description: '',
                        $input: null,
                        sample: '',
-                       hasLimit: false,
-                       expected: '',
-                       limit: null
-               }, options);
-
-               QUnit.asyncTest( opt.description, opt.hasLimit ? 3 : 2, function ( assert ) {
-               setTimeout( function () {
-                       var rawVal, fn, effectiveVal;
+                       expected: ''
+               }, options );
 
-                       opt.$input.appendTo( '#qunit-fixture' );
+               QUnit.asyncTest( opt.description, 1, function ( assert ) {
+                       setTimeout( function () {
+                               opt.$input.appendTo( '#qunit-fixture' );
 
-                       // Simulate pressing keys for each of the sample characters
-                       addChars( opt.$input, opt.sample );
+                               // Simulate pressing keys for each of the sample characters
+                               addChars( opt.$input, opt.sample );
 
-                       rawVal = opt.$input.val();
-                       fn = opt.$input.data( 'byteLimit.callback' );
-                       effectiveVal = fn ? fn( rawVal ) : rawVal;
-
-                       if ( opt.hasLimit ) {
-                               assert.ltOrEq(
-                                       $.byteLength( effectiveVal ),
-                                       opt.limit,
-                                       'Prevent keypresses after byteLimit was reached, length never exceeded the limit'
-                               );
                                assert.equal(
-                                       $.byteLength( rawVal ),
-                                       $.byteLength( opt.expected ),
-                                       'Not preventing keypresses too early, length has reached the expected length'
+                                       opt.$input.val(),
+                                       opt.expected,
+                                       'New value matches the expected string'
                                );
-                               assert.equal( rawVal, opt.expected, 'New value matches the expected string' );
 
-                       } else {
-                               assert.equal(
-                                       $.byteLength( effectiveVal ),
-                                       $.byteLength( opt.expected ),
-                                       'Unlimited scenarios are not affected, expected length reached'
-                               );
-                               assert.equal( rawVal, opt.expected, 'New value matches the expected string' );
-                       }
-                       QUnit.start();
-               }, 10 );
+                               QUnit.start();
+                       }, 10 );
                } );
        }
 
-       byteLimitTest({
+       byteLimitTest( {
                description: 'Plain text input',
                $input: $( '<input type="text"/>' ),
                sample: simpleSample,
-               hasLimit: false,
                expected: simpleSample
-       });
+       } );
 
-       byteLimitTest({
+       byteLimitTest( {
                description: 'Plain text input. Calling byteLimit with no parameters and no maxlength attribute (bug 36310)',
                $input: $( '<input type="text"/>' )
                        .byteLimit(),
                sample: simpleSample,
-               hasLimit: false,
                expected: simpleSample
-       });
+       } );
 
-       byteLimitTest({
+       byteLimitTest( {
                description: 'Limit using the maxlength attribute',
                $input: $( '<input type="text"/>' )
                        .attr( 'maxlength', '10' )
                        .byteLimit(),
                sample: simpleSample,
-               hasLimit: true,
-               limit: 10,
                expected: '1234567890'
-       });
+       } );
 
-       byteLimitTest({
+       byteLimitTest( {
                description: 'Limit using a custom value',
                $input: $( '<input type="text"/>' )
                        .byteLimit( 10 ),
                sample: simpleSample,
-               hasLimit: true,
-               limit: 10,
                expected: '1234567890'
-       });
+       } );
 
-       byteLimitTest({
+       byteLimitTest( {
                description: 'Limit using a custom value, overriding maxlength attribute',
                $input: $( '<input type="text"/>' )
                        .attr( 'maxlength', '10' )
                        .byteLimit( 15 ),
                sample: simpleSample,
-               hasLimit: true,
-               limit: 15,
                expected: '123456789012345'
-       });
+       } );
 
-       byteLimitTest({
+       byteLimitTest( {
                description: 'Limit using a custom value (multibyte)',
                $input: $( '<input type="text"/>' )
                        .byteLimit( 14 ),
                sample: mbSample,
-               hasLimit: true,
-               limit: 14,
                expected: '1234567890' + U_20AC + '1'
-       });
+       } );
 
-       byteLimitTest({
+       byteLimitTest( {
                description: 'Limit using a custom value (multibyte) overlapping a byte',
                $input: $( '<input type="text"/>' )
                        .byteLimit( 12 ),
                sample: mbSample,
-               hasLimit: true,
-               limit: 12,
                expected: '1234567890' + '12'
-       });
+       } );
 
-       byteLimitTest({
+       byteLimitTest( {
                description: 'Pass the limit and a callback as input filter',
                $input: $( '<input type="text"/>' )
                        .byteLimit( 6, function ( val ) {
                                return new mw.Title( String( val ) ).getMain();
                        } ),
                sample: 'User:Sample',
-               hasLimit: true,
-               limit: 6, // 'Sample' length
                expected: 'User:Sample'
-       });
+       } );
 
-       byteLimitTest({
+       byteLimitTest( {
                description: 'Limit using the maxlength attribute and pass a callback as input filter',
                $input: $( '<input type="text"/>' )
                        .attr( 'maxlength', '6' )
                                return new mw.Title( String( val ) ).getMain();
                        } ),
                sample: 'User:Sample',
-               hasLimit: true,
-               limit: 6, // 'Sample' length
                expected: 'User:Sample'
-       });
+       } );
+
+       byteLimitTest( {
+               description: 'Pass the limit and a callback as input filter',
+               $input: $( '<input type="text"/>' )
+                       .byteLimit( 6, function ( val ) {
+                               // Invalid title
+                               if ( val === '' ) {
+                                       return '';
+                               }
+
+                               // Return without namespace prefix
+                               return new mw.Title( String( val ) ).getMain();
+                       } ),
+               sample: 'User:Example',
+               // The callback alters the value to be used to calculeate
+               // the length. The altered value is "Exampl" which has
+               // a length of 6, the "e" would exceed the limit.
+               expected: 'User:Exampl'
+       } );
+
+       byteLimitTest( {
+               description: 'Input filter that increases the length',
+               $input: $( '<input type="text"/>' )
+               .byteLimit( 10, function ( text ) {
+                       return 'prefix' + text;
+               } ),
+               sample: simpleSample,
+               // Prefix adds 6 characters, limit is reached after 4
+               expected: '1234'
+       } );
+
+       // Regression tests for bug 41450
+       byteLimitTest( {
+               description: 'Input filter of which the base exceeds the limit',
+               $input: $( '<input type="text"/>' )
+               .byteLimit( 3, function ( text ) {
+                       return 'prefix' + text;
+               } ),
+               sample: simpleSample,
+               hasLimit: true,
+               limit: 6, // 'prefix' length
+               expected: ''
+       } );
 
        QUnit.test( 'Confirm properties and attributes set', 4, function ( assert ) {
                var $el, $elA, $elB;
                assert.strictEqual( $el.length, 2, 'Verify that there are no other elements clashing with this test suite' );
 
                $el.byteLimit();
-       });
+       } );
 
        QUnit.test( 'Trim from insertion when limit exceeded', 2, function ( assert ) {
                var $el;
                        .val( 'azbc' ).trigger( 'change' );
 
                assert.strictEqual( $el.val(), 'abc', 'Trim from the insertion point (at 1), not the end' );
-       });
-
+       } );
 }( jQuery, mediaWiki ) );