added browser tests [ci skip]

This commit is contained in:
SheetJS 2016-10-14 01:24:43 -04:00
parent f5a6d10ce4
commit 3eedb7e584
14 changed files with 37051 additions and 27 deletions

2
.gitignore vendored

@ -1,3 +1,3 @@
node_modules
misc/coverage.html
ctest/sauce*

@ -2,6 +2,7 @@ LIB=printj
REQS=loop_code
ADDONS=
AUXTARGETS=lib/loop_char.js lib/loop_code.js lib/index_char.js lib/index_code.js lib/regex.js
CMDS=bin/printj.njs
HTMLLINT=index.html
ULIB=$(shell echo $(LIB) | tr a-z A-Z)
@ -18,7 +19,7 @@ all: $(TARGET) ## Build library and auxiliary scripts
lib:
OUTDIR=$(PWD)/lib make -C bits
$(TARGET): %.js : %.flow.js
$(TARGET) $(AUXTARGETS): %.js : %.flow.js
node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^[ \t]*\/\*[:#][^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*[:#][^*]*\*\//gm,""))' > $@
$(FLOWTARGET): $(DEPS) lib
@ -38,6 +39,16 @@ clean: clean-stress ## Remove targets and build artifacts
test mocha: test.js $(TARGET) ## Run test suite
mocha -R spec -t 20000
.PHONY: ctest
ctest: ## Build browser test (into ctest/ subdirectory)
cp -f test.js ctest/test.js
cp -f shim.js ctest/shim.js
cp -f $(TARGET) ctest/
.PHONY: ctestserv
ctestserv: ## Start a test server on port 8000
@cd ctest && python -mSimpleHTTPServer
.PHONY: stress ## Run stress tests
stress:
@make -C stress clean
@ -51,8 +62,9 @@ clean-stress: ## Remove stress tests
## Code Checking
.PHONY: lint
lint: ## Run jshint and jscs checks
lint: $(TARGET) ## Run jshint and jscs checks
@jshint --show-non-errors $(TARGET) $(AUXTARGETS)
@jshint --show-non-errors $(CMDS)
@jshint --show-non-errors package.json
@jshint --show-non-errors --extract=always $(HTMLLINT)
@jscs lib/*.js

@ -3,7 +3,7 @@
Extended `sprintf` implementation (for the browser and nodejs). Emphasis on
compliance, performance and IE6+ support.
```JS
```js
PRINTJ.sprintf("Hello %s!", "World");
```
@ -93,6 +93,8 @@ granted by the Apache 2.0 license are reserved by the Original Author.
## Badges
[![Build Status](https://saucelabs.com/browser-matrix/printj.svg)](https://saucelabs.com/beta/builds/3b968565c1d942069871fa35eae5162f)
[![Build Status](https://travis-ci.org/SheetJS/printj.svg?branch=master)](https://travis-ci.org/SheetJS/printj)
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/printj/master.svg)](https://coveralls.io/r/SheetJS/printj?branch=master)
@ -967,6 +969,21 @@ JS. When converting C literal strings, there are a few differences in escaping:
| `"\ooo"` (octal) | `"\ooo"` | JS uses Latin-1 for non-ASCII codes |
| `"\xhh"` (hex) | `"\xhh"` | JS uses Latin-1 for non-ASCII codes |
## Browser Deviations
Opera does not always include the last significant digit in base 16 rendering.
For example, `(-6.9e-11).toString(16)` is `"0.000000004bddc5fd160168"` in every
other browser but is `"0.000000004bddc5fd16017"` in Opera. The test suite skips
the `%a/%A` precision-less formats in Opera.
`Object.prototype.toString.call` gives unexpected results in older browsers, and
no attempt is made to correct for them. The test suite ignores those cases:
| value | `%#T` expected | `%#T` IE < 9 | `%#T` Android < 4.4 |
|:------------|:---------------|:-------------|:--------------------|
| `null` | `"Null"` | `"Object"` | `"global"` |
| `undefined` | `"Undefined"` | `"Object"` | `"global"` |
## Support Summary
- Full [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html) conversion support with extensions!

@ -1,6 +1,7 @@
#!/usr/bin/env node
/* printj.js (C) 2016-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2 ft=javascript: */
/*jshint node:true, evil:true */
var X = require("../"), argv = process.argv;
function help() {
@ -47,9 +48,9 @@ function parse_arg(arg/*:string*/)/*:any*/ {
var args/*:Array<any>*/ = [];
var fmt = "", n = 0;
for(var i = 2; i < argv.length; ++i) switch(argv[i]) {
case "--help": case "-h": process.exit(help());
case "--dump": case "-d": if(fmt.length==0) fmt = argv[++i]; process.exit(dump(fmt));
default: if(n++ == 0) fmt = argv[i]; else args.push(parse_arg(argv[i]));
case "--help": case "-h": process.exit(help()); break;
case "--dump": case "-d": if(fmt.length===0) fmt = argv[++i]; process.exit(dump(fmt)); break;
default: if(n++ === 0) fmt = argv[i]; else args.push(parse_arg(argv[i]));
}
console.log(X.vsprintf(fmt, args));

4
ctest/fakeassert.js Normal file

@ -0,0 +1,4 @@
var assert = {};
assert.equal = function(x,y) { if(x !== y) throw new Error(x + " !== " + y); };
assert.throws = function(f) { try { f(); } catch(e) { return; } throw new Error("Function did not fail"); };
assert.doesNotThrow = function(f) { f(); };

29779
ctest/fixtures.js Normal file

File diff suppressed because it is too large Load Diff

22
ctest/index.html Normal file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>Mocha</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="shim.js"></script>
<script src="printj.js"></script>
<script src="fakeassert.js"></script>
<script src="mocha.js"></script>
<script src="fixtures.js"></script>
<script>mocha.setup('bdd')</script>
<script src="test.js"></script>
<script>
mocha.run();
</script>
</body>
</html>

305
ctest/mocha.css Normal file

@ -0,0 +1,305 @@
@charset "utf-8";
body {
margin:0;
}
#mocha {
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 60px 50px;
}
#mocha ul,
#mocha li {
margin: 0;
padding: 0;
}
#mocha ul {
list-style: none;
}
#mocha h1,
#mocha h2 {
margin: 0;
}
#mocha h1 {
margin-top: 15px;
font-size: 1em;
font-weight: 200;
}
#mocha h1 a {
text-decoration: none;
color: inherit;
}
#mocha h1 a:hover {
text-decoration: underline;
}
#mocha .suite .suite h1 {
margin-top: 0;
font-size: .8em;
}
#mocha .hidden {
display: none;
}
#mocha h2 {
font-size: 12px;
font-weight: normal;
cursor: pointer;
}
#mocha .suite {
margin-left: 15px;
}
#mocha .test {
margin-left: 15px;
overflow: hidden;
}
#mocha .test.pending:hover h2::after {
content: '(pending)';
font-family: arial, sans-serif;
}
#mocha .test.pass.medium .duration {
background: #c09853;
}
#mocha .test.pass.slow .duration {
background: #b94a48;
}
#mocha .test.pass::before {
content: '✓';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #00d6b2;
}
#mocha .test.pass .duration {
font-size: 9px;
margin-left: 5px;
padding: 2px 5px;
color: #fff;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
}
#mocha .test.pass.fast .duration {
display: none;
}
#mocha .test.pending {
color: #0b97c4;
}
#mocha .test.pending::before {
content: '◦';
color: #0b97c4;
}
#mocha .test.fail {
color: #c00;
}
#mocha .test.fail pre {
color: black;
}
#mocha .test.fail::before {
content: '✖';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #c00;
}
#mocha .test pre.error {
color: #c00;
max-height: 300px;
overflow: auto;
}
#mocha .test .html-error {
overflow: auto;
color: black;
line-height: 1.5;
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: calc(100% - 42px); /*(2)*/
max-height: 300px;
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-border-radius: 3px;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-border-radius: 3px;
-moz-box-shadow: 0 1px 3px #eee;
border-radius: 3px;
}
#mocha .test .html-error pre.error {
border: none;
-webkit-border-radius: none;
-webkit-box-shadow: none;
-moz-border-radius: none;
-moz-box-shadow: none;
padding: 0;
margin: 0;
margin-top: 18px;
max-height: none;
}
/**
* (1): approximate for browsers not supporting calc
* (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
* ^^ seriously
*/
#mocha .test pre {
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: calc(100% - 42px); /*(2)*/
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-border-radius: 3px;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-border-radius: 3px;
-moz-box-shadow: 0 1px 3px #eee;
border-radius: 3px;
}
#mocha .test h2 {
position: relative;
}
#mocha .test a.replay {
position: absolute;
top: 3px;
right: 0;
text-decoration: none;
vertical-align: middle;
display: block;
width: 15px;
height: 15px;
line-height: 15px;
text-align: center;
background: #eee;
font-size: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
-webkit-transition: opacity 200ms;
-moz-transition: opacity 200ms;
transition: opacity 200ms;
opacity: 0.3;
color: #888;
}
#mocha .test:hover a.replay {
opacity: 1;
}
#mocha-report.pass .test.fail {
display: none;
}
#mocha-report.fail .test.pass {
display: none;
}
#mocha-report.pending .test.pass,
#mocha-report.pending .test.fail {
display: none;
}
#mocha-report.pending .test.pass.pending {
display: block;
}
#mocha-error {
color: #c00;
font-size: 1.5em;
font-weight: 100;
letter-spacing: 1px;
}
#mocha-stats {
position: fixed;
top: 15px;
right: 10px;
font-size: 12px;
margin: 0;
color: #888;
z-index: 1;
}
#mocha-stats .progress {
float: right;
padding-top: 0;
}
#mocha-stats em {
color: black;
}
#mocha-stats a {
text-decoration: none;
color: inherit;
}
#mocha-stats a:hover {
border-bottom: 1px solid #eee;
}
#mocha-stats li {
display: inline-block;
margin: 0 5px;
list-style: none;
padding-top: 11px;
}
#mocha-stats canvas {
width: 40px;
height: 40px;
}
#mocha code .comment { color: #ddd; }
#mocha code .init { color: #2f6fad; }
#mocha code .string { color: #5890ad; }
#mocha code .keyword { color: #8a6343; }
#mocha code .number { color: #2f6fad; }
@media screen and (max-device-width: 480px) {
#mocha {
margin: 60px 0px;
}
#mocha #stats {
position: absolute;
}
}

5842
ctest/mocha.js Normal file

File diff suppressed because it is too large Load Diff

602
ctest/printj.js Normal file

@ -0,0 +1,602 @@
/* printj.js (C) 2016-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint sub:true, eqnull:true */
/*exported PRINTJ */
var PRINTJ;
(function (factory) {
/*jshint ignore:start */
if(typeof DO_NOT_EXPORT_PRINTJ === 'undefined') {
if('object' === typeof exports) {
factory(exports);
} else if ('function' === typeof define && define.amd) {
define(function () {
var module = {};
factory(module);
return module;
});
} else {
factory(PRINTJ = {});
}
} else {
factory(PRINTJ = {});
}
/*jshint ignore:end */
}(function(PRINTJ) {
PRINTJ.version = '0.1.1';
function tokenize(fmt) {
var out = [];
var start = 0;
var i = 0;
var infmt = false;
var fmtparam = "", fmtflags = "", fmtwidth = "", fmtprec = "", fmtlen = "";
var c = 0;
var L = fmt.length;
for(; i < L; ++i) {
c = fmt.charCodeAt(i);
if(!infmt) {
if(c !== 37) continue;
if(start < i) out.push(["L", fmt.substring(start, i)]);
start = i;
infmt = true;
continue;
}
if(c >= 48 && c < 58) {
if(fmtprec.length) fmtprec += String.fromCharCode(c);
else if(c == 48 && !fmtwidth.length) fmtflags += String.fromCharCode(c);
else fmtwidth += String.fromCharCode(c);
} else switch(c) {
/* positional */
case 36:
if(fmtprec.length) fmtprec += "$";
else if(fmtwidth.charAt(0) == "*") fmtwidth += "$";
else { fmtparam = fmtwidth + "$"; fmtwidth = ""; }
break;
/* flags */
case 39: fmtflags += "'"; break;
case 45: fmtflags += "-"; break;
case 43: fmtflags += "+"; break;
case 32: fmtflags += " "; break;
case 35: fmtflags += "#"; break;
/* width and precision */
case 46: fmtprec = "."; break;
case 42:
if(fmtprec.charAt(0) == ".") fmtprec += "*";
else fmtwidth += "*";
break;
/* length */
case 104:
case 108:
if(fmtlen.length > 1) throw "bad length " + fmtlen + String(c);
fmtlen += String.fromCharCode(c);
break;
case 76:
case 106:
case 122:
case 116:
case 113:
case 90:
case 119:
if(fmtlen !== "") throw "bad length " + fmtlen + String.fromCharCode(c);
fmtlen = String.fromCharCode(c);
break;
case 73:
if(fmtlen !== "") throw "bad length " + fmtlen + 'I';
fmtlen = 'I';
break;
/* conversion */
case 100:
case 105:
case 111:
case 117:
case 120:
case 88:
case 102:
case 70:
case 101:
case 69:
case 103:
case 71:
case 97:
case 65:
case 99:
case 67:
case 115:
case 83:
case 112:
case 110:
case 68:
case 85:
case 79:
case 109:
case 98:
case 66:
case 121:
case 89:
case 74:
case 86:
case 84:
case 37:
infmt = false;
if(fmtprec.length > 1) fmtprec = fmtprec.substr(1);
out.push([String.fromCharCode(c), fmt.substring(start, i+1), fmtparam, fmtflags, fmtwidth, fmtprec, fmtlen]);
start = i+1;
fmtlen = fmtprec = fmtwidth = fmtflags = fmtparam = "";
break;
default:
throw new Error("Invalid format string starting with |" + fmt.substring(start, i+1) + "|");
}
}
if(start < fmt.length) out.push(["L", fmt.substring(start)]);
return out;
}
//#define PAD_(x,c) (x >= 0 ? new Array(((x)|0) + 1).join((c)) : "")
var padstr = {
" ": " ",
"0": "000000000000000000000000000000000",
"7": "777777777777777777777777777777777",
"f": "fffffffffffffffffffffffffffffffff"
};
if(typeof util=='undefined' && typeof require!=='undefined')util=require("util");
var u_inspect = (typeof util != 'undefined') ? util.inspect : JSON.stringify;
function doit(t, args) {
var o = [];
var argidx = 0, idx = 0;
var Vnum = 0;
var pad = "";
for(var i = 0; i < t.length; ++i) {
var m = t[i], c = (m[0]).charCodeAt(0);
/* m order: conv full param flags width prec length */
if(c === /*L*/ 76) { o.push(m[1]); continue; }
if(c === /*%*/ 37) { o.push("%"); continue; }
var O = "";
var isnum = 0, radix = 10, bytes = 4, sign = false;
/* flags */
var flags = m[3]||"";
var alt = flags.indexOf("#") > -1;
/* position */
if(m[2]) argidx = parseInt(m[2])-1;
/* %m special case */
else if(c === /*m*/ 109 && !alt) { o.push("Success"); continue; }
/* grab width */
var width = 0; if(m[ 4] != null && m[ 4].length > 0) { if(m[ 4].charAt(0) !== '*') width = parseInt(m[ 4], 10); else if(m[ 4].length === 1) width = args[idx++]; else width = args[parseInt(m[ 4].substr(1), 10)-1]; }
/* grab precision */
var prec = -1; if(m[ 5] != null && m[ 5].length > 0) { if(m[ 5].charAt(0) !== '*') prec = parseInt(m[ 5], 10); else if(m[ 5].length === 1) prec = args[idx++]; else prec = args[parseInt(m[ 5].substr(1), 10)-1]; }
/* position not specified */
if(!m[2]) argidx = idx++;
/* grab argument */
var arg = args[argidx];
/* grab length */
var len = m[6] || "";
switch(c) {
/* str cCsS */
case /*S*/ 83:
case /*s*/ 115:
/* only valid flag is "-" for left justification */
O = String(arg);
if( prec >= 0) O = O.substr(0, prec);
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }
break;
/* first char of string or convert */
case /*C*/ 67:
case /*c*/ 99:
switch(typeof arg) {
case "number":
var cc = arg;
if(c == 67 || len.charCodeAt(0) === /*l*/ 108) { cc &= 0xFFFFFFFF; O = String.fromCharCode( cc); }
else cc &= 0xFF; O = String.fromCharCode( cc);
break;
case "string": O = arg.charAt(0); break;
default: O = String(arg).charAt(0);
}
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }
break;
/* int diDuUoOxXbB */
/* signed integer */
case /*D*/ 68: bytes = 8;
/* falls through */
case /*d*/ 100:
case /*i*/ 105: isnum = -1; sign = true; break;
/* unsigned integer */
case /*U*/ 85: bytes = 8;
/* falls through */
case /*u*/ 117: isnum = -1; break;
/* unsigned octal */
case /*O*/ 79: bytes = 8;
/* falls through */
case /*o*/ 111: isnum = -1; radix = (8); break;
/* unsigned hex */
case /*x*/ 120: isnum = -1; radix = (-16); break;
case /*X*/ 88: isnum = -1; radix = (16); break;
/* unsigned binary (extension) */
case /*B*/ 66: bytes = 8;
/* falls through */
case /*b*/ 98: isnum = -1; radix = (2); break;
/* flt fegFEGaA */
/* floating point logic */
case /*F*/ 70:
case /*f*/ 102: isnum = (1); break;
case /*E*/ 69:
case /*e*/ 101: isnum = (2); break;
case /*G*/ 71:
case /*g*/ 103: isnum = (3); break;
/* floating hex */
case /*A*/ 65:
case /*a*/ 97: isnum = (4); break;
/* misc pnmJVTyY */
/* JS has no concept of pointers so interpret the `l` key as an address */
case /*p*/ 112:
Vnum = typeof arg == "number" ? arg : arg ? Number(arg.l) : -1;
if(isNaN(Vnum)) Vnum = -1;
if(alt) O = Vnum.toString(10);
else {
Vnum = Math.abs(Vnum);
O = "0x" + Vnum.toString(16).toLowerCase();
}
break;
/* store length in the `len` key */
case /*n*/ 110:
if(arg) { arg.len=0; for(var oo = 0; oo < o.length; ++oo) arg.len += o[oo].length; }
continue;
/* process error */
case /*m*/ 109:
if(!(arg instanceof Error)) O = "Success";
else if(arg.message) O = arg.message;
else if(arg.errno) O = "Error number " + arg.errno;
else O = "Error " + String(arg);
break;
/* JS-specific conversions (extension) */
case /*J*/ 74: O = (alt ? u_inspect : JSON.stringify)(arg); break;
case /*V*/ 86: O = arg == null ? "null" : String(arg.valueOf()); break;
case /*T*/ 84:
if(alt) { /* from '[object %s]' extract %s */
O = Object.prototype.toString.call(arg).substr(8);
O = O.substr(0, O.length - 1);
} else O = typeof arg;
break;
/* boolean (extension) */
case /*Y*/ 89:
case /*y*/ 121:
O = Boolean(arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false");
if(c == /*Y*/ 89) O = O.toUpperCase();
if( prec >= 0) O = O.substr(0, prec);
if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O = flags.indexOf("-") > -1 ? O + pad : pad + O; } }
break;
}
if(isnum == -1) {
Vnum = Number(arg);
/* parse byte length field */
switch(len) {
/* char */
case "hh": { bytes = 1; } break;
/* short */
case "h": { bytes = 2; } break;
/* long */
case "l": { if(bytes == 4) bytes = 8; } break;
/* long long */
case "L":
case "q":
case "ll": { if(bytes == 4) bytes = 8; } break;
/* intmax_t */
case "j": { if(bytes == 4) bytes = 8; } break;
/* ptrdiff_t */
case "t": { if(bytes == 4) bytes = 8; } break;
/* size_t */
case "z":
case "Z": { if(bytes == 4) bytes = 8; } break;
/* CRT size_t or ptrdiff_t */
case "I":
{ if(bytes == 4) bytes = 8; }
break;
/* CRT wchar_t */
case "w": break;
}
/* restrict value */
switch(bytes) {
case 1: Vnum = (Vnum & 0xFF); if(sign && (Vnum > 0x7F)) Vnum -= (0xFF + 1); break;
case 2: Vnum = (Vnum & 0xFFFF); if(sign && (Vnum > 0x7FFF)) Vnum -= (0xFFFF + 1); break;
case 4: Vnum = sign ? (Vnum | 0) : (Vnum >>> 0); break;
default: Vnum = isNaN(Vnum) ? 0 : Math.round(Vnum); break;
}
/* generate string */
if(bytes > 4 && Vnum < 0 && !sign) {
if(radix == 16 || radix == -16) {
O = (Vnum>>>0).toString(16);
Vnum = Math.floor((Vnum - (Vnum >>> 0)) / Math.pow(2,32));
O = (Vnum>>>0).toString(16) + (8 - O.length >= 0 ? padstr[ "0"].substr(0,8 - O.length) : "") + O;
O = (16 - O.length >= 0 ? padstr[ "f"].substr(0,16 - O.length) : "") + O;
if(radix == 16) O = O.toUpperCase();
} else if(radix == 8) {
O = (Vnum>>>0).toString(8);
O = (10 - O.length >= 0 ? padstr[ "0"].substr(0,10 - O.length) : "") + O;
Vnum = Math.floor((Vnum - ((Vnum >>> 0)&0x3FFFFFFF)) / Math.pow(2,30));
O = (Vnum>>>0).toString(8) + O.substr(O.length - 10);
O = O.substr(O.length - 20);
O = "1" + (21 - O.length >= 0 ? padstr[ "7"].substr(0,21 - O.length) : "") + O;
} else {
Vnum = (-Vnum) % 1e16;
var d1 = [1,8,4,4,6,7,4,4,0,7,3,7,0,9,5,5,1,6,1,6];
var di = d1.length - 1;
while(Vnum > 0) {
if((d1[di] -= (Vnum % 10)) < 0) { d1[di] += 10; d1[di-1]--; }
--di; Vnum = Math.floor(Vnum / 10);
}
O = d1.join("");
}
} else {
if(radix === -16) O = Vnum.toString(16).toLowerCase();
else if(radix === 16) O = Vnum.toString(16).toUpperCase();
else O = Vnum.toString(radix);
}
/* apply precision */
if(prec ===0 && O == "0" && !(radix == 8 && alt)) O = ""; /* bail out */
else {
if(O.length < prec + (O.substr(0,1) == "-" ? 1 : 0)) {
if(O.substr(0,1) != "-") O = (prec - O.length >= 0 ? padstr[ "0"].substr(0,prec - O.length) : "") + O;
else O = O.substr(0,1) + (prec + 1 - O.length >= 0 ? padstr[ "0"].substr(0,prec + 1 - O.length) : "") + O.substr(1);
}
/* add prefix for # form */
if(!sign && alt && Vnum !== 0) switch(radix) {
case -16: O = "0x" + O; break;
case 16: O = "0X" + O; break;
case 8: if(O.charAt(0) != "0") O = "0" + O; break;
case 2: O = "0b" + O; break;
}
}
/* add sign character */
if(sign && O.charAt(0) != "-") {
if(flags.indexOf("+") > -1) O = "+" + O;
else if(flags.indexOf(" ") > -1) O = " " + O;
}
/* width */
if(width > 0) {
if(O.length < width) {
if(flags.indexOf("-") > -1) {
O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "");
} else if(flags.indexOf("0") > -1 && prec < 0 && O.length > 0) {
if(prec > O.length) O = ((prec - O.length) >= 0 ? padstr[ "0"].substr(0,(prec - O.length)) : "") + O;
pad = ((width - O.length) >= 0 ? padstr[ (prec > 0 ? " " : "0")].substr(0,(width - O.length)) : "");
if(O.charCodeAt(0) < 48) {
if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3);
else O = O.substr(0,1) + pad + O.substring(1);
}
else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2);
else O = pad + O;
} else {
O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O;
}
}
}
} else if(isnum > 0) {
Vnum = Number(arg);
if(arg === null) Vnum = 0/0;
if(len == "L") bytes = 12;
var isf = isFinite(Vnum);
if(!isf) { /* Infinity or NaN */
if(Vnum < 0) O = "-";
else if(flags.indexOf("+") > -1) O = "+";
else if(flags.indexOf(" ") > -1) O = " ";
O += (isNaN(Vnum)) ? "nan" : "inf";
} else {
var E = 0;
if(prec == -1 && isnum != 4) prec = 6;
/* g/G conditional behavior */
if(isnum == 3) {
O = Vnum.toExponential(1);
E = +O.substr(O.indexOf("e") + 1);
if(prec === 0) prec = 1;
if(prec > E && E >= -4) { isnum = (11); prec = prec -(E + 1); }
else { isnum = (12); prec = prec - 1; }
}
/* sign: workaround for negative zero */
var sg = (Vnum < 0 || 1/Vnum == -Infinity) ? "-" : "";
if(Vnum < 0) Vnum = -Vnum;
switch(isnum) {
/* f/F standard */
case 1: case 11:
if(Vnum < 1e21) {
O = Vnum.toFixed(prec);
if(isnum == 1) { if(prec===0 &&alt&& O.indexOf(".")==-1) O+="."; }
else if(!alt) O=O.replace(/(\.\d*[1-9])0*$/,"$1").replace(/\.0*$/,"");
else if(O.indexOf(".") == -1) O+= ".";
break;
}
O = Vnum.toExponential(20);
E = +O.substr(O.indexOf("e")+1);
O = O.charAt(0) + O.substr(2,O.indexOf("e")-2);
O = O + (E - O.length + 1 >= 0 ? padstr[ "0"].substr(0,E - O.length + 1) : "");
if(alt || (prec > 0 && isnum !== 11)) O = O + "." + (prec >= 0 ? padstr[ "0"].substr(0,prec) : "");
break;
/* e/E exponential */
case 2: case 12:
O = Vnum.toExponential(prec);
E = O.indexOf("e");
if(O.length - E === 3) O = O.substr(0, E+2) + "0" + O.substr(E+2);
if(alt && O.indexOf(".") == -1) O = O.substr(0,E) +"."+ O.substr(E);
else if(!alt && isnum == 12) O = O.replace(/\.0*e/, "e").replace(/\.(\d*[1-9])0*e/, ".$1e");
break;
/* a/A hex */
case 4:
if(Vnum===0){O= "0x0"+((alt||prec>0)?"."+(prec >= 0 ? padstr["0"].substr(0,prec) : ""):"")+"p+0"; break;}
O = Vnum.toString(16);
/* First char 0-9 */
var ac = O.charCodeAt(0);
if(ac == 48) {
ac = 2; E = -4; Vnum *= 16;
while(O.charCodeAt(ac++) == 48) { E -= 4; Vnum *= 16; }
O = Vnum.toString(16);
ac = O.charCodeAt(0);
}
var ai = O.indexOf(".");
if(O.indexOf("(") > -1) {
/* IE exponential form */
var am = O.match(/\(e(.*)\)/);
var ae = am ? (+am[1]) : 0;
E += 4 * ae; Vnum /= Math.pow(16, ae);
} else if(ai > 1) {
E += 4 * (ai - 1); Vnum /= Math.pow(16, ai - 1);
} else if(ai == -1) {
E += 4 * (O.length - 1); Vnum /= Math.pow(16, O.length - 1);
}
/* at this point 1 <= Vnum < 16 */
if(bytes > 8) {
if(ac < 50) { E -= 3; Vnum *= 8; }
else if(ac < 52) { E -= 2; Vnum *= 4; }
else if(ac < 56) { E -= 1; Vnum *= 2; }
/* at this point 8 <= Vnum < 16 */
} else {
if(ac >= 56) { E += 3; Vnum /= 8; }
else if(ac >= 52) { E += 2; Vnum /= 4; }
else if(ac >= 50) { E += 1; Vnum /= 2; }
/* at this point 1 <= Vnum < 2 */
}
O = Vnum.toString(16);
if(O.length > 1) {
if(O.length > prec+2 && O.charCodeAt(prec+2) >= 56) {
var _f = O.charCodeAt(0) == 102;
O = (Vnum + 8 * Math.pow(16, -prec-1)).toString(16);
if(_f && O.charCodeAt(0) == 49) E += 4;
}
if(prec > 0) {
O = O.substr(0, prec + 2);
if(O.length < prec + 2) {
if(O.charCodeAt(0) < 48) O = O.charAt(0) + ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : "") + O.substr(1);
else O += ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : "");
}
} else if(prec === 0) O = O.charAt(0) + (alt ? "." : "");
} else if(prec > 0) O = O + "." + (prec >= 0 ? padstr["0"].substr(0,prec) : "");
else if(alt) O = O + ".";
O = "0x" + O + "p" + (E>=0 ? "+" + E : E);
break;
}
if(sg === "") {
if(flags.indexOf("+") > -1) sg = "+";
else if(flags.indexOf(" ") > -1) sg = " ";
}
O = sg + O;
}
/* width */
if(width > O.length) {
if(flags.indexOf("-") > -1) {
O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "");
} else if(flags.indexOf("0") > -1 && O.length > 0 && isf) {
pad = ((width - O.length) >= 0 ? padstr[ "0"].substr(0,(width - O.length)) : "");
if(O.charCodeAt(0) < 48) {
if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3);
else O = O.substr(0,1) + pad + O.substring(1);
}
else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2);
else O = pad + O;
} else {
O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O;
}
}
if(c < 96) O = O.toUpperCase();
}
o.push(O);
}
return o.join("");
}
function vsprintf(fmt, args) { return doit(tokenize(fmt), args); }
//function sprintf() { return doit(tokenize(arguments[0]), Array.prototype.slice.call(arguments, 1)); }
function sprintf() {
var args = new Array(arguments.length - 1);
for(var i = 0; i < args.length; ++i) args[i] = arguments[i+1];
return doit(tokenize(arguments[0]), args);
}
PRINTJ.sprintf = sprintf;
PRINTJ.vsprintf = vsprintf;
PRINTJ._doit = doit;
PRINTJ._tokenize = tokenize;
}));

237
ctest/shim.js Normal file

@ -0,0 +1,237 @@
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
};
})();
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun /*, thisp */)
{
"use strict";
if (this == null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var res = [];
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in t)
{
var val = t[i]; // in case fun mutates this
if (fun.call(thisp, val, i, t))
res.push(val);
}
}
return res;
};
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
if (!Array.prototype.forEach)
{
Array.prototype.forEach = function(fun /*, thisArg */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++)
{
if (i in t)
fun.call(thisArg, t[i], i, t);
}
};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.com/#x15.4.4.19
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== "function") {
throw new TypeError(callback + " is not a function");
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (thisArg) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
// the standard built-in constructor with that name and len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while(k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[ k ];
// ii. Let mappedValue be the result of calling the Call internal method of callback
// with T as the this value and argument list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
// For best browser support, use the following:
A[ k ] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement, fromIndex) {
if ( this === undefined || this === null ) {
throw new TypeError( '"this" is null or not defined' );
}
var length = this.length >>> 0; // Hack to convert object.length to a UInt32
fromIndex = +fromIndex || 0;
if (Math.abs(fromIndex) === Infinity) {
fromIndex = 0;
}
if (fromIndex < 0) {
fromIndex += length;
if (fromIndex < 0) {
fromIndex = 0;
}
}
for (;fromIndex < length; fromIndex++) {
if (this[fromIndex] === searchElement) {
return fromIndex;
}
}
return -1;
};
}
// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
if (! Array.isArray) {
Array.isArray = function(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
};
}
// https://github.com/ttaubert/node-arraybuffer-slice
// (c) 2013 Tim Taubert <tim@timtaubert.de>
// arraybuffer-slice may be freely distributed under the MIT license.
"use strict";
if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
ArrayBuffer.prototype.slice = function (begin, end) {
begin = (begin|0) || 0;
var num = this.byteLength;
end = end === (void 0) ? num : (end|0);
// Handle negative values.
if (begin < 0) begin += num;
if (end < 0) end += num;
if (num === 0 || begin >= num || begin >= end) {
return new ArrayBuffer(0);
}
var length = Math.min(num - begin, end - begin);
var target = new ArrayBuffer(length);
var targetArray = new Uint8Array(target);
targetArray.set(new Uint8Array(this, begin, length));
return target;
};
}

174
ctest/test.js Normal file

@ -0,0 +1,174 @@
/* vim: set ts=2: */
var X;
var IMPLS = {}, IMPLA = [], IMPL = [];
if(typeof require !== 'undefined') {
assert = require('assert');
X=require('./');
IMPL = require("./lib/impl.json");
IMPL.forEach(function(impl, i) { IMPLS[impl] = IMPLA[i] = require("./lib/" + impl); });
} else {
X = PRINTJ;
IMPL.push("base"); IMPLS["base"] = IMPLA[IMPL.length-1] = X;
}
function msieversion()
{
if(typeof window == 'undefined') return Infinity;
if(typeof window.navigator == 'undefined') return Infinity;
var ua = window.navigator.userAgent
var msie = ua.indexOf ( "MSIE " )
if(msie < 0) return Infinity;
return parseInt (ua.substring (msie+5, ua.indexOf (".", msie )));
}
function isopera() {
if(typeof window == 'undefined') return false;
if(typeof window.navigator == 'undefined') return false;
var ua = window.navigator.userAgent;
return ua.indexOf("Opera") > -1;
}
function compare_parse(a,b) {
assert.equal(a.length, b.length);
for(var i = 0; i < a.length; ++i) {
for(var j = 0; j < a[i].length; ++j) {
if((a[i][j] || "") != (b[i][j] || "")) {
throw i + "," + j + " " + a[i] + " " + b[i];
}
}
}
}
if(typeof require !== 'undefined') describe('consensus', function() {
it('tokenizer', function() {
var COMPARE = require("./tests/compare.json");
COMPARE.forEach(function(m) {
var base = IMPLA[0]._tokenize(m);
for(var i = 1; i < IMPLA.length; ++i) compare_parse(base, IMPLA[i]._tokenize(m));
});
});
});
describe('correctness', function() {
var PRINTF = typeof tests !== 'undefined' ? tests : require("./tests/printf");
IMPL.forEach(function(n,i) {
var impl = IMPLA[i];
it(n, function() {
PRINTF.forEach(function(v) {
if(impl.sprintf.apply(impl, v[0]) != v[1]) {
if(isopera() && v[0][0].match(/^%.*[Aa]$/)) return;
console.log(v);
assert.equal(impl.sprintf.apply(impl, v[0]), v[1]);
}
});
});
});
});
var sprintf = X.sprintf;
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ !\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_~{|}`".split("");
var convs = "aAbBcCdDeEfFgGiJmnoOpsSTuUVxXyY%".split("");
var flags = " #'+-0".split("");
var digits = "0123456789".split("");
var lens = "hIjlLqtwzZ".split(""); lens.push("hh"); lens.push("ll");
var other = "$*.".split("");
var unused = []; chars.forEach(function(c) {
if(convs.indexOf(c) == -1 &&
flags.indexOf(c) == -1 &&
digits.indexOf(c) == -1 &&
lens.indexOf(c) == -1 &&
other.indexOf(c) == -1
) unused.push(c);
});
describe('special cases', function() {
it('fails on unrecognized format chars: ' + unused.join(""), function() {
unused.forEach(function(c) {
assert.throws(function() { sprintf("%" + c, 0); }, "Should fail on %" +c);
});
});
it('accepts all expected conversions: ' + convs.join(""), function() {
convs.forEach(function(c) {
assert.doesNotThrow(function() { sprintf("%" + c, 0); }, "Should pass on %" +c);
});
});
it('accepts all expected lengths: ' + lens.join(""), function() {
lens.forEach(function(l) {
var fmt = "%" + l + "X";
assert.doesNotThrow(function() { sprintf(fmt, 0); }, "Should pass on "+fmt);
});
});
it('accepts all expected flags: ' + flags.join(""), function() {
flags.forEach(function(l) {
var fmt = "%" + l + "X";
assert.doesNotThrow(function() { sprintf(fmt, 0); }, "Should pass on "+fmt);
});
});
it('correctly handles character conversions: cC', function() {
assert.equal(sprintf("|%c %c|", "69", 69), "|6 E|");
assert.equal(sprintf("|%c|", {toString:function() { return "69"; }, valueOf: function() { return 69; }} ), "|6|");
});
it('correctly handles error conversion: m', function() {
var x = new Error("sheetjs");
x.errno = 69; x.toString = function() { return "SHEETJS"; };
assert.equal(sprintf("|%#m|", x), "|sheetjs|");
delete x.message;
assert.equal(sprintf("|%#m|", x), "|Error number 69|");
delete x.errno;
assert.equal(sprintf("|%#m|", x), "|Error SHEETJS|");
});
it('correctly handles typeof and valueOf conversions: TV', function() {
assert.equal(sprintf("%1$T %1$#T", 1), 'number Number');
assert.equal(sprintf("%1$T %1$#T", 'foo'), 'string String');
assert.equal(sprintf("%1$T %1$#T", [1,2,3]), 'object Array');
assert.equal(sprintf("%1$T %1$#T", null).replace(/Object|global/, "Null"), 'object Null');
assert.equal(sprintf("%1$T %1$#T", undefined).replace(/Object|global/, "Undefined"), 'undefined Undefined');
var _f = function() { return "f"; };
var _3 = function() { return 3; };
assert.equal(sprintf("%1$d %1$s %1$V", {toString:_f}), '0 f f');
assert.equal(sprintf("%1$d %1$s %1$V", {valueOf:_3}), '3 [object Object] 3');
assert.equal(sprintf("%1$d %1$s %1$V", {valueOf:_3, toString:_f}), '3 f 3');
});
it('correctly handles standard integer conversions: diouxXDUO', function() {
assert.equal(sprintf("%02hhx %02hhX", 1, 1234321), "01 91");
assert.equal(sprintf("%02hhx %-02hhX", -1, -253), "ff 3 ");
assert.equal(sprintf("%#02llx", -3), "0xfffffffffffffffd");
assert.equal(sprintf("%#02llX", -3), "0XFFFFFFFFFFFFFFFD");
assert.equal(sprintf("%#02llo", -3), "01777777777777777777775");
assert.equal(sprintf("%#02llu", -3), "18446744073709551613");
assert.equal(sprintf("%#03lld", -3), "-03");
assert.equal(sprintf("%.9d %.9d", 123456, -123456), "000123456 -000123456");
});
it('correctly handles new binary conversions: bB', function() {
assert.equal(sprintf("%#b", -3), "0b11111111111111111111111111111101");
assert.equal(sprintf("%#5B", 3), " 0b11");
});
it('recognizes IEEE754 special values', function() {
assert.equal(sprintf("%a", Infinity), "inf");
assert.equal(sprintf("%e", -Infinity), "-inf");
assert.equal(sprintf("%f", 0/0), "nan");
assert.equal(sprintf("%g", 1/-Infinity), "-0");
});
it('correctly handles floating point conversions: aAeEfFgG', function() {
assert.equal(sprintf("%1$g %1$#g", 1e5), "100000 100000.");
assert.equal(sprintf("%.3g %.3g", 1.2345e-4, 1.2345e-5), "0.000123 1.23e-05");
assert.equal(sprintf("%f", 1.23e22).replace("10486","00000"), "12300000000000000000000.000000");
assert.equal(sprintf("|%1$4.1f|%1$04.1f|%1$-4.1f", 1.2), "| 1.2|01.2|1.2 ");
assert.equal(sprintf("%1$.1a|%1$04.0f", -128), "-0x1.0p+7|-128");
assert.equal(sprintf("%1$.1a|%1$04.0f", -6.9e-11), "-0x1.3p-34|-000");
if(!isopera()) {
assert.equal(sprintf("%a %A %a %A", 1, .2, .69, 6e20), "0x1p+0 0X1.999999999999AP-3 0x1.6147ae147ae14p-1 0X1.043561A88293P+69");
assert.equal(sprintf("%La %LA %La %LA", 1, .2, .69, 6e20), "0x8p-3 0XC.CCCCCCCCCCCDP-6 0xb.0a3d70a3d70ap-4 0X8.21AB0D441498P+66");
assert.equal(sprintf("%010.1a", 1.), "0x001.0p+0");
assert.equal(sprintf("%.7a %.7a", 129, -129), "0x1.0200000p+7 -0x1.0200000p+7");
assert.equal(sprintf("%.7a", -3.1), "-0x1.8cccccdp+1");
}
});
it('consistently handles null and undefined', function() {
assert.equal(sprintf("|%1$a|%1$A|%1$e|%1$E|%1$f|%1$F|%1$g|%1$G|", undefined), "|nan|NAN|nan|NAN|nan|NAN|nan|NAN|");
assert.equal(sprintf("|%1$a|%1$A|%1$e|%1$E|%1$f|%1$F|%1$g|%1$G|", null), "|nan|NAN|nan|NAN|nan|NAN|nan|NAN|");
assert.equal(sprintf("|%1$b|%1$B|%1$d|%1$D|%1$i|%1$o|%1$O|%1$u|%1$U|%1$x|%1$X|", undefined), "|0|0|0|0|0|0|0|0|0|0|0|");
assert.equal(sprintf("|%1$b|%1$B|%1$d|%1$D|%1$i|%1$o|%1$O|%1$u|%1$U|%1$x|%1$X|", null), "|0|0|0|0|0|0|0|0|0|0|0|");
});
});

65
test.js

@ -1,12 +1,32 @@
var assert = require("assert");
/* vim: set ts=2: */
var X;
var IMPLS = {}, IMPLA = [], IMPL = [];
if(typeof require !== 'undefined') {
assert = require('assert');
X=require('./');
IMPL = require("./lib/impl.json");
IMPL.forEach(function(impl, i) { IMPLS[impl] = IMPLA[i] = require("./lib/" + impl); });
} else {
X = PRINTJ;
IMPL.push("base"); IMPLS["base"] = IMPLA[IMPL.length-1] = X;
}
var IMPL = require("./lib/impl.json");
var COMPARE = require("./tests/compare.json");
var PRINTF = require("./tests/printf");
function msieversion()
{
if(typeof window == 'undefined') return Infinity;
if(typeof window.navigator == 'undefined') return Infinity;
var ua = window.navigator.userAgent
var msie = ua.indexOf ( "MSIE " )
if(msie < 0) return Infinity;
return parseInt (ua.substring (msie+5, ua.indexOf (".", msie )));
}
var IMPLS = {}, IMPLA = [];
IMPL.forEach(function(impl, i) { IMPLS[impl] = IMPLA[i] = require("./lib/" + impl); });
IMPL.push("base"); IMPLS["base"] = IMPLA[IMPL.length-1] = require("./");
function isopera() {
if(typeof window == 'undefined') return false;
if(typeof window.navigator == 'undefined') return false;
var ua = window.navigator.userAgent;
return ua.indexOf("Opera") > -1;
}
function compare_parse(a,b) {
assert.equal(a.length, b.length);
@ -19,8 +39,9 @@ function compare_parse(a,b) {
}
}
describe('consensus', function() {
if(typeof require !== 'undefined') describe('consensus', function() {
it('tokenizer', function() {
var COMPARE = require("./tests/compare.json");
COMPARE.forEach(function(m) {
var base = IMPLA[0]._tokenize(m);
for(var i = 1; i < IMPLA.length; ++i) compare_parse(base, IMPLA[i]._tokenize(m));
@ -29,16 +50,22 @@ describe('consensus', function() {
});
describe('correctness', function() {
var PRINTF = typeof tests !== 'undefined' ? tests : require("./tests/printf");
IMPL.forEach(function(n,i) {
var impl = IMPLA[i];
it(n, function() {
PRINTF.forEach(function(v) {
assert.equal(IMPLA[i].sprintf.apply(IMPLA[i], v[0]), v[1]);
if(impl.sprintf.apply(impl, v[0]) != v[1]) {
if(isopera() && v[0][0].match(/^%.*[Aa]$/)) return;
console.log(v);
assert.equal(impl.sprintf.apply(impl, v[0]), v[1]);
}
});
});
});
});
var sprintf = IMPLS["base"].sprintf;
var sprintf = X.sprintf;
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ !\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_~{|}`".split("");
var convs = "aAbBcCdDeEfFgGiJmnoOpsSTuUVxXyY%".split("");
var flags = " #'+-0".split("");
@ -94,8 +121,8 @@ describe('special cases', function() {
assert.equal(sprintf("%1$T %1$#T", 1), 'number Number');
assert.equal(sprintf("%1$T %1$#T", 'foo'), 'string String');
assert.equal(sprintf("%1$T %1$#T", [1,2,3]), 'object Array');
assert.equal(sprintf("%1$T %1$#T", null), 'object Null');
assert.equal(sprintf("%1$T %1$#T", undefined), 'undefined Undefined');
assert.equal(sprintf("%1$T %1$#T", null).replace(/Object|global/, "Null"), 'object Null');
assert.equal(sprintf("%1$T %1$#T", undefined).replace(/Object|global/, "Undefined"), 'undefined Undefined');
var _f = function() { return "f"; };
var _3 = function() { return 3; };
@ -126,15 +153,17 @@ describe('special cases', function() {
it('correctly handles floating point conversions: aAeEfFgG', function() {
assert.equal(sprintf("%1$g %1$#g", 1e5), "100000 100000.");
assert.equal(sprintf("%.3g %.3g", 1.2345e-4, 1.2345e-5), "0.000123 1.23e-05");
assert.equal(sprintf("%f", 1.23e22), "12300000000000001048600.000000");
assert.equal(sprintf("%a %A %a %A", 1, .2, .69, 6e20), "0x1p+0 0X1.999999999999AP-3 0x1.6147ae147ae14p-1 0X1.043561A88293P+69");
assert.equal(sprintf("%La %LA %La %LA", 1, .2, .69, 6e20), "0x8p-3 0XC.CCCCCCCCCCCDP-6 0xb.0a3d70a3d70ap-4 0X8.21AB0D441498P+66");
assert.equal(sprintf("%f", 1.23e22).replace("10486","00000"), "12300000000000000000000.000000");
assert.equal(sprintf("|%1$4.1f|%1$04.1f|%1$-4.1f", 1.2), "| 1.2|01.2|1.2 ");
assert.equal(sprintf("%1$.1a|%1$04.0f", -128), "-0x1.0p+7|-128");
assert.equal(sprintf("%1$.1a|%1$04.0f", -6.9e-11), "-0x1.3p-34|-000");
assert.equal(sprintf("%010.1a", 1.), "0x001.0p+0");
assert.equal(sprintf("%.7a %.7a", 129, -129), "0x1.0200000p+7 -0x1.0200000p+7");
assert.equal(sprintf("%.7a", -3.1), "-0x1.8cccccdp+1");
if(!isopera()) {
assert.equal(sprintf("%a %A %a %A", 1, .2, .69, 6e20), "0x1p+0 0X1.999999999999AP-3 0x1.6147ae147ae14p-1 0X1.043561A88293P+69");
assert.equal(sprintf("%La %LA %La %LA", 1, .2, .69, 6e20), "0x8p-3 0XC.CCCCCCCCCCCDP-6 0xb.0a3d70a3d70ap-4 0X8.21AB0D441498P+66");
assert.equal(sprintf("%010.1a", 1.), "0x001.0p+0");
assert.equal(sprintf("%.7a %.7a", 129, -129), "0x1.0200000p+7 -0x1.0200000p+7");
assert.equal(sprintf("%.7a", -3.1), "-0x1.8cccccdp+1");
}
});
it('consistently handles null and undefined', function() {
assert.equal(sprintf("|%1$a|%1$A|%1$e|%1$E|%1$f|%1$F|%1$g|%1$G|", undefined), "|nan|NAN|nan|NAN|nan|NAN|nan|NAN|");

@ -89881,7 +89881,7 @@ var tests = [
// JSON
[["|%1$J|%1$#J|", 1], '|1|1|'],
[["|%1$J|%1$#J|", "2"], '|"2"|\'2\'|'],
[["|%1$J|%1$#J|", "2"], typeof require !== 'undefined' ? '|"2"|\'2\'|' : '|"2"|"2"|'],
// length
[["%p", p], "0x7b"],
@ -89921,6 +89921,6 @@ tests.push([["|%#m|", e1], "|sheetjs|"])
tests.push([["|%#m|", e2], "|Error number 69|"])
tests.push([["|%#m|", e3], "|Error SHEETJS|"])
module.exports = tests;
if(typeof module !== 'undefined') module.exports = tests;