Home | History | Annotate | Download | only in RegExp
      1 /* ***** BEGIN LICENSE BLOCK *****
      2 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
      3 *
      4 * The contents of this file are subject to the Netscape Public License
      5 * Version 1.1 (the "License"); you may not use this file except in
      6 * compliance with the License. You may obtain a copy of the License at
      7 * http://www.mozilla.org/NPL/
      8 *
      9 * Software distributed under the License is distributed on an "AS IS" basis,
     10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     11 * for the specific language governing rights and limitations under the
     12 * License.
     13 *
     14 * The Original Code is JavaScript Engine testing utilities.
     15 *
     16 * The Initial Developer of the Original Code is Netscape Communications Corp.
     17 * Portions created by the Initial Developer are Copyright (C) 2002
     18 * the Initial Developer. All Rights Reserved.
     19 *
     20 * Contributor(s): pschwartau (at) netscape.com
     21 *
     22 * Alternatively, the contents of this file may be used under the terms of
     23 * either the GNU General Public License Version 2 or later (the "GPL"), or
     24 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
     25 * in which case the provisions of the GPL or the LGPL are applicable instead
     26 * of those above. If you wish to allow use of your version of this file only
     27 * under the terms of either the GPL or the LGPL, and not to allow others to
     28 * use your version of this file under the terms of the NPL, indicate your
     29 * decision by deleting the provisions above and replace them with the notice
     30 * and other provisions required by the GPL or the LGPL. If you do not delete
     31 * the provisions above, a recipient may use your version of this file under
     32 * the terms of any one of the NPL, the GPL or the LGPL.
     33 *
     34 * ***** END LICENSE BLOCK *****
     35 *
     36 *
     37 * Date:    18 Feb 2002
     38 * SUMMARY: Testing re.exec(str) when re.lastIndex is < 0 or > str.length
     39 *
     40 * Case 1: If re has the global flag set, then re(str) should be null
     41 * Case 2: If re doesn't have this set, then re(str) should be unaffected
     42 *
     43 * See http://bugzilla.mozilla.org/show_bug.cgi?id=76717
     44 *
     45 *
     46 * From the ECMA-262 Final spec:
     47 *
     48 * 15.10.6.2 RegExp.prototype.exec(string)
     49 * Performs a regular expression match of string against the regular
     50 * expression and returns an Array object containing the results of
     51 * the match, or null if the string did not match.
     52 *
     53 * The string ToString(string) is searched for an occurrence of the
     54 * regular expression pattern as follows:
     55 *
     56 * 1.  Let S be the value of ToString(string).
     57 * 2.  Let length be the length of S.
     58 * 3.  Let lastIndex be the value of the lastIndex property.
     59 * 4.  Let i be the value of ToInteger(lastIndex).
     60 * 5.  If the global property is false, let i = 0.
     61 * 6.  If i < 0 or i > length then set lastIndex to 0 and return null.
     62 * 7.  Call [[Match]], giving it the arguments S and i.
     63 *     If [[Match]] returned failure, go to step 8;
     64 *     otherwise let r be its State result and go to step 10.
     65 * 8.  Let i = i+1.
     66 * 9.  Go to step 6.
     67 * 10. Let e be r's endIndex value.
     68 * 11. If the global property is true, set lastIndex to e.
     69 *
     70 *          etc.
     71 *
     72 *
     73 * So:
     74 *
     75 * A. If the global flag is not set, |lastIndex| is set to 0
     76 *    before the match is attempted; thus the match is unaffected.
     77 *
     78 * B. If the global flag IS set and re.lastIndex is >= 0 and <= str.length,
     79 *    |lastIndex| is incremented every time there is a match; not from
     80 *    i to i+1, but from i to "endIndex" e:
     81 *
     82 *      e = (index of last input character matched so far by the pattern) + 1
     83 *
     84 *    The match is then attempted from this position in the string (Step 7).
     85 *
     86 * C. When the global flag IS set and re.lastIndex is < 0 or > str.length,
     87 *    |lastIndex| is set to 0 and the match returns null.
     88 *
     89 *
     90 * Note the |lastIndex| property is writeable, and may be set arbitrarily
     91 * by the programmer - and we will do that below.
     92 *
     93 */
     94 //-----------------------------------------------------------------------------
     95 var i = 0;
     96 var bug = 76717;
     97 var summary = 'Testing re.exec(str) when re.lastIndex is < 0 or > str.length';
     98 var status = '';
     99 var statusmessages = new Array();
    100 var pattern = '';
    101 var patterns = new Array();
    102 var string = '';
    103 var strings = new Array();
    104 var actualmatch = '';
    105 var actualmatches = new Array();
    106 var expectedmatch = '';
    107 var expectedmatches = new Array();
    108 
    109 
    110 /******************************************************************************
    111  *
    112  * Case 1 : when the global flag is set -
    113  *
    114  *****************************************************************************/
    115 pattern = /abc/gi;
    116 string = 'AbcaBcabC';
    117 
    118   status = inSection(1);
    119   actualmatch = pattern.exec(string);
    120   expectedmatch = Array('Abc');
    121   addThis();
    122 
    123   status = inSection(2);
    124   actualmatch = pattern.exec(string);
    125   expectedmatch = Array('aBc');
    126   addThis();
    127 
    128   status = inSection(3);
    129   actualmatch = pattern.exec(string);
    130   expectedmatch = Array('abC');
    131   addThis();
    132 
    133   /*
    134    * At this point |lastIndex| is > string.length, so the match should be null -
    135    */
    136   status = inSection(4);
    137   actualmatch = pattern.exec(string);
    138   expectedmatch = null;
    139   addThis();
    140 
    141   /*
    142    * Now let's set |lastIndex| to -1, so the match should again be null -
    143    */
    144   status = inSection(5);
    145   pattern.lastIndex = -1;
    146   actualmatch = pattern.exec(string);
    147   expectedmatch = null;
    148   addThis();
    149 
    150   /*
    151    * Now try some edge-case values. Thanks to the work done in
    152    * http://bugzilla.mozilla.org/show_bug.cgi?id=124339, |lastIndex|
    153    * is now stored as a double instead of a uint32 (unsigned integer).
    154    *
    155    * Note 2^32 -1 is the upper bound for uint32's, but doubles can go
    156    * all the way up to Number.MAX_VALUE. So that's why we need cases
    157    * between those two numbers.
    158    */
    159   status = inSection(6);
    160   pattern.lastIndex = Math.pow(2,32);
    161   actualmatch = pattern.exec(string);
    162   expectedmatch = null;
    163   addThis();
    164 
    165   status = inSection(7);
    166   pattern.lastIndex = -Math.pow(2,32);
    167   actualmatch = pattern.exec(string);
    168   expectedmatch = null;
    169   addThis();
    170 
    171   status = inSection(8);
    172   pattern.lastIndex = Math.pow(2,32) + 1;
    173   actualmatch = pattern.exec(string);
    174   expectedmatch = null;
    175   addThis();
    176 
    177   status = inSection(9);
    178   pattern.lastIndex = -(Math.pow(2,32) + 1);
    179   actualmatch = pattern.exec(string);
    180   expectedmatch = null;
    181   addThis();
    182 
    183   status = inSection(10);
    184   pattern.lastIndex = Math.pow(2,32) * 2;
    185   actualmatch = pattern.exec(string);
    186   expectedmatch = null;
    187   addThis();
    188 
    189   status = inSection(11);
    190   pattern.lastIndex = -Math.pow(2,32) * 2;
    191   actualmatch = pattern.exec(string);
    192   expectedmatch = null;
    193   addThis();
    194 
    195   status = inSection(12);
    196   pattern.lastIndex = Math.pow(2,40);
    197   actualmatch = pattern.exec(string);
    198   expectedmatch = null;
    199   addThis();
    200 
    201   status = inSection(13);
    202   pattern.lastIndex = -Math.pow(2,40);
    203   actualmatch = pattern.exec(string);
    204   expectedmatch = null;
    205   addThis();
    206 
    207   status = inSection(14);
    208   pattern.lastIndex = Number.MAX_VALUE;
    209   actualmatch = pattern.exec(string);
    210   expectedmatch = null;
    211   addThis();
    212 
    213   status = inSection(15);
    214   pattern.lastIndex = -Number.MAX_VALUE;
    215   actualmatch = pattern.exec(string);
    216   expectedmatch = null;
    217   addThis();
    218 
    219 
    220 
    221 /******************************************************************************
    222  *
    223  * Case 2: repeat all the above cases WITHOUT the global flag set.
    224  * According to EMCA. |lastIndex| should get set to 0 before the match.
    225  *
    226  * Therefore re.exec(str) should be unaffected; thus our expected values
    227  * below are now DIFFERENT when |lastIndex| is < 0 or > str.length
    228  *
    229  *****************************************************************************/
    230 
    231 pattern = /abc/i;
    232 string = 'AbcaBcabC';
    233 
    234   status = inSection(16);
    235   actualmatch = pattern.exec(string);
    236   expectedmatch = Array('Abc');
    237   addThis();
    238 
    239   status = inSection(17);
    240   actualmatch = pattern.exec(string);
    241   expectedmatch = Array('Abc'); // NOT Array('aBc') as before -
    242   addThis();
    243 
    244   status = inSection(18);
    245   actualmatch = pattern.exec(string);
    246   expectedmatch = Array('Abc'); // NOT Array('abC') as before -
    247   addThis();
    248 
    249   /*
    250    * At this point above, |lastIndex| WAS > string.length, but not here -
    251    */
    252   status = inSection(19);
    253   actualmatch = pattern.exec(string);
    254   expectedmatch = Array('Abc') // NOT null as before -
    255   addThis();
    256 
    257   /*
    258    * Now let's set |lastIndex| to -1
    259    */
    260   status = inSection(20);
    261   pattern.lastIndex = -1;
    262   actualmatch = pattern.exec(string);
    263   expectedmatch = Array('Abc') // NOT null as before -
    264   addThis();
    265 
    266   /*
    267    * Now try some edge-case values. Thanks to the work done in
    268    * http://bugzilla.mozilla.org/show_bug.cgi?id=124339, |lastIndex|
    269    * is now stored as a double instead of a uint32 (unsigned integer).
    270    *
    271    * Note 2^32 -1 is the upper bound for uint32's, but doubles can go
    272    * all the way up to Number.MAX_VALUE. So that's why we need cases
    273    * between those two numbers.
    274    */
    275   status = inSection(21);
    276   pattern.lastIndex = Math.pow(2,32);
    277   actualmatch = pattern.exec(string);
    278   expectedmatch = Array('Abc') // NOT null as before -
    279   addThis();
    280 
    281   status = inSection(22);
    282   pattern.lastIndex = -Math.pow(2,32);
    283   actualmatch = pattern.exec(string);
    284   expectedmatch = Array('Abc') // NOT null as before -
    285   addThis();
    286 
    287   status = inSection(23);
    288   pattern.lastIndex = Math.pow(2,32) + 1;
    289   actualmatch = pattern.exec(string);
    290   expectedmatch = Array('Abc') // NOT null as before -
    291   addThis();
    292 
    293   status = inSection(24);
    294   pattern.lastIndex = -(Math.pow(2,32) + 1);
    295   actualmatch = pattern.exec(string);
    296   expectedmatch = Array('Abc') // NOT null as before -
    297   addThis();
    298 
    299   status = inSection(25);
    300   pattern.lastIndex = Math.pow(2,32) * 2;
    301   actualmatch = pattern.exec(string);
    302   expectedmatch = Array('Abc') // NOT null as before -
    303   addThis();
    304 
    305   status = inSection(26);
    306   pattern.lastIndex = -Math.pow(2,32) * 2;
    307   actualmatch = pattern.exec(string);
    308   expectedmatch = Array('Abc') // NOT null as before -
    309   addThis();
    310 
    311   status = inSection(27);
    312   pattern.lastIndex = Math.pow(2,40);
    313   actualmatch = pattern.exec(string);
    314   expectedmatch = Array('Abc') // NOT null as before -;
    315   addThis();
    316 
    317   status = inSection(28);
    318   pattern.lastIndex = -Math.pow(2,40);
    319   actualmatch = pattern.exec(string);
    320   expectedmatch = Array('Abc') // NOT null as before -
    321   addThis();
    322 
    323   status = inSection(29);
    324   pattern.lastIndex = Number.MAX_VALUE;
    325   actualmatch = pattern.exec(string);
    326   expectedmatch = Array('Abc') // NOT null as before -
    327   addThis();
    328 
    329   status = inSection(30);
    330   pattern.lastIndex = -Number.MAX_VALUE;
    331   actualmatch = pattern.exec(string);
    332   expectedmatch = Array('Abc') // NOT null as before -
    333   addThis();
    334 
    335 
    336 
    337 
    338 //-------------------------------------------------------------------------------------------------
    339 test();
    340 //-------------------------------------------------------------------------------------------------
    341 
    342 
    343 
    344 function addThis()
    345 {
    346   statusmessages[i] = status;
    347   patterns[i] = pattern;
    348   strings[i] = string;
    349   actualmatches[i] = actualmatch;
    350   expectedmatches[i] = expectedmatch;
    351   i++;
    352 }
    353 
    354 
    355 function test()
    356 {
    357   enterFunc ('test');
    358   printBugNumber (bug);
    359   printStatus (summary);
    360   testRegExp(statusmessages, patterns, strings, actualmatches, expectedmatches);
    361   exitFunc ('test');
    362 }
    363