1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * 3 * ***** BEGIN LICENSE BLOCK ***** 4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 5 * 6 * The contents of this file are subject to the Mozilla Public License Version 7 * 1.1 (the "License"); you may not use this file except in compliance with 8 * the License. You may obtain a copy of the License at 9 * http://www.mozilla.org/MPL/ 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 * 16 * The Original Code is Mozilla Communicator client code, released 17 * March 31, 1998. 18 * 19 * The Initial Developer of the Original Code is 20 * Netscape Communications Corporation. 21 * Portions created by the Initial Developer are Copyright (C) 1998 22 * the Initial Developer. All Rights Reserved. 23 * 24 * Contributor(s): 25 * Rob Ginda rginda (at) netscape.com 26 * Bob Clary bob (at) bclary.com 27 * 28 * Alternatively, the contents of this file may be used under the terms of 29 * either the GNU General Public License Version 2 or later (the "GPL"), or 30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 31 * in which case the provisions of the GPL or the LGPL are applicable instead 32 * of those above. If you wish to allow use of your version of this file only 33 * under the terms of either the GPL or the LGPL, and not to allow others to 34 * use your version of this file under the terms of the MPL, indicate your 35 * decision by deleting the provisions above and replace them with the notice 36 * and other provisions required by the GPL or the LGPL. If you do not delete 37 * the provisions above, a recipient may use your version of this file under 38 * the terms of any one of the MPL, the GPL or the LGPL. 39 * 40 * ***** END LICENSE BLOCK ***** */ 41 42 var FAILED = "FAILED!: "; 43 var STATUS = "STATUS: "; 44 var BUGNUMBER = "BUGNUMBER: "; 45 var VERBOSE = false; 46 var SECT_PREFIX = 'Section '; 47 var SECT_SUFFIX = ' of test -'; 48 var callStack = new Array(); 49 50 function writeLineToLog( string ) { 51 print( string + "\n"); 52 } 53 /* 54 * The test driver searches for such a phrase in the test output. 55 * If such phrase exists, it will set n as the expected exit code. 56 */ 57 function expectExitCode(n) 58 { 59 60 writeLineToLog('--- NOTE: IN THIS TESTCASE, WE EXPECT EXIT CODE ' + n + ' ---'); 61 62 } 63 64 /* 65 * Statuses current section of a test 66 */ 67 function inSection(x) 68 { 69 70 return SECT_PREFIX + x + SECT_SUFFIX; 71 72 } 73 74 /* 75 * Some tests need to know if we are in Rhino as opposed to SpiderMonkey 76 */ 77 function inRhino() 78 { 79 return (typeof defineClass == "function"); 80 } 81 82 /* 83 * Report a failure in the 'accepted' manner 84 */ 85 function reportFailure (msg) 86 { 87 var lines = msg.split ("\n"); 88 var l; 89 var funcName = currentFunc(); 90 var prefix = (funcName) ? "[reported from " + funcName + "] ": ""; 91 92 for (var i=0; i<lines.length; i++) 93 writeLineToLog (FAILED + prefix + lines[i]); 94 95 } 96 97 /* 98 * Print a non-failure message. 99 */ 100 function printStatus (msg) 101 { 102 msg = String(msg); 103 msg = msg.toString(); 104 var lines = msg.split ("\n"); 105 var l; 106 107 for (var i=0; i<lines.length; i++) 108 writeLineToLog (STATUS + lines[i]); 109 110 } 111 112 /* 113 * Print a bugnumber message. 114 */ 115 function printBugNumber (num) 116 { 117 118 writeLineToLog (BUGNUMBER + num); 119 120 } 121 122 /* 123 * Compare expected result to actual result, if they differ (in value and/or 124 * type) report a failure. If description is provided, include it in the 125 * failure report. 126 */ 127 function reportCompare (expected, actual, description) 128 { 129 var expected_t = typeof expected; 130 var actual_t = typeof actual; 131 var output = ""; 132 133 if ((VERBOSE) && (typeof description != "undefined")) 134 printStatus ("Comparing '" + description + "'"); 135 136 if (expected_t != actual_t) 137 output += "Type mismatch, expected type " + expected_t + 138 ", actual type " + actual_t + "\n"; 139 else if (VERBOSE) 140 printStatus ("Expected type '" + actual_t + "' matched actual " + 141 "type '" + expected_t + "'"); 142 143 if (expected != actual) 144 output += "Expected value '" + expected + "', Actual value '" + actual + 145 "'\n"; 146 else if (VERBOSE) 147 printStatus ("Expected value '" + actual + "' matched actual " + 148 "value '" + expected + "'"); 149 150 if (output != "") 151 { 152 if (typeof description != "undefined") 153 reportFailure (description); 154 reportFailure (output); 155 } 156 return (output == ""); // true if passed 157 } 158 159 /* 160 * Puts funcName at the top of the call stack. This stack is used to show 161 * a function-reported-from field when reporting failures. 162 */ 163 function enterFunc (funcName) 164 { 165 166 if (!funcName.match(/\(\)$/)) 167 funcName += "()"; 168 169 callStack.push(funcName); 170 171 } 172 173 /* 174 * Pops the top funcName off the call stack. funcName is optional, and can be 175 * used to check push-pop balance. 176 */ 177 function exitFunc (funcName) 178 { 179 var lastFunc = callStack.pop(); 180 181 if (funcName) 182 { 183 if (!funcName.match(/\(\)$/)) 184 funcName += "()"; 185 186 if (lastFunc != funcName) 187 reportFailure ("Test driver failure, expected to exit function '" + 188 funcName + "' but '" + lastFunc + "' came off " + 189 "the stack"); 190 } 191 192 } 193 194 /* 195 * Peeks at the top of the call stack. 196 */ 197 function currentFunc() 198 { 199 200 return callStack[callStack.length - 1]; 201 202 } 203 204 /* 205 Calculate the "order" of a set of data points {X: [], Y: []} 206 by computing successive "derivatives" of the data until 207 the data is exhausted or the derivative is linear. 208 */ 209 function BigO(data) 210 { 211 var order = 0; 212 var origLength = data.X.length; 213 214 while (data.X.length > 2) 215 { 216 var lr = new LinearRegression(data); 217 if (lr.b > 1e-6) 218 { 219 // only increase the order if the slope 220 // is "great" enough 221 order++; 222 } 223 224 if (lr.r > 0.98 || lr.Syx < 1 || lr.b < 1e-6) 225 { 226 // terminate if close to a line lr.r 227 // small error lr.Syx 228 // small slope lr.b 229 break; 230 } 231 data = dataDeriv(data); 232 } 233 234 if (2 == origLength - order) 235 { 236 order = Number.POSITIVE_INFINITY; 237 } 238 return order; 239 240 function LinearRegression(data) 241 { 242 /* 243 y = a + bx 244 for data points (Xi, Yi); 0 <= i < n 245 246 b = (n*SUM(XiYi) - SUM(Xi)*SUM(Yi))/(n*SUM(Xi*Xi) - SUM(Xi)*SUM(Xi)) 247 a = (SUM(Yi) - b*SUM(Xi))/n 248 */ 249 var i; 250 251 if (data.X.length != data.Y.length) 252 { 253 throw 'LinearRegression: data point length mismatch'; 254 } 255 if (data.X.length < 3) 256 { 257 throw 'LinearRegression: data point length < 2'; 258 } 259 var n = data.X.length; 260 var X = data.X; 261 var Y = data.Y; 262 263 this.Xavg = 0; 264 this.Yavg = 0; 265 266 var SUM_X = 0; 267 var SUM_XY = 0; 268 var SUM_XX = 0; 269 var SUM_Y = 0; 270 var SUM_YY = 0; 271 272 for (i = 0; i < n; i++) 273 { 274 SUM_X += X[i]; 275 SUM_XY += X[i]*Y[i]; 276 SUM_XX += X[i]*X[i]; 277 SUM_Y += Y[i]; 278 SUM_YY += Y[i]*Y[i]; 279 } 280 281 this.b = (n * SUM_XY - SUM_X * SUM_Y)/(n * SUM_XX - SUM_X * SUM_X); 282 this.a = (SUM_Y - this.b * SUM_X)/n; 283 284 this.Xavg = SUM_X/n; 285 this.Yavg = SUM_Y/n; 286 287 var SUM_Ydiff2 = 0; 288 var SUM_Xdiff2 = 0; 289 var SUM_XdiffYdiff = 0; 290 291 for (i = 0; i < n; i++) 292 { 293 var Ydiff = Y[i] - this.Yavg; 294 var Xdiff = X[i] - this.Xavg; 295 296 SUM_Ydiff2 += Ydiff * Ydiff; 297 SUM_Xdiff2 += Xdiff * Xdiff; 298 SUM_XdiffYdiff += Xdiff * Ydiff; 299 } 300 301 var Syx2 = (SUM_Ydiff2 - Math.pow(SUM_XdiffYdiff/SUM_Xdiff2, 2))/(n - 2); 302 var r2 = Math.pow((n*SUM_XY - SUM_X * SUM_Y), 2) / 303 ((n*SUM_XX - SUM_X*SUM_X)*(n*SUM_YY-SUM_Y*SUM_Y)); 304 305 this.Syx = Math.sqrt(Syx2); 306 this.r = Math.sqrt(r2); 307 308 } 309 310 function dataDeriv(data) 311 { 312 if (data.X.length != data.Y.length) 313 { 314 throw 'length mismatch'; 315 } 316 var length = data.X.length; 317 318 if (length < 2) 319 { 320 throw 'length ' + length + ' must be >= 2'; 321 } 322 var X = data.X; 323 var Y = data.Y; 324 325 var deriv = {X: [], Y: [] }; 326 327 for (var i = 0; i < length - 1; i++) 328 { 329 deriv.X[i] = (X[i] + X[i+1])/2; 330 deriv.Y[i] = (Y[i+1] - Y[i])/(X[i+1] - X[i]); 331 } 332 return deriv; 333 } 334 335 } 336 337 /* JavaScriptOptions 338 encapsulate the logic for setting and retrieving the values 339 of the javascript options. 340 341 Note: in shell, options() takes an optional comma delimited list 342 of option names, toggles the values for each option and returns the 343 list of option names which were set before the call. 344 If no argument is passed to options(), it returns the current 345 options with value true. 346 347 Usage; 348 349 // create and initialize object. 350 jsOptions = new JavaScriptOptions(); 351 352 // set a particular option 353 jsOptions.setOption(name, boolean); 354 355 // reset all options to their original values. 356 jsOptions.reset(); 357 */ 358 359 function JavaScriptOptions() 360 { 361 this.orig = {}; 362 this.orig.strict = this.strict = false; 363 this.orig.werror = this.werror = false; 364 365 this.privileges = 'UniversalXPConnect'; 366 367 if (typeof options == 'function') 368 { 369 // shell 370 var optString = options(); 371 if (optString) 372 { 373 var optList = optString.split(','); 374 for (iOpt = 0; i < optList.length; iOpt++) 375 { 376 optName = optList[iOpt]; 377 this[optName] = true; 378 } 379 } 380 } 381 else if (typeof document != 'undefined') 382 { 383 // browser 384 netscape.security.PrivilegeManager.enablePrivilege(this.privileges); 385 386 var preferences = Components.classes['@mozilla.org/preferences;1']; 387 if (!preferences) 388 { 389 throw 'JavaScriptOptions: unable to get @mozilla.org/preference;1'; 390 } 391 392 var prefService = preferences. 393 getService(Components.interfaces.nsIPrefService); 394 395 if (!prefService) 396 { 397 throw 'JavaScriptOptions: unable to get nsIPrefService'; 398 } 399 400 var pref = prefService.getBranch(''); 401 402 if (!pref) 403 { 404 throw 'JavaScriptOptions: unable to get prefService branch'; 405 } 406 407 try 408 { 409 this.orig.strict = this.strict = 410 pref.getBoolPref('javascript.options.strict'); 411 } 412 catch(e) 413 { 414 } 415 416 try 417 { 418 this.orig.werror = this.werror = 419 pref.getBoolPref('javascript.options.werror'); 420 } 421 catch(e) 422 { 423 } 424 } 425 } 426 427 JavaScriptOptions.prototype.setOption = 428 function (optionName, optionValue) 429 { 430 if (typeof options == 'function') 431 { 432 // shell 433 if (this[optionName] != optionValue) 434 { 435 options(optionName); 436 } 437 } 438 else if (typeof document != 'undefined') 439 { 440 // browser 441 netscape.security.PrivilegeManager.enablePrivilege(this.privileges); 442 443 var preferences = Components.classes['@mozilla.org/preferences;1']; 444 if (!preferences) 445 { 446 throw 'setOption: unable to get @mozilla.org/preference;1'; 447 } 448 449 var prefService = preferences. 450 getService(Components.interfaces.nsIPrefService); 451 452 if (!prefService) 453 { 454 throw 'setOption: unable to get nsIPrefService'; 455 } 456 457 var pref = prefService.getBranch(''); 458 459 if (!pref) 460 { 461 throw 'setOption: unable to get prefService branch'; 462 } 463 464 pref.setBoolPref('javascript.options.' + optionName, optionValue); 465 } 466 467 this[optionName] = optionValue; 468 469 return; 470 } 471 472 473 JavaScriptOptions.prototype.reset = function () 474 { 475 this.setOption('strict', this.orig.strict); 476 this.setOption('werror', this.orig.werror); 477 } 478