GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

third-party/js-xlsx/js-xlsx-0.13.5/test.js   F
last analyzed

Complexity

Total Complexity 763
Complexity/F 1.38

Size

Lines of Code 2360
Function Count 554

Duplication

Duplicated Lines 2360
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 1797
dl 2360
loc 2360
rs 0.8
c 0
b 0
f 0
wmc 763
mnd 209
bc 209
fnc 554
bpm 0.3772
cpm 1.3772
noi 11

32 Functions

Rating   Name   Duplication   Size   Complexity  
F test.js ➔ parsetest 101 101 51
A test.js ➔ deepcmp 6 6 4
A test.js ➔ cmparr 1 1 2
A test.js ➔ custprop 6 6 1
F test.js ➔ seq 6 6 179
F test.js ➔ checkcells 5 5 64
A test.js ➔ stripbom 1 1 1
D test.js ➔ get_cell 5 5 13
F test.js ➔ get_dom_element 11 11 47
C test.js ➔ fixsheetname 1 1 10
A test.js ➔ coreprop 11 11 5
A test.js ➔ datenum 5 5 2
A test.js ➔ fixcsv 1 1 1
B test.js ➔ each_cell 4 4 6
A test.js ➔ make_csv_str 5 5 2
A test.js ➔ make_html_str 5 5 1
B test.js ➔ parseDate 12 12 6
F test.js ➔ RT 15 15 74
F test.js ➔ test_file 1 1 21
A test.js ➔ check_comments 13 13 1
A test.js ➔ each_sheet 1 1 2
F test.js ➔ seeker 8 8 86
A test.js ➔ fixjson 1 1 1
F test.js ➔ chk 6 6 26
C test.js ➔ eqarr 4 4 11
A test.js ➔ hlink2 9 9 3
A test.js ➔ diffsty 9 9 4
A test.js ➔ pathit 1 1 2
F test.js ➔ plaintext_test 10 10 45
C test.js ➔ eqcell 4 4 11
A test.js ➔ check_margin 5 5 2
A test.js ➔ hlink1 12 12 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like third-party/js-xlsx/js-xlsx-0.13.5/test.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
2
/* vim: set ts=2: */
3
/*jshint mocha:true */
4
/* eslint-env mocha */
5
/*global process, document, require */
6
/*global ArrayBuffer, Uint8Array */
7
/*::
8
declare type EmptyFunc = (() => void) | null;
9
declare type DescribeIt = { (desc:string, test:EmptyFunc):void; skip(desc:string, test:EmptyFunc):void; };
10
declare var describe : DescribeIt;
11
declare var it: DescribeIt;
12
declare var before:(test:EmptyFunc)=>void;
13
declare var afterEach:(test:EmptyFunc)=>void;
14
declare var cptable: any;
15
*/
16 View Code Duplication
var X;
17
var modp = './';
18
var fs = require('fs'), assert = require('assert');
19
describe('source',function(){it('should load',function(){X=require(modp);});});
20
var DIF_XL = true;
21
22
var browser = typeof document !== 'undefined';
23
// $FlowIgnore
24
if(!browser) try { require('./shim'); } catch(e) { }
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
25
26
var Buffer_from = /*::(*/function(){}/*:: :any)*/;
27
28
if(typeof Buffer !== 'undefined') {
29
	var nbfs = !Buffer.from;
30
	if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
31
	Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
32
	// $FlowIgnore
33
	if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
34
}
35
36
var opts = ({cellNF: true}/*:any*/);
37
var TYPE = browser ? "binary" : "buffer";
38
opts.type = TYPE;
39
var fullex = [".xlsb", /*".xlsm",*/ ".xlsx"/*, ".xlml", ".xls"*/];
40
var ofmt = ["xlsb", "xlsm", "xlsx", "ods", "biff2", "biff5", "biff8", "xlml", "sylk", "dif", "dbf", "eth", "fods", "csv", "txt", "html"];
41
var ex = fullex.slice(); ex = ex.concat([".ods", ".xls", ".xml", ".fods"]);
42
if(typeof process != 'undefined' && ((process||{}).env)) {
43
	opts.WTF = true;
44
	opts.cellStyles = true;
45
	if(process.env.FMTS === "full") process.env.FMTS = ex.join(":");
46
	if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;});
47
}
48
var exp = ex.map(function(x){ return x + ".pending"; });
49
function test_file(x){ return ex.indexOf(x.slice(-5))>=0||exp.indexOf(x.slice(-13))>=0 || ex.indexOf(x.slice(-4))>=0||exp.indexOf(x.slice(-12))>=0; }
50
51
var files = [], fileA = [];
52
if(!browser) {
53
	var _files = fs.existsSync('tests.lst') ? fs.readFileSync('tests.lst', 'utf-8').split("\n").map(function(x) { return x.trim(); }) : fs.readdirSync('test_files');
54
	for(var _filesi = 0; _filesi < _files.length; ++_filesi) if(test_file(_files[_filesi])) files.push(_files[_filesi]);
55
	var _fileA = fs.existsSync('tests/testA.lst') ? fs.readFileSync('tests/testA.lst', 'utf-8').split("\n").map(function(x) { return x.trim(); }) : [];
56
	for(var _fileAi = 0; _fileAi < _fileA.length; ++_fileAi) if(test_file(_fileA[_fileAi])) fileA.push(_fileA[_fileAi]);
57
}
58
59
/* Excel enforces 31 character sheet limit, although technical file limit is 255 */
60
function fixsheetname(x/*:string*/)/*:string*/ { return x.substr(0,31); }
61
62
function stripbom(x/*:string*/)/*:string*/ { return x.replace(/^\ufeff/,""); }
63
function fixcsv(x/*:string*/)/*:string*/ { return stripbom(x).replace(/\t/g,",").replace(/#{255}/g,"").replace(/"/g,"").replace(/[\n\r]+/g,"\n").replace(/\n*$/,""); }
64
function fixjson(x/*:string*/)/*:string*/ { return x.replace(/[\r\n]+$/,""); }
65
66
var dir = "./test_files/";
67
68
var dirwp = dir + "artifacts/wps/", dirqp = dir + "artifacts/quattro/";
69
var paths = {
70
	aadbf:  dirwp + 'write.dbf',
71
	aadif:  dirwp + 'write.dif',
72
	aaxls:  dirwp + 'write.xls',
73
	aaxlsx: dirwp + 'write.xlsx',
74
	aaxml:  dirwp + 'write.xml',
75
76
	abcsv:  dirqp + 'write_.csv',
77
	abdif:  dirqp + 'write_.dif',
78
	abslk:  dirqp + 'write_.slk',
79
	abx57:  dirqp + 'write_57.xls',
80
	abwb2:  dirqp + 'write_6.wb2',
81
	abwb2b: dirqp + 'write_6b.wb2',
82
	abwb3:  dirqp + 'write_8.wb3',
83
	abqpw:  dirqp + 'write_9.qpw',
84
	abx97:  dirqp + 'write_97.xls',
85
	abwks:  dirqp + 'write_L1.wks',
86
	abwk1:  dirqp + 'write_L2.wk1',
87
	abwk3:  dirqp + 'write_L3.wk3',
88
	abwk4:  dirqp + 'write_L45.wk4',
89
	ab123:  dirqp + 'write_L9.123',
90
	ab124:  dirqp + 'write_L97.123',
91
	abwke2: dirqp + 'write_Led.wke',
92
	abwq1:  dirqp + 'write_qpdos.wq1',
93
	abwb1:  dirqp + 'write_qpw.wb1',
94
95
	afxls:   dir + 'AutoFilter.xls',
96
	afxml:   dir + 'AutoFilter.xml',
97
	afods:   dir + 'AutoFilter.ods',
98
	afxlsx:  dir + 'AutoFilter.xlsx',
99
	afxlsb:  dir + 'AutoFilter.xlsb',
100
101
	asxls:   dir + 'author_snowman.xls',
102
	asxls5:  dir + 'author_snowman.xls5',
103
	asxml:   dir + 'author_snowman.xml',
104
	asods:   dir + 'author_snowman.ods',
105
	asxlsx:  dir + 'author_snowman.xlsx',
106
	asxlsb:  dir + 'author_snowman.xlsb',
107
108
	cpxls:   dir + 'custom_properties.xls',
109
	cpxml:   dir + 'custom_properties.xls.xml',
110
	cpxlsx:  dir + 'custom_properties.xlsx',
111
	cpxlsb:  dir + 'custom_properties.xlsb',
112
113
	cssxls: dir + 'cell_style_simple.xls',
114
	cssxml: dir + 'cell_style_simple.xml',
115
	cssxlsx: dir + 'cell_style_simple.xlsx',
116
	cssxlsb: dir + 'cell_style_simple.xlsb',
117
118
	cstxls: dir + 'comments_stress_test.xls',
119
	cstxml: dir + 'comments_stress_test.xls.xml',
120
	cstxlsx: dir + 'comments_stress_test.xlsx',
121
	cstxlsb: dir + 'comments_stress_test.xlsb',
122
	cstods: dir + 'comments_stress_test.ods',
123
124
	cwxls:  dir + 'column_width.xls',
125
	cwxls5:  dir + 'column_width.biff5',
126
	cwxml:  dir + 'column_width.xml',
127
	cwxlsx:  dir + 'column_width.xlsx',
128
	cwxlsb:  dir + 'column_width.xlsb',
129
	cwslk:  dir + 'column_width.slk',
130
131
	dnsxls: dir + 'defined_names_simple.xls',
132
	dnsxml: dir + 'defined_names_simple.xml',
133
	dnsxlsx: dir + 'defined_names_simple.xlsx',
134
	dnsxlsb: dir + 'defined_names_simple.xlsb',
135
136
	dnuxls: dir + 'defined_names_unicode.xls',
137
	dnuxml: dir + 'defined_names_unicode.xml',
138
	dnuods: dir + 'defined_names_unicode.ods',
139
	dnuxlsx: dir + 'defined_names_unicode.xlsx',
140
	dnuxlsb: dir + 'defined_names_unicode.xlsb',
141
142
	dtxls:  dir + 'xlsx-stream-d-date-cell.xls',
143
	dtxml:  dir + 'xlsx-stream-d-date-cell.xls.xml',
144
	dtxlsx:  dir + 'xlsx-stream-d-date-cell.xlsx',
145
	dtxlsb:  dir + 'xlsx-stream-d-date-cell.xlsb',
146
147
	fstxls: dir + 'formula_stress_test.xls',
148
	fstxml: dir + 'formula_stress_test.xls.xml',
149
	fstxlsx: dir + 'formula_stress_test.xlsx',
150
	fstxlsb: dir + 'formula_stress_test.xlsb',
151
	fstods: dir + 'formula_stress_test.ods',
152
153
	hlxls:  dir + 'hyperlink_stress_test_2011.xls',
154
	hlxml:  dir + 'hyperlink_stress_test_2011.xml',
155
	hlxlsx:  dir + 'hyperlink_stress_test_2011.xlsx',
156
	hlxlsb:  dir + 'hyperlink_stress_test_2011.xlsb',
157
158
	ilxls:   dir + 'internal_link.xls',
159
	ilxls5:  dir + 'internal_link.biff5',
160
	ilxml:   dir + 'internal_link.xml',
161
	ilxlsx:  dir + 'internal_link.xlsx',
162
	ilxlsb:  dir + 'internal_link.xlsb',
163
	ilods:   dir + 'internal_link.ods',
164
165
	lonxls: dir + 'LONumbers.xls',
166
	lonxlsx: dir + 'LONumbers.xlsx',
167
168
	mcxls:  dir + 'merge_cells.xls',
169
	mcxml:  dir + 'merge_cells.xls.xml',
170
	mcxlsx:  dir + 'merge_cells.xlsx',
171
	mcxlsb:  dir + 'merge_cells.xlsb',
172
	mcods:  dir + 'merge_cells.ods',
173
174
	nfxls:  dir + 'number_format.xls',
175
	nfxml:  dir + 'number_format.xls.xml',
176
	nfxlsx:  dir + 'number_format.xlsm',
177
	nfxlsb:  dir + 'number_format.xlsb',
178
179
	olxls:  dir + 'outline.xls',
180
	olxls5:  dir + 'outline.biff5',
181
	olxlsx:  dir + 'outline.xlsx',
182
	olxlsb:  dir + 'outline.xlsb',
183
	olods:  dir + 'outline.ods',
184
185
	pmxls:  dir + 'page_margins_2016.xls',
186
	pmxls5: dir + 'page_margins_2016_5.xls',
187
	pmxml:  dir + 'page_margins_2016.xml',
188
	pmxlsx: dir + 'page_margins_2016.xlsx',
189
	pmxlsb: dir + 'page_margins_2016.xlsb',
190
191
	rhxls:  dir + 'row_height.xls',
192
	rhxls5:  dir + 'row_height.biff5',
193
	rhxml:  dir + 'row_height.xml',
194
	rhxlsx:  dir + 'row_height.xlsx',
195
	rhxlsb:  dir + 'row_height.xlsb',
196
	rhslk:  dir + 'row_height.slk',
197
198
	svxls:  dir + 'sheet_visibility.xls',
199
	svxls5: dir + 'sheet_visibility.xls',
200
	svxml:  dir + 'sheet_visibility.xml',
201
	svxlsx: dir + 'sheet_visibility.xlsx',
202
	svxlsb: dir + 'sheet_visibility.xlsb',
203
204
	swcxls: dir + 'apachepoi_SimpleWithComments.xls',
205
	swcxml: dir + '2011/apachepoi_SimpleWithComments.xls.xml',
206
	swcxlsx: dir + 'apachepoi_SimpleWithComments.xlsx',
207
	swcxlsb: dir + '2013/apachepoi_SimpleWithComments.xlsx.xlsb'
208
};
209
210
function pathit(p, ext) { return ext.map(function(n) { return paths[p + n]; }); }
211
var FSTPaths = pathit("fst", ["xlsx", "xlsb", "xls", "xml", "ods"]);
212
var CSTPaths = pathit("cst", ["xlsx", "xlsb", "xls", "xml", "ods"]);
213
var MCPaths =  pathit("mc",  ["xlsx", "xlsb", "xls", "xml", "ods"]);
214
var CSSPaths = pathit("css", ["xlsx", "xlsb", "xls", "xml"]);
215
var NFPaths =  pathit("nf",  ["xlsx", "xlsb", "xls", "xml"]);
216
var DTPaths =  pathit("dt",  ["xlsx", "xlsb", "xls", "xml"]);
217
var HLPaths =  pathit("hl",  ["xlsx", "xlsb", "xls", "xml"]);
218
var ILPaths =  pathit("il",  ["xlsx", "xlsb", "xls", "xml", "ods", "xls5"]);
219
var OLPaths =  pathit("ol",  ["xlsx", "xlsb", "xls", "ods", "xls5"]);
220
var PMPaths =  pathit("pm",  ["xlsx", "xlsb", "xls", "xml", "xls5"]);
221
var SVPaths =  pathit("sv",  ["xlsx", "xlsb", "xls", "xml", "xls5"]);
222
var CWPaths =  pathit("cw",  ["xlsx", "xlsb", "xls", "xml", "xls5", "slk"]);
223
var RHPaths =  pathit("rh",  ["xlsx", "xlsb", "xls", "xml", "xls5", "slk"]);
224
225
var artifax = [
226
	"cstods", "cstxls", "cstxlsb", "cstxlsb", "cstxml", "aadbf", "aadif",
227
	"aaxls", "aaxml", "aaxlsx", "ab123", "ab124", "abcsv", "abdif", "abqpw",
228
	"abslk", "abwb1", "abwb2", "abwb3", "abwk1", "abwk3", "abwk4", "abwks",
229
	"abwq1", "abx57", "abx97", "abwke2", "abwb2b"
230
].map(function(x) { return paths[x]; });
231
232
function parsetest(x/*:string*/, wb/*:Workbook*/, full/*:boolean*/, ext/*:?string*/) {
233
	ext = (ext ? " [" + ext + "]": "");
234
	if(!full && ext) return;
235
	describe(x + ext + ' should have all bits', function() {
236
		var sname = dir + '2016/' + x.substr(x.lastIndexOf('/')+1) + '.sheetnames';
237
		if(!fs.existsSync(sname)) sname = dir + '2011/' + x.substr(x.lastIndexOf('/')+1) + '.sheetnames';
238
		if(!fs.existsSync(sname)) sname = dir + '2013/' + x.substr(x.lastIndexOf('/')+1) + '.sheetnames';
239
		it('should have all sheets', function() {
240
			wb.SheetNames.forEach(function(y) { assert(wb.Sheets[y], 'bad sheet ' + y); });
241
		});
242
		if(fs.existsSync(sname)) it('should have the right sheet names', function() {
243
			var file = fs.readFileSync(sname, 'utf-8').replace(/\r/g,"");
244
			var names = wb.SheetNames.map(fixsheetname).join("\n") + "\n";
245
			if(file.length && !x.match(/artifacts/)) assert.equal(names, file);
246
		});
247
	});
248
	describe(x + ext + ' should generate CSV', function() {
249
		wb.SheetNames.forEach(function(ws, i) {
250
			it('#' + i + ' (' + ws + ')', function() {
251
				X.utils.make_csv(wb.Sheets[ws]);
252
			});
253
		});
254
	});
255
	describe(x + ext + ' should generate JSON', function() {
256
		wb.SheetNames.forEach(function(ws, i) {
257
			it('#' + i + ' (' + ws + ')', function() {
258
				X.utils.sheet_to_json(wb.Sheets[ws]);
259
			});
260
		});
261
	});
262
	describe(x + ext + ' should generate formulae', function() {
263
		wb.SheetNames.forEach(function(ws, i) {
264
			it('#' + i + ' (' + ws + ')', function() {
265
				X.utils.get_formulae(wb.Sheets[ws]);
266
			});
267
		});
268
	});
269
	if(!full) return;
270
	var getfile = function(dir, x, i, type) {
271
		var name = (dir + x + '.' + i + type);
272
		var root = "";
273
		if(x.substr(-5) === ".xlsb") {
274
			root = x.slice(0,-5);
275
			if(!fs.existsSync(name)) name=(dir + root + '.xlsx.' + i + type);
276
			if(!fs.existsSync(name)) name=(dir + root + '.xlsm.' + i + type);
277
			if(!fs.existsSync(name)) name=(dir + root + '.xls.'  + i + type);
278
		}
279
		if(x.substr(-4) === ".xls") {
280
			root = x.slice(0,-4);
281
			if(!fs.existsSync(name)) name=(dir + root + '.xlsx.' + i + type);
282
			if(!fs.existsSync(name)) name=(dir + root + '.xlsm.' + i + type);
283
			if(!fs.existsSync(name)) name=(dir + root + '.xlsb.' + i + type);
284
		}
285
		return name;
286
	};
287
	describe(x + ext + ' should generate correct CSV output', function() {
288
		wb.SheetNames.forEach(function(ws, i) {
289
			var name = getfile(dir, x, i, ".csv");
290
			if(fs.existsSync(name)) it('#' + i + ' (' + ws + ')', function() {
291
				var file = fs.readFileSync(name, 'utf-8');
292
				var csv = X.utils.make_csv(wb.Sheets[ws]);
293
				assert.equal(fixcsv(csv), fixcsv(file), "CSV badness");
294
			});
295
		});
296
	});
297
	if(typeof JSON !== 'undefined') describe(x + ext + ' should generate correct JSON output', function() {
298
		wb.SheetNames.forEach(function(ws, i) {
299
			var rawjson = getfile(dir, x, i, ".rawjson");
300
			if(fs.existsSync(rawjson)) it('#' + i + ' (' + ws + ')', function() {
301
				var file = fs.readFileSync(rawjson, 'utf-8');
302
				var json = X.utils.make_json(wb.Sheets[ws],{raw:true});
303
				assert.equal(JSON.stringify(json), fixjson(file), "JSON badness");
304
			});
305
306
			var jsonf = getfile(dir, x, i, ".json");
307
			if(fs.existsSync(jsonf)) it('#' + i + ' (' + ws + ')', function() {
308
				var file = fs.readFileSync(jsonf, 'utf-8');
309
				var json = X.utils.make_json(wb.Sheets[ws]);
310
				assert.equal(JSON.stringify(json), fixjson(file), "JSON badness");
311
			});
312
		});
313
	});
314
	if(fs.existsSync(dir + '2011/' + x + '.xml'))
315
	describe(x + ext + '.xml from 2011', function() {
316
		it('should parse', function() {
317
			/*var wb = */X.readFile(dir + '2011/' + x + '.xml', opts);
318
		});
319
	});
320
	if(fs.existsSync(dir + '2013/' + x + '.xlsb'))
321
	describe(x + ext + '.xlsb from 2013', function() {
322
		it('should parse', function() {
323
			/*var wb = */X.readFile(dir + '2013/' + x + '.xlsb', opts);
324
		});
325
	});
326
	if(fs.existsSync(dir + x + '.xml' + ext))
327
	describe(x + '.xml', function() {
328
		it('should parse', function() {
329
			/*var wb = */X.readFile(dir + x + '.xml', opts);
330
		});
331
	});
332
}
333
334
var wbtable = {};
335
336
(browser ? describe.skip : describe)('should parse test files', function() {
337
	files.forEach(function(x) {
338
		if(x.slice(-8) == ".pending" || !fs.existsSync(dir + x)) return;
339
		it(x, function() {
340
			var wb = X.readFile(dir + x, opts);
341
			wbtable[dir + x] = wb;
342
			parsetest(x, wb, true);
343
		});
344
		fullex.forEach(function(ext) {
345
			it(x + ' [' + ext + ']', function(){
346
				var wb = wbtable[dir + x];
347
				if(!wb) wb = X.readFile(dir + x, opts);
348
				wb = X.read(X.write(wb, {type:"buffer", bookType:ext.replace(/\./,"")}), {WTF:opts.WTF, cellNF: true});
349
				parsetest(x, wb, ext.replace(/\./,"") !== "xlsb", ext);
350
			});
351
		});
352
	});
353
	fileA.forEach(function(x) {
354
		if(x.slice(-8) == ".pending" || !fs.existsSync(dir + x)) return;
355
		it(x, function() {
356
			var wb = X.readFile(dir + x, {WTF:opts.WTF, sheetRows:10});
357
			parsetest(x, wb, false);
358
		});
359
	});
360
});
361
362
function get_cell(ws/*:Worksheet*/, addr/*:string*/) {
363
	if(!Array.isArray(ws)) return ws[addr];
364
	var a = X.utils.decode_cell(addr);
365
	return (ws[a.r]||[])[a.c];
366
}
367
368
function each_cell(ws, f) {
369
	if(Array.isArray(ws)) ws.forEach(function(row) { if(row) row.forEach(f); });
370
	else Object.keys(ws).forEach(function(addr) { if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return; f(ws[addr]); });
371
}
372
373
function each_sheet(wb, f) { wb.SheetNames.forEach(function(n, i) { f(wb.Sheets[n], i); }); }
374
375
/* comments_stress_test family */
376
function check_comments(wb) {
377
	var ws0 = wb.Sheets.Sheet2;
378
	assert.equal(get_cell(ws0,"A1").c[0].a, 'Author');
379
	assert.equal(get_cell(ws0,"A1").c[0].t, 'Author:\nGod thinks this is good');
380
	assert.equal(get_cell(ws0,"C1").c[0].a, 'Author');
381
	assert.equal(get_cell(ws0,"C1").c[0].t, 'I really hope that xlsx decides not to use magic like rPr');
382
383
	var ws3 = wb.Sheets.Sheet4;
384
	assert.equal(get_cell(ws3,"B1").c[0].a, 'Author');
385
	assert.equal(get_cell(ws3,"B1").c[0].t, 'The next comment is empty');
386
	assert.equal(get_cell(ws3,"B2").c[0].a, 'Author');
387
	assert.equal(get_cell(ws3,"B2").c[0].t, '');
388
}
389
390
describe('parse options', function() {
391
	var html_cell_types = ['s'];
392
	var bef = (function() {
393
		X = require(modp);
394
	});
395
	if(typeof before != 'undefined') before(bef);
396
	else it('before', bef);
397
	describe('cell', function() {
398
		it('XLSX should generate HTML by default', function() {
399
			var wb = X.read(fs.readFileSync(paths.cstxlsx), {type:TYPE});
400
			var ws = wb.Sheets.Sheet1;
401
			each_cell(ws, function(cell) {
402
				assert(html_cell_types.indexOf(cell.t) === -1 || cell.h);
403
			});
404
		});
405
		it('XLSX should not generate HTML when requested', function() {
406
			var wb = X.read(fs.readFileSync(paths.cstxlsx), {type:TYPE, cellHTML:false});
407
			var ws = wb.Sheets.Sheet1;
408
			each_cell(ws, function(cell) {
409
				assert(typeof cell.h === 'undefined');
410
			});
411
		});
412
		it('should generate formulae by default', function() {
413
			FSTPaths.forEach(function(p) {
414
				var wb = X.read(fs.readFileSync(p), {type:TYPE});
415
				var found = false;
416
				wb.SheetNames.forEach(function(s) {
417
					each_cell(wb.Sheets[s], function(cell) {
418
						if(typeof cell.f !== 'undefined') return (found = true);
419
					});
420
				});
421
				assert(found);
422
			});
423
		});
424
		it('should not generate formulae when requested', function() {
425
			FSTPaths.forEach(function(p) {
426
				var wb =X.read(fs.readFileSync(p),{type:TYPE,cellFormula:false});
427
				wb.SheetNames.forEach(function(s) {
428
					each_cell(wb.Sheets[s], function(cell) {
429
						assert(typeof cell.f === 'undefined');
430
					});
431
				});
432
			});
433
		});
434
		it('should generate formatted text by default', function() {
435
			FSTPaths.forEach(function(p) {
436
				var wb = X.read(fs.readFileSync(p),{type:TYPE});
437
				var found = false;
438
				wb.SheetNames.forEach(function(s) {
439
					var ws = wb.Sheets[s];
440
					each_cell(ws, function(cell) {
441
						if(typeof cell.w !== 'undefined') return (found = true);
442
					});
443
				});
444
				assert(found);
445
			});
446
		});
447
		it('should not generate formatted text when requested', function() {
448
			FSTPaths.forEach(function(p) {
449
				var wb =X.read(fs.readFileSync(p),{type:TYPE, cellText:false});
450
				wb.SheetNames.forEach(function(s) {
451
					var ws = wb.Sheets[s];
452
					each_cell(ws, function(cell) {
453
						assert(typeof cell.w === 'undefined');
454
					});
455
				});
456
			});
457
		});
458
		it('should not generate number formats by default', function() {
459
			NFPaths.forEach(function(p) {
460
				var wb = X.read(fs.readFileSync(p), {type:TYPE});
461
				wb.SheetNames.forEach(function(s) {
462
					var ws = wb.Sheets[s];
463
					each_cell(ws, function(cell) {
464
						assert(typeof cell.z === 'undefined');
465
					});
466
				});
467
			});
468
		});
469
		it('should generate number formats when requested', function() {
470
			NFPaths.forEach(function(p) {
471
				var wb = X.read(fs.readFileSync(p), {type:TYPE, cellNF: true});
472
				wb.SheetNames.forEach(function(s) {
473
					var ws = wb.Sheets[s];
474
					each_cell(ws, function(cell) {
475
						assert(cell.t!== 'n' || typeof cell.z !== 'undefined');
476
					});
477
				});
478
			});
479
		});
480
		it('should not generate cell styles by default', function() {
481
			CSSPaths.forEach(function(p) {
482
				var wb = X.read(fs.readFileSync(p), {type:TYPE, WTF:1});
483
				wb.SheetNames.forEach(function(s) {
484
					var ws = wb.Sheets[s];
485
					each_cell(ws, function(cell) {
486
						assert(typeof cell.s === 'undefined');
487
					});
488
				});
489
			});
490
		});
491
		it('should generate cell styles when requested', function() {
492
			/* TODO: XLS / XLML */
493
			[paths.cssxlsx /*, paths.cssxlsb, paths.cssxls, paths.cssxml*/].forEach(function(p) {
494
				var wb = X.read(fs.readFileSync(p), {type:TYPE, cellStyles:true});
495
				var found = false;
496
				each_sheet(wb, function(ws/*::, i*/) { /*:: void i; */each_cell(ws, function(cell) {
497
					if(typeof cell.s !== 'undefined') return (found = true);
498
				}); });
499
				assert(found);
500
			});
501
		});
502
		it('should not generate cell dates by default', function() {
503
			DTPaths.forEach(function(p) {
504
				var wb = X.read(fs.readFileSync(p), {type:TYPE});
505
				each_sheet(wb, function(ws/*::, i*/) { /*:: void i; */each_cell(ws, function(cell) {
506
					assert(cell.t !== 'd');
507
				}); });
508
			});
509
		});
510
		it('should generate cell dates when requested', function() {
511
			DTPaths.forEach(function(p) {
512
				var wb = X.read(fs.readFileSync(p), {type:TYPE, cellDates: true, WTF:1});
513
				var found = false;
514
				each_sheet(wb, function(ws/*::, i*/) { /*:: void i; */each_cell(ws, function(cell) {
515
					if(cell.t === 'd') return (found = true);
516
				}); });
517
				assert(found);
518
			});
519
		});
520
	});
521
	describe('sheet', function() {
522
		it('should not generate sheet stubs by default', function() {
523
			MCPaths.forEach(function(p) {
524
				var wb = X.read(fs.readFileSync(p), {type:TYPE});
525
				assert.throws(function() { return get_cell(wb.Sheets.Merge, "A2").v; });
526
			});
527
		});
528
		it('should generate sheet stubs when requested', function() {
529
			MCPaths.forEach(function(p) {
530
				var wb = X.read(fs.readFileSync(p), {type:TYPE, sheetStubs:true});
531
				assert(get_cell(wb.Sheets.Merge, "A2").t == 'z');
532
			});
533
		});
534
		it('should handle stub cells', function() {
535
			MCPaths.forEach(function(p) {
536
				var wb = X.read(fs.readFileSync(p), {type:TYPE, sheetStubs:true});
537
				X.utils.sheet_to_csv(wb.Sheets.Merge);
538
				X.utils.sheet_to_json(wb.Sheets.Merge);
539
				X.utils.sheet_to_formulae(wb.Sheets.Merge);
540
				ofmt.forEach(function(f) { if(f != "dbf") X.write(wb, {type:TYPE, bookType:f}); });
541
			});
542
		});
543
		function checkcells(wb, A46, B26, C16, D2) {
544
			[ ["A46", A46], ["B26", B26], ["C16", C16], ["D2", D2] ].forEach(function(r) {
545
				assert((typeof get_cell(wb.Sheets.Text, r[0]) !== 'undefined') == r[1]);
546
			});
547
		}
548
		it('should read all cells by default', function() { FSTPaths.forEach(function(p) {
549
			checkcells(X.read(fs.readFileSync(p), {type:TYPE}), true, true, true, true);
550
		}); });
551
		it('sheetRows n=30', function() { FSTPaths.forEach(function(p) {
552
			checkcells(X.read(fs.readFileSync(p), {type:TYPE, sheetRows:30}), false, true, true, true);
553
		}); });
554
		it('sheetRows n=20', function() { FSTPaths.forEach(function(p) {
555
			checkcells(X.read(fs.readFileSync(p), {type:TYPE, sheetRows:20}), false, false, true, true);
556
		}); });
557
		it('sheetRows n=10', function() { FSTPaths.forEach(function(p) {
558
			checkcells(X.read(fs.readFileSync(p), {type:TYPE, sheetRows:10}), false, false, false, true);
559
		}); });
560
		it('sheetRows n=1', function() { ofmt.forEach(function(fmt) {
561
			var data = [[1,2],[3,4],[5,6]];
562
			var ws = X.utils.aoa_to_sheet(data);
563
			assert(ws['!ref'] === "A1:B3");
564
			var wb = X.utils.book_new();
565
			X.utils.book_append_sheet(wb, ws, "Sheet1");
566
			var bs = X.write(wb, { bookType: fmt, type: "binary" });
567
568
			var wb0 = X.read(bs, { type: "binary" });
569
			var ws0 = wb0.Sheets.Sheet1;
570
			assert.equal(ws0['!ref'], "A1:B3");
571
			assert.equal(get_cell(ws0, "A1").v, 1);
572
			assert.equal(get_cell(ws0, "B2").v, 4);
573
			assert.equal(get_cell(ws0, "A3").v, 5);
574
575
			var wb1 = X.read(bs, { type: "binary", sheetRows: 1 });
576
			var ws1 = wb1.Sheets.Sheet1;
577
			assert.equal(ws1['!ref'], "A1:B1");
578
			assert.equal(get_cell(ws1, "A1").v, 1);
579
			assert(!get_cell(ws1, "B2"));
580
			assert(!get_cell(ws1, "A3"));
581
			if(ws1['!fullref']) assert.equal(ws1['!fullref'], "A1:B3");
582
583
			var wb2 = X.read(bs, { type: "binary", sheetRows: 2 });
584
			var ws2 = wb2.Sheets.Sheet1;
585
			assert.equal(ws2['!ref'], "A1:B2");
586
			assert.equal(get_cell(ws2, "A1").v, 1);
587
			assert.equal(get_cell(ws2, "B2").v, 4);
588
			assert(!get_cell(ws2, "A3"));
589
			if(ws2['!fullref']) assert.equal(ws2['!fullref'], "A1:B3");
590
591
			var wb3 = X.read(bs, { type: "binary", sheetRows: 3 });
592
			var ws3 = wb3.Sheets.Sheet1;
593
			assert.equal(ws3['!ref'], "A1:B3");
594
			assert.equal(get_cell(ws3, "A1").v, 1);
595
			assert.equal(get_cell(ws3, "B2").v, 4);
596
			assert.equal(get_cell(ws3, "A3").v, 5);
597
			if(ws3['!fullref']) assert.equal(ws3['!fullref'], "A1:B3");
598
		}); });
599
	});
600
	describe('book', function() {
601
		it('bookSheets should not generate sheets', function() {
602
			MCPaths.forEach(function(p) {
603
				var wb = X.read(fs.readFileSync(p), {type:TYPE, bookSheets:true});
604
				assert(typeof wb.Sheets === 'undefined');
605
			});
606
		});
607
		it('bookProps should not generate sheets', function() {
608
			NFPaths.forEach(function(p) {
609
				var wb = X.read(fs.readFileSync(p), {type:TYPE, bookProps:true});
610
				assert(typeof wb.Sheets === 'undefined');
611
			});
612
		});
613
		it('bookProps && bookSheets should not generate sheets', function() {
614
			PMPaths.forEach(function(p) {
615
				if(!fs.existsSync(p)) return;
616
				var wb = X.read(fs.readFileSync(p), {type:TYPE, bookProps:true, bookSheets:true});
617
				assert(typeof wb.Sheets === 'undefined');
618
			});
619
		});
620
621
		var FSTXL = [
622
			[paths.fstxlsx, true],
623
			[paths.fstxlsb, true],
624
			[paths.fstxls, false]
625
		];
626
		it('should not generate deps by default', function() {
627
			FSTPaths.forEach(function(p) {
628
				var wb = X.read(fs.readFileSync(p), {type:TYPE});
629
				assert(typeof wb.Deps === 'undefined' || !(wb.Deps && wb.Deps.length>0));
630
			});
631
		});
632
		it('bookDeps should generate deps (XLSX/XLSB)', function() {
633
			FSTXL.forEach(function(p) {
634
				if(!p[1]) return;
635
				var wb = X.read(fs.readFileSync(p[0]), {type:TYPE, bookDeps:true});
636
				assert(typeof wb.Deps !== 'undefined' && wb.Deps.length > 0);
637
			});
638
		});
639
640
		var ckf = function(wb, fields, exists) { fields.forEach(function(f) { assert((typeof wb[f] !== 'undefined') == exists); }); };
641
		it('should not generate book files by default', function() {FSTXL.forEach(function(r) {
642
			var wb = X.read(fs.readFileSync(r[0]), {type:TYPE});
643
			ckf(wb, r[1] ? ['files', 'keys'] : ['cfb'], false);
644
		}); });
645
		it('bookFiles should generate book files', function() {FSTXL.forEach(function(r) {
646
			var wb = X.read(fs.readFileSync(r[0]), {type:TYPE, bookFiles:true});
647
			ckf(wb, r[1] ? ['files', 'keys'] : ['cfb'], true);
648
		}); });
649
650
		var NFVBA = ["nfxlsx", "nfxlsb", "nfxls"].map(function(n) { return paths[n]; });
651
		it('should not generate VBA by default', function() { NFPaths.forEach(function(p) {
652
			var wb = X.read(fs.readFileSync(p), {type:TYPE}); assert(typeof wb.vbaraw === 'undefined');
653
		}); });
654
		it('bookVBA should generate vbaraw', function() { NFVBA.forEach(function(p) {
655
			var wb = X.read(fs.readFileSync(p),{type: TYPE, bookVBA: true});
656
			assert(wb.vbaraw);
657
			var cfb = X.CFB.read(wb.vbaraw, {type: 'array'});
658
			assert(X.CFB.find(cfb, '/VBA/ThisWorkbook'));
659
		}); });
660
	});
661
});
662
663
describe('input formats', function() {
664
	it('should read binary strings', function() { artifax.forEach(function(p) {
665
		X.read(fs.readFileSync(p, 'binary'), {type: 'binary'});
666
	}); });
667
	it('should read base64 strings', function() { artifax.forEach(function(p) {
668
		X.read(fs.readFileSync(p, 'base64'), {type: 'base64'});
669
	}); });
670
	(typeof Uint8Array !== 'undefined' ? it : it.skip)('should read array', function() { artifax.forEach(function(p) {
671
		X.read(fs.readFileSync(p, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'});
672
	}); });
673
	((browser || typeof Buffer === 'undefined') ? it.skip : it)('should read Buffers', function() { artifax.forEach(function(p) {
674
		X.read(fs.readFileSync(p), {type: 'buffer'});
675
	}); });
676
	(typeof Uint8Array !== 'undefined' ? it : it.skip)('should read ArrayBuffer / Uint8Array', function() { artifax.forEach(function(p) {
677
		var payload = fs.readFileSync(p, browser ? 'buffer' : null);
678
		var ab = new ArrayBuffer(payload.length), vu = new Uint8Array(ab);
679
		for(var i = 0; i < payload.length; ++i) vu[i] = payload[i];
680
		X.read(ab, {type: 'array'});
681
		X.read(vu, {type: 'array'});
682
	}); });
683
	it('should throw if format is unknown', function() { artifax.forEach(function(p) {
684
		assert.throws(function() { X.read(fs.readFileSync(p), {type: 'dafuq'}); });
685
	}); });
686
687
	var T = browser ? 'base64' : 'buffer';
688
	it('should default to "' + T + '" type', function() { artifax.forEach(function(p) {
689
		X.read(fs.readFileSync.apply(fs, browser ? [p, 'base64'] : [p]));
690
	}); });
691
	if(!browser) it('should read files', function() { artifax.forEach(function(p) { X.readFile(p); }); });
692
});
693
694
describe('output formats', function() {
695
	var fmts = [
696
		/* fmt   unicode   str */
697
		["xlsx",   true,  false],
698
		["xlsb",   true,  false],
699
		["xls",    true,  false],
700
		["xlml",   true,   true],
701
		["ods",    true,  false],
702
		["fods",   true,   true],
703
		["csv",    true,   true],
704
		["txt",    true,   true],
705
		["sylk",  false,   true],
706
		["eth",   false,   true],
707
		["html",   true,   true],
708
		["dif",   false,   true],
709
		["dbf",   false,  false],
710
		["prn",   false,   true]
711
	];
712
	function RT(T) {
713
		if(!X) X = require(modp);
714
		fmts.forEach(function(fmt) {
715
			var wb = X.utils.book_new();
716
			X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([['R',"\u2603"],["\u0BEE",2]]), "Sheet1");
717
			if(T == 'string' && !fmt[2]) return assert.throws(function() {X.write(wb, {type: T, bookType:fmt[0], WTF:1});});
718
			var out = X.write(wb, {type: T, bookType:fmt[0], WTF:1});
719
			var nwb = X.read(out, {type: T, WTF:1});
720
			var nws = nwb.Sheets[nwb.SheetNames[0]];
721
			assert.equal(get_cell(nws, "B2").v, 2);
722
			assert.equal(get_cell(nws, "A1").v, "R");
723
			if(fmt[1]) assert.equal(get_cell(nws, "A2").v, "\u0BEE");
724
			if(fmt[1]) assert.equal(get_cell(nws, "B1").v, "\u2603");
725
		});
726
	}
727
	it('should write binary strings', function() { RT('binary'); });
728
	it('should write base64 strings', function() { RT('base64'); });
729
	it('should write JS strings', function() { RT('string'); });
730
	if(typeof ArrayBuffer !== 'undefined' && (typeof process == 'undefined' || !process.version.match(/v0.12/))) it('should write array buffers', function() { RT('array'); });
731
	if(!browser) it('should write buffers', function() { RT('buffer'); });
732
	it('should throw if format is unknown', function() { assert.throws(function() { RT('dafuq'); }); });
733
});
734
735
function eqarr(a,b) {
736
	assert.equal(a.length, b.length);
737
	a.forEach(function(x, i) { assert.equal(x, b[i]); });
738
}
739
740
describe('API', function() {
741
	it('book_append_sheet', function() {
742
		var wb = X.utils.book_new();
743
		X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([[1,2,3],[4],[5]]), "A");
744
		X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([[1,2,3],[4],[5]]));
745
		X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([[1,2,3],[4],[5]]));
746
		X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([[1,2,3],[4],[5]]), "B");
747
		X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([[1,2,3],[4],[5]]));
748
		eqarr(wb.SheetNames, ["A","Sheet1","Sheet2","B","Sheet3"]);
749
	});
750
	it('sheet_add_json', function() {
751
		var ws = X.utils.json_to_sheet([{A:"S", B:"h", C:"e", D:"e", E:"t", F:"J", G:"S"}], {header:["A","B","C","D","E","F","G"], skipHeader:true});
752
		X.utils.sheet_add_json(ws, [{A:1, B:2}, {A:2, B:3}, {A:3, B:4}], {skipHeader:true, origin:"A2"});
753
		X.utils.sheet_add_json(ws, [{A:5, B:6, C:7}, {A:6, B:7, C:8}, {A:7, B:8, C:9}], {skipHeader:true, origin:{r:1, c:4}, header:["A","B","C"]});
754
		X.utils.sheet_add_json(ws, [{A:4, B:5, C:6, D:7, E:8, F:9, G:0}], {header:["A","B","C","D","E","F","G"], skipHeader:true, origin:-1});
755
		assert.equal(X.utils.sheet_to_csv(ws).trim(), "S,h,e,e,t,J,S\n1,2,,,5,6,7\n2,3,,,6,7,8\n3,4,,,7,8,9\n4,5,6,7,8,9,0");
756
	});
757
	it('sheet_add_aoa', function() {
758
		var ws = X.utils.aoa_to_sheet([ "SheetJS".split("") ]);
759
		X.utils.sheet_add_aoa(ws, [[1,2], [2,3], [3,4]], {origin: "A2"});
760
		X.utils.sheet_add_aoa(ws, [[5,6,7], [6,7,8], [7,8,9]], {origin:{r:1, c:4}});
761
		X.utils.sheet_add_aoa(ws, [[4,5,6,7,8,9,0]], {origin: -1});
762
		assert.equal(X.utils.sheet_to_csv(ws).trim(), "S,h,e,e,t,J,S\n1,2,,,5,6,7\n2,3,,,6,7,8\n3,4,,,7,8,9\n4,5,6,7,8,9,0");
763
	});
764
});
765
766
function coreprop(props) {
767
	assert.equal(props.Title, 'Example with properties');
768
	assert.equal(props.Subject, 'Test it before you code it');
769
	assert.equal(props.Author, 'Pony Foo');
770
	assert.equal(props.Manager, 'Despicable Drew');
771
	assert.equal(props.Company, 'Vector Inc');
772
	assert.equal(props.Category, 'Quirky');
773
	assert.equal(props.Keywords, 'example humor');
774
	assert.equal(props.Comments, 'some comments');
775
	assert.equal(props.LastAuthor, 'Hugues');
776
}
777
function custprop(props) {
778
	assert.equal(props['I am a boolean'], true);
779
	assert.equal(props['Date completed'].toISOString(), '1967-03-09T16:30:00.000Z');
780
	assert.equal(props.Status, 2);
781
	assert.equal(props.Counter, -3.14);
782
}
783
784
function cmparr(x){ for(var i=1;i<x.length;++i) assert.deepEqual(x[0], x[i]); }
785
786
function deepcmp(x,y,k,m,c) {
787
	var s = k.indexOf(".");
788
	m = (m||"") + "|" + (s > -1 ? k.substr(0,s) : k);
789
	if(s < 0) return assert[c<0?'notEqual':'equal'](x[k], y[k], m);
790
	return deepcmp(x[k.substr(0,s)],y[k.substr(0,s)],k.substr(s+1),m,c);
791
}
792
793
var styexc = [
794
	'A2|H10|bgColor.rgb',
795
	'F6|H1|patternType'
796
];
797
var stykeys = [
798
	"patternType",
799
	"fgColor.rgb",
800
	"bgColor.rgb"
801
];
802
function diffsty(ws, r1,r2) {
803
	var c1 = get_cell(ws,r1).s, c2 = get_cell(ws,r2).s;
804
	stykeys.forEach(function(m) {
805
		var c = -1;
806
		if(styexc.indexOf(r1+"|"+r2+"|"+m) > -1) c = 1;
807
		else if(styexc.indexOf(r2+"|"+r1+"|"+m) > -1) c = 1;
808
		deepcmp(c1,c2,m,r1+","+r2,c);
809
	});
810
}
811
812
function hlink1(ws) {[
813
	["A1", "http://www.sheetjs.com"],
814
	["A2", "http://oss.sheetjs.com"],
815
	["A3", "http://oss.sheetjs.com#foo"],
816
	["A4", "mailto:[email protected]"],
817
	["A5", "mailto:[email protected]?subject=hyperlink"],
818
	["A6", "../../sheetjs/Documents/Test.xlsx"],
819
	["A7", "http://sheetjs.com", "foo bar baz"]
820
].forEach(function(r) {
821
	assert.equal(get_cell(ws, r[0]).l.Target, r[1]);
822
	if(r[2]) assert.equal(get_cell(ws, r[0]).l.Tooltip, r[2]);
823
}); }
824
825
function hlink2(ws) { [
826
	["A1", "#Sheet2!A1"],
827
	["A2", "#WBScope"],
828
	["A3", "#Sheet1!WSScope1", "#Sheet1!C7:E8"],
829
	["A5", "#Sheet1!A5"]
830
].forEach(function(r) {
831
	if(r[2] && get_cell(ws, r[0]).l.Target == r[2]) return;
832
	assert.equal(get_cell(ws, r[0]).l.Target, r[1]);
833
}); }
834
835
function check_margin(margins, exp) {
836
	["left", "right", "top", "bottom", "header", "footer"].forEach(function(m,i) {
837
		assert.equal(margins[m],   exp[i]);
838
	});
839
}
840
841
describe('parse features', function() {
842
	describe('sheet visibility', function() {
843
		var wbs = [];
844
		var bef = (function() {
845
			wbs = SVPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
846
		});
847
		if(typeof before != 'undefined') before(bef);
848
		else it('before', bef);
849
850
		it('should detect visible sheets', function() {
851
			if(!wbs.length) bef();
852
			wbs.forEach(function(wb) {
853
				assert(!wb.Workbook.Sheets[0].Hidden);
854
			});
855
		});
856
		it('should detect all hidden sheets', function() {
857
			wbs.forEach(function(wb) {
858
				assert(wb.Workbook.Sheets[1].Hidden);
859
				assert(wb.Workbook.Sheets[2].Hidden);
860
			});
861
		});
862
		it('should distinguish very hidden sheets', function() {
863
			wbs.forEach(function(wb) {
864
				assert.equal(wb.Workbook.Sheets[1].Hidden,1);
865
				assert.equal(wb.Workbook.Sheets[2].Hidden,2);
866
			});
867
		});
868
	});
869
870
	describe('comments', function() {
871
		if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){
872
			X = require(modp);
873
			var sheet = 'Sheet1';
874
			var wb1=X.read(fs.readFileSync(paths.swcxlsx), {type:TYPE});
875
			var wb2=X.read(fs.readFileSync(paths.swcxlsb), {type:TYPE});
876
			var wb3=X.read(fs.readFileSync(paths.swcxls), {type:TYPE});
877
			var wb4=X.read(fs.readFileSync(paths.swcxml), {type:TYPE});
878
879
			[wb1,wb2,wb3,wb4].map(function(wb) { return wb.Sheets[sheet]; }).forEach(function(ws, i) {
880
				assert.equal(get_cell(ws, "B1").c.length, 1,"must have 1 comment");
881
				assert.equal(get_cell(ws, "B1").c[0].a, "Yegor Kozlov","must have the same author");
882
				assert.equal(get_cell(ws, "B1").c[0].t, "Yegor Kozlov:\nfirst cell", "must have the concatenated texts");
883
				if(i > 0) return;
884
				assert.equal(get_cell(ws, "B1").c[0].r, '<r><rPr><b/><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t>Yegor Kozlov:</t></r><r><rPr><sz val="8"/><color indexed="81"/><rFont val="Tahoma"/></rPr><t xml:space="preserve">\r\nfirst cell</t></r>', "must have the rich text representation");
885
				assert.equal(get_cell(ws, "B1").c[0].h, '<span style="font-size:8pt;"><b>Yegor Kozlov:</b></span><span style="font-size:8pt;"><br/>first cell</span>', "must have the html representation");
886
			});
887
		});
888
		[
889
			['xlsx', paths.cstxlsx],
890
			['xlsb', paths.cstxlsb],
891
			['xls', paths.cstxls],
892
			['xlml', paths.cstxml],
893
			['ods', paths.cstods]
894
		].forEach(function(m) { it(m[0] + ' stress test', function() {
895
			var wb = X.read(fs.readFileSync(m[1]), {type:TYPE});
896
			check_comments(wb);
897
			var ws0 = wb.Sheets.Sheet2;
898
			assert.equal(get_cell(ws0,"A1").c[0].a, 'Author');
899
			assert.equal(get_cell(ws0,"A1").c[0].t, 'Author:\nGod thinks this is good');
900
			assert.equal(get_cell(ws0,"C1").c[0].a, 'Author');
901
			assert.equal(get_cell(ws0,"C1").c[0].t, 'I really hope that xlsx decides not to use magic like rPr');
902
		}); });
903
	});
904
905
	describe('should parse core properties and custom properties', function() {
906
		var wbs=[];
907
		var bef = (function() {
908
			wbs = [
909
				X.read(fs.readFileSync(paths.cpxlsx), {type:TYPE, WTF:1}),
910
				X.read(fs.readFileSync(paths.cpxlsb), {type:TYPE, WTF:1}),
911
				X.read(fs.readFileSync(paths.cpxls), {type:TYPE, WTF:1}),
912
				X.read(fs.readFileSync(paths.cpxml), {type:TYPE, WTF:1})
913
			];
914
		});
915
		if(typeof before != 'undefined') before(bef);
916
		else it('before', bef);
917
918
		['XLSX', 'XLSB', 'XLS', 'XML'].forEach(function(x, i) {
919
			it(x + ' should parse core properties', function() { coreprop(wbs[i].Props); });
920
			it(x + ' should parse custom properties', function() { custprop(wbs[i].Custprops); });
921
		});
922
		[
923
			["asxls",  "BIFF8", "\u2603"],
924
			["asxls5", "BIFF5", "_"],
925
			["asxml",   "XLML", "\u2603"],
926
			["asods",    "ODS", "God"],
927
			["asxlsx",  "XLSX", "\u2603"],
928
			["asxlsb",  "XLSB", "\u2603"]
929
		].forEach(function(x) {
930
		(fs.existsSync(paths[x[0]]) ? it : it.skip)(x[1] + ' should read ' + (x[2] == "\u2603" ? 'unicode ' : "") + 'author', function() {
931
			var wb = X.read(fs.readFileSync(paths[x[0]]), {type:TYPE});
932
			assert.equal(wb.Props.Author, x[2]);
933
		}); });
934
		var BASE = "இராமா";
935
		/* TODO: ODS, XLS */
936
		[ "xlsx", "xlsb", "xlml"/*, "ods", "xls" */].forEach(function(n) {
937
		it(n + ' should round-trip unicode category', function() {
938
			var wb = X.utils.book_new();
939
			X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([["a"]]), "Sheet1");
940
			if(!wb.Props) wb.Props = {};
941
			wb.Props.Category = BASE;
942
			var wb2 = X.read(X.write(wb, {bookType:n, type:TYPE}), {type:TYPE});
943
			assert.equal(wb2.Props.Category,BASE);
944
		}); });
945
	});
946
947
	describe('sheetRows', function() {
948
		it('should use original range if not set', function() {
949
			var opts = {type:TYPE};
950
			FSTPaths.map(function(p) { return X.read(fs.readFileSync(p), opts); }).forEach(function(wb) {
951
				assert.equal(wb.Sheets.Text["!ref"],"A1:F49");
952
			});
953
		});
954
		it('should adjust range if set', function() {
955
			var opts = {type:TYPE, sheetRows:10};
956
			var wbs = FSTPaths.map(function(p) { return X.read(fs.readFileSync(p), opts); });
957
			/* TODO: XLS, XML, ODS */
958
			wbs.slice(0,2).forEach(function(wb) {
959
				assert.equal(wb.Sheets.Text["!fullref"],"A1:F49");
960
				assert.equal(wb.Sheets.Text["!ref"],"A1:F10");
961
			});
962
		});
963
		it('should not generate comment cells', function() {
964
			var opts = {type:TYPE, sheetRows:10};
965
			var wbs = CSTPaths.map(function(p) { return X.read(fs.readFileSync(p), opts); });
966
			/* TODO: XLS, XML, ODS */
967
			wbs.slice(0,2).forEach(function(wb) {
968
				assert.equal(wb.Sheets.Sheet7["!fullref"],"A1:N34");
969
				assert.equal(wb.Sheets.Sheet7["!ref"],"A1");
970
			});
971
		});
972
	});
973
974
	describe('column properties', function() {
975
		var wbs = [], wbs_no_slk = [];
976
		var bef = (function() {
977
			X = require(modp);
978
			wbs = CWPaths.map(function(n) { return X.read(fs.readFileSync(n), {type:TYPE, cellStyles:true}); });
979
			wbs_no_slk = wbs.slice(0, 5);
980
		});
981
		if(typeof before != 'undefined') before(bef);
982
		else it('before', bef);
983
		it('should have "!cols"', function() {
984
			wbs.forEach(function(wb) { assert(wb.Sheets.Sheet1['!cols']); });
985
		});
986
		it('should have correct widths', function() {
987
			/* SYLK rounds wch so skip non-integral */
988
			wbs_no_slk.map(function(x) { return x.Sheets.Sheet1['!cols']; }).forEach(function(x) {
989
				assert.equal(x[1].width, 0.1640625);
990
				assert.equal(x[2].width, 16.6640625);
991
				assert.equal(x[3].width, 1.6640625);
992
			});
993
			wbs.map(function(x) { return x.Sheets.Sheet1['!cols']; }).forEach(function(x) {
994
				assert.equal(x[4].width, 4.83203125);
995
				assert.equal(x[5].width, 8.83203125);
996
				assert.equal(x[6].width, 12.83203125);
997
				assert.equal(x[7].width, 16.83203125);
998
			});
999
		});
1000
		it('should have correct pixels', function() {
1001
			/* SYLK rounds wch so skip non-integral */
1002
			wbs_no_slk.map(function(x) { return x.Sheets.Sheet1['!cols']; }).forEach(function(x) {
1003
				assert.equal(x[1].wpx, 1);
1004
				assert.equal(x[2].wpx, 100);
1005
				assert.equal(x[3].wpx, 10);
1006
			});
1007
			wbs.map(function(x) { return x.Sheets.Sheet1['!cols']; }).forEach(function(x) {
1008
				assert.equal(x[4].wpx, 29);
1009
				assert.equal(x[5].wpx, 53);
1010
				assert.equal(x[6].wpx, 77);
1011
				assert.equal(x[7].wpx, 101);
1012
			});
1013
		});
1014
	});
1015
1016
	describe('row properties', function() {
1017
		var wbs = [], ols = [];
1018
		var ol = fs.existsSync(paths.olxls);
1019
		var bef = (function() {
1020
			X = require(modp);
1021
			wbs = RHPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, cellStyles:true}); });
1022
			/* */
1023
			if(!ol) return;
1024
			ols = OLPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, cellStyles:true}); });
1025
		});
1026
		if(typeof before != 'undefined') before(bef);
1027
		else it('before', bef);
1028
		it('should have "!rows"', function() {
1029
			wbs.forEach(function(wb) { assert(wb.Sheets.Sheet1['!rows']); });
1030
		});
1031
		it('should have correct points', function() {
1032
			wbs.map(function(x) { return x.Sheets.Sheet1['!rows']; }).forEach(function(x) {
1033
				assert.equal(x[1].hpt, 1);
1034
				assert.equal(x[2].hpt, 10);
1035
				assert.equal(x[3].hpt, 100);
1036
			});
1037
		});
1038
		it('should have correct pixels', function() {
1039
			wbs.map(function(x) { return x.Sheets.Sheet1['!rows']; }).forEach(function(x) {
1040
				/* note: at 96 PPI hpt == hpx */
1041
				assert.equal(x[1].hpx, 1);
1042
				assert.equal(x[2].hpx, 10);
1043
				assert.equal(x[3].hpx, 100);
1044
			});
1045
		});
1046
		(ol ? it : it.skip)('should have correct outline levels', function() {
1047
			ols.map(function(x) { return x.Sheets.Sheet1; }).forEach(function(ws) {
1048
				var rows = ws['!rows'];
1049
				for(var i = 0; i < 29; ++i) {
1050
					var cell = get_cell(ws, "A" + X.utils.encode_row(i));
1051
					var lvl = (rows[i]||{}).level||0;
1052
					if(!cell || cell.t == 's') assert.equal(lvl, 0);
1053
					else if(cell.t == 'n') {
1054
						if(cell.v === 0) assert.equal(lvl, 0);
1055
						else assert.equal(lvl, cell.v);
1056
					}
1057
				}
1058
				assert.equal(rows[29].level, 7);
1059
			});
1060
		});
1061
	});
1062
1063
	describe('merge cells',function() {
1064
		var wbs=[];
1065
		var bef = (function() {
1066
			X = require(modp);
1067
			wbs = MCPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
1068
		});
1069
		if(typeof before != 'undefined') before(bef);
1070
		else it('before', bef);
1071
		it('should have !merges', function() {
1072
			wbs.forEach(function(wb) {
1073
				assert(wb.Sheets.Merge['!merges']);
1074
			});
1075
			var m = wbs.map(function(x) { return x.Sheets.Merge['!merges'].map(function(y) { return X.utils.encode_range(y); });});
1076
			m.slice(1).forEach(function(x) {
1077
				assert.deepEqual(m[0].sort(),x.sort());
1078
			});
1079
		});
1080
	});
1081
1082
	describe('should find hyperlinks', function() {
1083
		var wb1, wb2;
1084
		var bef = (function() {
1085
			X = require(modp);
1086
			wb1 = HLPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, WTF:1}); });
1087
			wb2 = ILPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, WTF:1}); });
1088
		});
1089
		if(typeof before != 'undefined') before(bef);
1090
		else it('before', bef);
1091
1092
		['xlsx', 'xlsb', 'xls', 'xml'].forEach(function(x, i) {
1093
			it(x + " external", function() { hlink1(wb1[i].Sheets.Sheet1); });
1094
		});
1095
		['xlsx', 'xlsb', 'xls', 'xml', 'ods'].forEach(function(x, i) {
1096
			it(x + " internal", function() { hlink2(wb2[i].Sheets.Sheet1); });
1097
		});
1098
	});
1099
1100
	describe('should parse cells with date type (XLSX/XLSM)', function() {
1101
		it('Must have read the date', function() {
1102
			var wb, ws;
1103
			var sheetName = 'Sheet1';
1104
			wb = X.read(fs.readFileSync(paths.dtxlsx), {type:TYPE});
1105
			ws = wb.Sheets[sheetName];
1106
			var sheet = X.utils.sheet_to_json(ws);
1107
			assert.equal(sheet[3]['てすと'], '2/14/14');
1108
		});
1109
		it('cellDates should not affect formatted text', function() {
1110
			var sheetName = 'Sheet1';
1111
			var ws1 = X.read(fs.readFileSync(paths.dtxlsx), {type:TYPE}).Sheets[sheetName];
1112
			var ws2 = X.read(fs.readFileSync(paths.dtxlsb), {type:TYPE}).Sheets[sheetName];
1113
			assert.equal(X.utils.sheet_to_csv(ws1),X.utils.sheet_to_csv(ws2));
1114
		});
1115
	});
1116
1117
	describe('cellDates', function() {
1118
		var fmts = [
1119
			/* desc     path        sheet     cell   formatted */
1120
			['XLSX', paths.dtxlsx, 'Sheet1',  'B5',  '2/14/14'],
1121
			['XLSB', paths.dtxlsb, 'Sheet1',  'B5',  '2/14/14'],
1122
			['XLS',  paths.dtxls,  'Sheet1',  'B5',  '2/14/14'],
1123
			['XLML', paths.dtxml,  'Sheet1',  'B5',  '2/14/14'],
1124
			['XLSM', paths.nfxlsx, 'Implied', 'B13', '18-Oct-33']
1125
		];
1126
		it('should not generate date cells by default', function() { fmts.forEach(function(f) {
1127
			var wb, ws;
1128
			wb = X.read(fs.readFileSync(f[1]), {type:TYPE});
1129
			ws = wb.Sheets[f[2]];
1130
			assert.equal(get_cell(ws, f[3]).w, f[4]);
1131
			assert.equal(get_cell(ws, f[3]).t, 'n');
1132
		}); });
1133
		it('should generate date cells if cellDates is true', function() { fmts.forEach(function(f) {
1134
			var wb, ws;
1135
			wb = X.read(fs.readFileSync(f[1]), {type:TYPE, cellDates:true});
1136
			ws = wb.Sheets[f[2]];
1137
			assert.equal(get_cell(ws, f[3]).w, f[4]);
1138
			assert.equal(get_cell(ws, f[3]).t, 'd');
1139
		}); });
1140
	});
1141
1142
	describe('defined names', function() {[
1143
		/* desc     path        cmnt */
1144
		['xlsx', paths.dnsxlsx,  true],
1145
		['xlsb', paths.dnsxlsb,  true],
1146
		['xls',  paths.dnsxls,   true],
1147
		['xlml', paths.dnsxml,  false]
1148
	].forEach(function(m) { it(m[0], function() {
1149
		var wb = X.read(fs.readFileSync(m[1]), {type:TYPE});
1150
		var names = wb.Workbook.Names;
1151
		for(var i = 0; i < names.length; ++i) if(names[i].Name == "SheetJS") break;
1152
		assert(i < names.length, "Missing name");
1153
		assert.equal(names[i].Sheet, null);
1154
		assert.equal(names[i].Ref, "Sheet1!$A$1");
1155
		if(m[2]) assert.equal(names[i].Comment, "defined names just suck  excel formulae are bad  MS should feel bad");
1156
1157
		for(i = 0; i < names.length; ++i) if(names[i].Name == "SHEETjs") break;
1158
		assert(i < names.length, "Missing name");
1159
		assert.equal(names[i].Sheet, 0);
1160
		assert.equal(names[i].Ref, "Sheet1!$A$2");
1161
	}); }); });
1162
1163
	describe('defined names unicode', function() {[
1164
		/* desc     path      */
1165
		['xlsx', paths.dnuxlsx],
1166
		['xlsb', paths.dnuxlsb],
1167
		['ods',  paths.dnuods ],
1168
		['xls',  paths.dnuxls ],
1169
		['xlml', paths.dnuxml ]
1170
	].forEach(function(m) { it(m[0], function() {
1171
		var wb = X.read(fs.readFileSync(m[1]), {type:TYPE});
1172
		[
1173
			"NoContainsJapanese",
1174
			"\u65E5\u672C\u8a9e\u306e\u307f",
1175
			"sheet\u65e5\u672c\u8a9e",
1176
			"\u65e5\u672c\u8a9esheet",
1177
			"sheet\u65e5\u672c\u8a9esheet"
1178
		].forEach(function(n, i) { assert.equal(wb.SheetNames[i], n); });
1179
		[
1180
			["name\u65e5\u672c\u8a9e", "sheet\u65e5\u672c\u8a9e!$A$1"],
1181
			["name\u65e5\u672c\u8a9ename", "sheet\u65e5\u672c\u8a9esheet!$B$2"],
1182
			["NoContainsJapaneseName", "\u65e5\u672c\u8a9e\u306e\u307f!$A$1"],
1183
			["sheet\u65e5\u672c\u8a9e", "sheet\u65e5\u672c\u8a9e!$A$1"],
1184
			["\u65e5\u672c\u8a9e", "NoContainsJapanese!$A$1"],
1185
			["\u65e5\u672c\u8a9ename", "\u65e5\u672c\u8a9esheet!$I$2"]
1186
		].forEach(function(n) {
1187
			var DN = null;
1188
			var arr = wb.Workbook.Names;
1189
			for(var j = 0; j < arr.length; ++j) if(arr[j].Name == n[0]) DN = arr[j];
1190
			assert(DN);
1191
			// $FlowIgnore
1192
			assert.equal(DN.Ref, n[1]);
1193
		});
1194
	}); }); });
1195
1196
	describe('auto filter', function() {[
1197
		['xlsx', paths.afxlsx],
1198
		['xlsb', paths.afxlsb],
1199
		['xls',  paths.afxls],
1200
		['xlml', paths.afxml],
1201
		['ods',  paths.afods]
1202
	].forEach(function(m) { it(m[0], function() {
1203
		var wb = X.read(fs.readFileSync(m[1]), {type:TYPE});
1204
		assert(!wb.Sheets[wb.SheetNames[0]]['!autofilter']);
1205
		for(var i = 1; i < wb.SheetNames.length; ++i) {
1206
			assert(wb.Sheets[wb.SheetNames[i]]['!autofilter']);
1207
			assert.equal(wb.Sheets[wb.SheetNames[i]]['!autofilter'].ref,"A1:E22");
1208
		}
1209
	}); }); });
1210
1211
	describe('HTML', function() {
1212
		var ws, wb;
1213
		var bef = (function() {
1214
			ws = X.utils.aoa_to_sheet([
1215
				["a","b","c"],
1216
				["&","<",">","\n"]
1217
			]);
1218
			wb = {SheetNames:["Sheet1"],Sheets:{Sheet1:ws}};
1219
		});
1220
		if(typeof before != 'undefined') before(bef);
1221
		else it('before', bef);
1222
		['xlsx'].forEach(function(m) { it(m, function() {
1223
			var wb2 = X.read(X.write(wb, {bookType:m, type:TYPE}),{type:TYPE, cellHTML:true});
1224
			assert.equal(get_cell(wb2.Sheets.Sheet1, "A2").h, "&amp;");
1225
			assert.equal(get_cell(wb2.Sheets.Sheet1, "B2").h, "&lt;");
1226
			assert.equal(get_cell(wb2.Sheets.Sheet1, "C2").h, "&gt;");
1227
			assert.equal(get_cell(wb2.Sheets.Sheet1, "D2").h, "<br/>");
1228
		}); });
1229
	});
1230
1231
	describe('page margins', function() {
1232
		var wbs=[];
1233
		var bef = (function() {
1234
			if(!fs.existsSync(paths.pmxls)) return;
1235
			wbs = PMPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, WTF:1}); });
1236
		});
1237
		if(typeof before != 'undefined') before(bef);
1238
		else it('before', bef);
1239
		[
1240
			/* Sheet Name     Margins: left   right  top bottom head foot */
1241
			["Normal",                 [0.70, 0.70, 0.75, 0.75, 0.30, 0.30]],
1242
			["Wide",                   [1.00, 1.00, 1.00, 1.00, 0.50, 0.50]],
1243
			["Narrow",                 [0.25, 0.25, 0.75, 0.75, 0.30, 0.30]],
1244
			["Custom 1 Inch Centered", [1.00, 1.00, 1.00, 1.00, 0.30, 0.30]],
1245
			["1 Inch HF",              [0.70, 0.70, 0.75, 0.75, 1.00, 1.00]]
1246
		].forEach(function(t) { it('should parse ' + t[0] + ' margin', function() { wbs.forEach(function(wb) {
1247
			check_margin(wb.Sheets[t[0]]["!margins"], t[1]);
1248
		}); }); });
1249
	});
1250
1251
	describe('should correctly handle styles', function() {
1252
		var wsxls, wsxlsx, rn, rn2;
1253
		var bef = (function() {
1254
			wsxls=X.read(fs.readFileSync(paths.cssxls), {type:TYPE,cellStyles:true,WTF:1}).Sheets.Sheet1;
1255
			wsxlsx=X.read(fs.readFileSync(paths.cssxlsx), {type:TYPE,cellStyles:true,WTF:1}).Sheets.Sheet1;
1256
			rn = function(range) {
1257
				var r = X.utils.decode_range(range);
1258
				var out = [];
1259
				for(var R = r.s.r; R <= r.e.r; ++R) for(var C = r.s.c; C <= r.e.c; ++C)
1260
					out.push(X.utils.encode_cell({c:C,r:R}));
1261
				return out;
1262
			};
1263
			rn2 = function(r) { return [].concat.apply([], r.split(",").map(rn)); };
1264
		});
1265
		if(typeof before != 'undefined') before(bef);
1266
		else it('before', bef);
1267
		var ranges = [
1268
			'A1:D1,F1:G1', 'A2:D2,F2:G2', /* rows */
1269
			'A3:A10', 'B3:B10', 'E1:E10', 'F6:F8', /* cols */
1270
			'H1:J4', 'H10' /* blocks */
1271
		];
1272
		/*eslint-disable */
1273
		var exp/*:Array<any>*/ = [
1274
			{ patternType: 'darkHorizontal',
1275
			  fgColor: { theme: 9, raw_rgb: 'F79646' },
1276
			  bgColor: { theme: 5, raw_rgb: 'C0504D' } },
1277
			{ patternType: 'darkUp',
1278
			  fgColor: { theme: 3, raw_rgb: 'EEECE1' },
1279
			  bgColor: { theme: 7, raw_rgb: '8064A2' } },
1280
			{ patternType: 'darkGray',
1281
			  fgColor: { theme: 3, raw_rgb: 'EEECE1' },
1282
			  bgColor: { theme: 1, raw_rgb: 'FFFFFF' } },
1283
			{ patternType: 'lightGray',
1284
			  fgColor: { theme: 6, raw_rgb: '9BBB59' },
1285
			  bgColor: { theme: 2, raw_rgb: '1F497D' } },
1286
			{ patternType: 'lightDown',
1287
			  fgColor: { theme: 4, raw_rgb: '4F81BD' },
1288
			  bgColor: { theme: 7, raw_rgb: '8064A2' } },
1289
			{ patternType: 'lightGrid',
1290
			  fgColor: { theme: 6, raw_rgb: '9BBB59' },
1291
			  bgColor: { theme: 9, raw_rgb: 'F79646' } },
1292
			{ patternType: 'lightGrid',
1293
			  fgColor: { theme: 4, raw_rgb: '4F81BD' },
1294
			  bgColor: { theme: 2, raw_rgb: '1F497D' } },
1295
			{ patternType: 'lightVertical',
1296
			  fgColor: { theme: 3, raw_rgb: 'EEECE1' },
1297
			  bgColor: { theme: 7, raw_rgb: '8064A2' } }
1298
		];
1299
		/*eslint-enable */
1300
		ranges.forEach(function(rng) {
1301
			it('XLS  | ' + rng,function(){cmparr(rn2(rng).map(function(x){ return get_cell(wsxls,x).s; }));});
1302
			it('XLSX | ' + rng,function(){cmparr(rn2(rng).map(function(x){ return get_cell(wsxlsx,x).s; }));});
1303
		});
1304
		it('different styles', function() {
1305
			for(var i = 0; i != ranges.length-1; ++i) {
1306
				for(var j = i+1; j != ranges.length; ++j) {
1307
					diffsty(wsxlsx, rn2(ranges[i])[0], rn2(ranges[j])[0]);
1308
					/* TODO: XLS */
1309
					//diffsty(wsxls, rn2(ranges[i])[0], rn2(ranges[j])[0]);
1310
				}
1311
			}
1312
		});
1313
		it('correct styles', function() {
1314
			//var stylesxls = ranges.map(function(r) { return rn2(r)[0]; }).map(function(r) { return get_cell(wsxls,r).s; });
1315
			var stylesxlsx = ranges.map(function(r) { return rn2(r)[0]; }).map(function(r) { return get_cell(wsxlsx,r).s; });
1316
			exp.forEach(function(e, i) {
1317
				[
1318
					"fgColor.theme","fgColor.raw_rgb",
1319
					"bgColor.theme","bgColor.raw_rgb",
1320
					"patternType"
1321
				].forEach(function(k) {
1322
					deepcmp(e, stylesxlsx[i], k, i + ":" + k, 0);
1323
					/* TODO: XLS */
1324
					//deepcmp(e, stylesxls[i], k, i + ":" + k, 0);
1325
				});
1326
			});
1327
		});
1328
	});
1329
});
1330
1331
describe('write features', function() {
1332
	describe('props', function() {
1333
		describe('core', function() {
1334
			var ws;
1335
			var baseprops = {
1336
				Category: "Newspaper",
1337
				ContentStatus: "Published",
1338
				Keywords: "☃",
1339
				LastAuthor: "Perry White",
1340
				LastPrinted: "1978-12-15",
1341
				RevNumber: 6969,
1342
				AppVersion: 69,
1343
				Author: "Lois Lane",
1344
				Comments: "Needs work",
1345
				Identifier: "1d",
1346
				Language: "English",
1347
				Subject: "Superman",
1348
				Title: "Man of Steel"
1349
			};
1350
			var bef = (function() {
1351
				X = require(modp);
1352
				ws = X.utils.aoa_to_sheet([["a","b","c"],[1,2,3]]);
1353
			});
1354
			if(typeof before != 'undefined') before(bef);
1355
			else it('before', bef);
1356
			['xlml', 'xlsx', 'xlsb'].forEach(function(w) { it(w, function() {
1357
				var wb = {
1358
					Props: {},
1359
					SheetNames: ["Sheet1"],
1360
					Sheets: {Sheet1: ws}
1361
				};
1362
				Object.keys(baseprops).forEach(function(k) { wb.Props[k] = baseprops[k]; });
1363
				var wb2 = X.read(X.write(wb, {bookType:w, type:TYPE}), {type:TYPE});
1364
				Object.keys(baseprops).forEach(function(k) { assert.equal(baseprops[k], wb2.Props[k]); });
1365
				var wb3 = X.read(X.write(wb2, {bookType:w, type:TYPE, Props: {Author:"SheetJS"}}), {type:TYPE});
1366
				assert.equal("SheetJS", wb3.Props.Author);
1367
			}); });
1368
		});
1369
	});
1370
	describe('HTML', function() {
1371
		it('should use `h` value when present', function() {
1372
			var sheet = X.utils.aoa_to_sheet([["abc"]]);
1373
			get_cell(sheet, "A1").h = "<b>abc</b>";
1374
			var wb = {SheetNames:["Sheet1"], Sheets:{Sheet1:sheet}};
1375
			var str = X.write(wb, {bookType:"html", type:"binary"});
1376
			assert(str.indexOf("<b>abc</b>") > 0);
1377
		});
1378
	});
1379
	describe('sheet range limits', function() { [
1380
		["biff2", "IV16384"],
1381
		["biff5", "IV16384"],
1382
		["biff8", "IV65536"],
1383
		["xlsx", "XFD1048576"],
1384
		["xlsb", "XFD1048576"]
1385
	].forEach(function(r) { it(r[0], function() {
1386
		var C = X.utils.decode_cell(r[1]);
1387
		var wopts = {bookType:r[0], type:'binary', WTF:1};
1388
		var wb = { SheetNames: ["Sheet1"], Sheets: { Sheet1: {} } };
1389
1390
		wb.Sheets.Sheet1['!ref'] =  "A1:" + X.utils.encode_cell({r:0, c:C.c});
1391
		X.write(wb, wopts);
1392
		wb.Sheets.Sheet1['!ref'] =  "A" + X.utils.encode_row(C.r - 5) + ":" + X.utils.encode_cell({r:C.r, c:0});
1393
		X.write(wb, wopts);
1394
1395
		wb.Sheets.Sheet1['!ref'] =  "A1:" + X.utils.encode_cell({r:0, c:C.c+1});
1396
		assert.throws(function() { X.write(wb, wopts); });
1397
		wb.Sheets.Sheet1['!ref'] =  "A" + X.utils.encode_row(C.r - 5) + ":" + X.utils.encode_cell({r:C.r+1, c:0});
1398
		assert.throws(function() { X.write(wb, wopts); });
1399
	}); }); });
1400
	it('single worksheet formats', function() {
1401
		var wb = X.utils.book_new();
1402
		X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([[1,2],[3,4]]), "Sheet1");
1403
		X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([[5,6],[7,8]]), "Sheet2");
1404
		assert.equal(X.write(wb, {type:"string", bookType:"csv", sheet:"Sheet1"}), "1,2\n3,4\n");
1405
		assert.equal(X.write(wb, {type:"string", bookType:"csv", sheet:"Sheet2"}), "5,6\n7,8\n");
1406
		assert.throws(function() { X.write(wb, {type:"string", bookType:"csv", sheet:"Sheet3"}); });
1407
	});
1408
});
1409
1410
function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {
1411
	var s = start || 0;
1412
	var o = new Array(end - s);
1413
	for(var i = 0; i != o.length; ++i) o[i] = s + i;
1414
	return o;
1415
}
1416
1417
var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
1418
var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
1419
function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
1420
	var epoch = v.getTime();
1421
	if(date1904) epoch += 1462*24*60*60*1000;
1422
	return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
1423
}
1424
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
1425
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
1426
var good_pd = good_pd_date.getFullYear() == 2017;
1427
function parseDate(str/*:string|Date*/)/*:Date*/ {
1428
	var d = new Date(str);
1429
	if(good_pd) return d;
1430
	if(str instanceof Date) return str;
1431
	if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) {
1432
		var s = d.getFullYear();
1433
		if(str.indexOf("" + s) > -1) return d;
1434
		d.setFullYear(d.getFullYear() + 100); return d;
1435
	}
1436
	var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
1437
	return new Date(Date.UTC(+n[0], +n[1] - 1, +n[2], +n[3], +n[4], +n[5]));
1438
}
1439
1440
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
1441
1442
describe('roundtrip features', function() {
1443
	var bef = (function() { X = require(modp); });
1444
	if(typeof before != 'undefined') before(bef);
1445
	else it('before', bef);
1446
	describe('should preserve core properties', function() { [
1447
		['xls', paths.cpxls],
1448
		['xlml', paths.cpxml],
1449
		['xlsx', paths.cpxlsx],
1450
		['xlsb', paths.cpxlsb]
1451
	].forEach(function(w) {
1452
		it(w[0], function() {
1453
			var wb1 = X.read(fs.readFileSync(w[1]), {type:TYPE});
1454
			coreprop(wb1.Props);
1455
			var wb2 = X.read(X.write(wb1, {bookType:w[0], type:TYPE}), {type:TYPE});
1456
			coreprop(wb2.Props);
1457
		});
1458
	}); });
1459
1460
	describe('should preserve custom properties', function() { [
1461
		['xls', paths.cpxls],
1462
		['xlml', paths.cpxml],
1463
		['xlsx', paths.cpxlsx],
1464
		['xlsb', paths.cpxlsb]
1465
	].forEach(function(w) {
1466
		it(w[0], function() {
1467
			var wb1 = X.read(fs.readFileSync(w[1]), {type:TYPE});
1468
			custprop(wb1.Custprops);
1469
			var wb2 = X.read(X.write(wb1, {bookType:w[0], type:TYPE}), {type:TYPE});
1470
			custprop(wb2.Custprops);
1471
		});
1472
	}); });
1473
1474
	describe('should preserve merge cells', function() {
1475
		["xlsx", "xlsb", "xlml", "ods", "biff8"].forEach(function(f) { it(f, function() {
1476
			var wb1 = X.read(fs.readFileSync(paths.mcxlsx), {type:TYPE});
1477
			var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary'}),{type:'binary'});
1478
			var m1 = wb1.Sheets.Merge['!merges'].map(X.utils.encode_range);
1479
			var m2 = wb2.Sheets.Merge['!merges'].map(X.utils.encode_range);
1480
			assert.equal(m1.length, m2.length);
1481
			for(var i = 0; i < m1.length; ++i) assert(m1.indexOf(m2[i]) > -1);
1482
		}); });
1483
	});
1484
1485
	describe('should preserve dates', function() {
1486
		seq(16).forEach(function(n) {
1487
			var d = (n & 1) ? 'd' : 'n', dk = d === 'd';
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1488
			var c = (n & 2) ? 'd' : 'n', dj = c === 'd';
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1489
			var b = (n & 4) ? 'd' : 'n', di = b === 'd';
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1490
			var a = (n & 8) ? 'd' : 'n', dh = a === 'd';
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1491
			var f, sheet, addr;
1492
			if(dh) { f = paths.dtxlsx; sheet = 'Sheet1'; addr = 'B5'; }
1493
			else { f = paths.nfxlsx; sheet = '2011'; addr = 'J36'; }
1494
			it('[' + a + '] -> (' + b + ') -> [' + c + '] -> (' + d + ')', function() {
1495
				var wb1 = X.read(fs.readFileSync(f), {type:TYPE, cellNF: true, cellDates: di, WTF: opts.WTF});
1496
				var  _f = X.write(wb1, {type:'binary', cellDates:dj, WTF:opts.WTF});
1497
				var wb2 = X.read(_f, {type:'binary', cellDates: dk, WTF: opts.WTF});
1498
				var m = [wb1,wb2].map(function(x) { return get_cell(x.Sheets[sheet], addr); });
1499
				assert.equal(m[0].w, m[1].w);
1500
1501
				assert.equal(m[0].t, b);
1502
				assert.equal(m[1].t, d);
1503
1504
				if(m[0].t === 'n' && m[1].t === 'n') assert.equal(m[0].v, m[1].v);
1505
				else if(m[0].t === 'd' && m[1].t === 'd') assert.equal(m[0].v.toString(), m[1].v.toString());
1506
				else if(m[1].t === 'n') assert(Math.abs(datenum(browser ? parseDate(m[0].v) : new Date(m[0].v)) - m[1].v) < 0.01);
1507
			});
1508
		});
1509
	});
1510
1511
	describe('should preserve formulae', function() { [
1512
		['xlml', paths.fstxml],
1513
		['xlsx', paths.fstxlsx],
1514
		['ods',  paths.fstods]
1515
	].forEach(function(w) { it(w[0], function() {
1516
		var wb1 = X.read(fs.readFileSync(w[1]), {type:TYPE, cellFormula:true});
1517
		var wb2 = X.read(X.write(wb1, {bookType:w[0], type:TYPE}), {cellFormula:true, type:TYPE});
1518
		wb1.SheetNames.forEach(function(n) {
1519
			assert.equal(
1520
				X.utils.sheet_to_formulae(wb1.Sheets[n]).sort().join("\n"),
1521
				X.utils.sheet_to_formulae(wb2.Sheets[n]).sort().join("\n")
1522
			);
1523
		});
1524
	}); }); });
1525
1526
	describe('should preserve hyperlink', function() { [
1527
		['xlml', paths.hlxml,   true],
1528
		['xls',  paths.hlxls,   true],
1529
		['xlsx', paths.hlxlsx,  true],
1530
		['xlsb', paths.hlxlsb,  true],
1531
		['xlml', paths.ilxml,  false],
1532
		['xls',  paths.ilxls,  false],
1533
		['xlsx', paths.ilxlsx, false],
1534
		['xlsb', paths.ilxlsb, false],
1535
		['ods',  paths.ilods,  false]
1536
	].forEach(function(w) { it(w[0]+" "+(w[2]?"ex":"in")+ "ternal", function() {
1537
		var wb = X.read(fs.readFileSync(w[1]), {type:TYPE, WTF:opts.WTF});
1538
		var hlink = (w[2] ? hlink1 : hlink2); hlink(wb.Sheets.Sheet1);
1539
		wb = X.read(X.write(wb, {bookType:w[0], type:TYPE, WTF:opts.WTF}), {type:TYPE, WTF:opts.WTF});
1540
		hlink(wb.Sheets.Sheet1);
1541
	}); }); });
1542
1543
	(fs.existsSync(paths.pmxlsx) ? describe : describe.skip)('should preserve page margins', function() {[
1544
			['xlml', paths.pmxml],
1545
			['xlsx', paths.pmxlsx],
1546
			['xlsb', paths.pmxlsb]
1547
		].forEach(function(w) { it(w[0], function() {
1548
			var wb1 = X.read(fs.readFileSync(w[1]), {type:TYPE});
1549
			var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"binary"}), {type:"binary"});
1550
			[
1551
				/* Sheet Name     Margins: left   right  top bottom head foot */
1552
				["Normal",                 [0.70, 0.70, 0.75, 0.75, 0.30, 0.30]],
1553
				["Wide",                   [1.00, 1.00, 1.00, 1.00, 0.50, 0.50]],
1554
				["Narrow",                 [0.25, 0.25, 0.75, 0.75, 0.30, 0.30]],
1555
				["Custom 1 Inch Centered", [1.00, 1.00, 1.00, 1.00, 0.30, 0.30]],
1556
				["1 Inch HF",              [0.70, 0.70, 0.75, 0.75, 1.00, 1.00]]
1557
			].forEach(function(t) {
1558
				check_margin(wb2.Sheets[t[0]]["!margins"], t[1]);
1559
			});
1560
	}); }); });
1561
1562
	describe('should preserve sheet visibility', function() { [
1563
			['xlml', paths.svxml],
1564
			['xlsx', paths.svxlsx],
1565
			['xlsb', paths.svxlsb]
1566
		].forEach(function(w) {
1567
			it(w[0], function() {
1568
				var wb1 = X.read(fs.readFileSync(w[1]), {type:TYPE});
1569
				var wb2 = X.read(X.write(wb1, {bookType:w[0], type:TYPE}), {type:TYPE});
1570
				var wbs1 = wb1.Workbook.Sheets;
1571
				var wbs2 = wb2.Workbook.Sheets;
1572
				assert.equal(wbs1.length, wbs2.length);
1573
				for(var i = 0; i < wbs1.length; ++i) {
1574
					assert.equal(wbs1[i].name, wbs2[i].name);
1575
					assert.equal(wbs1[i].Hidden, wbs2[i].Hidden);
1576
				}
1577
			});
1578
		});
1579
	});
1580
1581
	describe('should preserve column properties', function() { [
1582
			'xlml', /*'biff2', 'biff8', */ 'xlsx', 'xlsb', 'slk'
1583
		].forEach(function(w) { it(w, function() {
1584
				var ws1 = X.utils.aoa_to_sheet([["hpx12", "hpt24", "hpx48", "hidden"]]);
1585
				ws1['!cols'] = [{wch:9},{wpx:100},{width:80},{hidden:true}];
1586
				var wb1 = {SheetNames:["Sheet1"], Sheets:{Sheet1:ws1}};
1587
				var wb2 = X.read(X.write(wb1, {bookType:w, type:TYPE}), {type:TYPE, cellStyles:true});
1588
				var ws2 = wb2.Sheets.Sheet1;
1589
				assert.equal(ws2['!cols'][3].hidden, true);
1590
				assert.equal(ws2['!cols'][0].wch, 9);
1591
				if(w == 'slk') return;
1592
				assert.equal(ws2['!cols'][1].wpx, 100);
1593
				/* xlml stores integral pixels -> approximate width */
1594
				if(w == 'xlml') assert.equal(Math.round(ws2['!cols'][2].width), 80);
1595
				else assert.equal(ws2['!cols'][2].width, 80);
1596
		}); });
1597
	});
1598
1599
	/* TODO: ODS and BIFF5/8 */
1600
	describe('should preserve row properties', function() { [
1601
			'xlml', /*'biff2', 'biff8', */ 'xlsx', 'xlsb', 'slk'
1602
		].forEach(function(w) { it(w, function() {
1603
				var ws1 = X.utils.aoa_to_sheet([["hpx12"],["hpt24"],["hpx48"],["hidden"]]);
1604
				ws1['!rows'] = [{hpx:12},{hpt:24},{hpx:48},{hidden:true}];
1605
				for(var i = 0; i <= 7; ++i) ws1['!rows'].push({level:i});
1606
				var wb1 = {SheetNames:["Sheet1"], Sheets:{Sheet1:ws1}};
1607
				var wb2 = X.read(X.write(wb1, {bookType:w, type:TYPE, cellStyles:true}), {type:TYPE, cellStyles:true});
1608
				var ws2 = wb2.Sheets.Sheet1;
1609
				assert.equal(ws2['!rows'][0].hpx, 12);
1610
				assert.equal(ws2['!rows'][1].hpt, 24);
1611
				assert.equal(ws2['!rows'][2].hpx, 48);
1612
				assert.equal(ws2['!rows'][3].hidden, true);
1613
				if(w == 'xlsb' || w == 'xlsx') for(i = 0; i <= 7; ++i) assert.equal((ws2['!rows'][4+i]||{}).level||0, i);
1614
		}); });
1615
	});
1616
1617
	/* TODO: ODS and XLS */
1618
	describe('should preserve cell comments', function() { [
1619
			['xlsx', paths.cstxlsx],
1620
			['xlsb', paths.cstxlsb],
1621
			//['xls', paths.cstxlsx],
1622
			['xlml', paths.cstxml]
1623
			//['ods', paths.cstods]
1624
	].forEach(function(w) {
1625
			it(w[0], function() {
1626
				var wb1 = X.read(fs.readFileSync(w[1]), {type:TYPE});
1627
				var wb2 = X.read(X.write(wb1, {bookType:w[0], type:TYPE}), {type:TYPE});
1628
				check_comments(wb1);
1629
				check_comments(wb2);
1630
			});
1631
		});
1632
	});
1633
1634
	it('should preserve JS objects', function() {
1635
		var data/*:Array<any>*/ = [
1636
			{a:1},
1637
			{b:2,c:3},
1638
			{b:"a",d:"b"},
1639
			{a:true, c:false},
1640
			{c:fixdate}
1641
		];
1642
		var o = X.utils.sheet_to_json(X.utils.json_to_sheet(data, {cellDates:true}), {raw:true});
1643
		data.forEach(function(row, i) {
1644
			Object.keys(row).forEach(function(k) { assert.equal(row[k], o[i][k]); });
1645
		});
1646
	});
1647
});
1648
1649
//function password_file(x){return x.match(/^password.*\.xls$/); }
1650
var password_files = [
1651
	//"password_2002_40_972000.xls",
1652
	"password_2002_40_xor.xls"
1653
];
1654
describe('invalid files', function() {
1655
	describe('parse', function() { [
1656
		['password', 'apachepoi_password.xls'],
1657
		['passwords', 'apachepoi_xor-encryption-abc.xls'],
1658
		['DOC files', 'word_doc.doc']
1659
	].forEach(function(w) { it('should fail on ' + w[0], function() {
1660
		assert.throws(function() { X.read(fs.readFileSync(dir + w[1], 'binary'), {type:'binary'}); });
1661
		assert.throws(function() { X.read(fs.readFileSync(dir + w[1], 'base64'), {type:'base64'}); });
1662
	}); }); });
1663
	describe('write', function() {
1664
		it('should pass -> XLSX', function() { FSTPaths.forEach(function(p) {
1665
			X.write(X.read(fs.readFileSync(p), {type:TYPE}), {type:TYPE});
1666
		}); });
1667
		it('should pass if a sheet is missing', function() {
1668
			var wb = X.read(fs.readFileSync(paths.fstxlsx), {type:TYPE}); delete wb.Sheets[wb.SheetNames[0]];
1669
			X.read(X.write(wb, {type:'binary'}), {type:'binary'});
1670
		});
1671
		['Props', 'Custprops', 'SSF'].forEach(function(t) { it('should pass if ' + t + ' is missing', function() {
1672
			var wb = X.read(fs.readFileSync(paths.fstxlsx), {type:TYPE});
1673
			assert.doesNotThrow(function() { delete wb[t]; X.write(wb, {type:'binary'}); });
1674
		}); });
1675
		['SheetNames', 'Sheets'].forEach(function(t) { it('should fail if ' + t + ' is missing', function() {
1676
			var wb = X.read(fs.readFileSync(paths.fstxlsx), {type:TYPE});
1677
			assert.throws(function() { delete wb[t]; X.write(wb, {type:'binary'}); });
1678
		}); });
1679
		it('should fail if SheetNames has duplicate entries', function() {
1680
			var wb = X.read(fs.readFileSync(paths.fstxlsx), {type:TYPE});
1681
			wb.SheetNames.push(wb.SheetNames[0]);
1682
			assert.throws(function() { X.write(wb, {type:'binary'}); });
1683
		});
1684
	});
1685
});
1686
1687
1688
describe('json output', function() {
1689
	function seeker(json, keys, val) {
1690
		if(typeof keys == "string") keys = keys.split("");
1691
		for(var i = 0; i != json.length; ++i) {
1692
			for(var j = 0; j != keys.length; ++j) {
1693
				if(json[i][keys[j]] === val) throw new Error("found " + val + " in row " + i + " key " + keys[j]);
1694
			}
1695
		}
1696
	}
1697
	var data, ws;
1698
	var bef = (function() {
1699
		data = [
1700
			[1,2,3],
1701
			[true, false, null, "sheetjs"],
1702
			["foo", "bar", fixdate, "0.3"],
1703
			["baz", undefined, "qux"]
1704
		];
1705
		ws = X.utils.aoa_to_sheet(data);
1706
	});
1707
	if(typeof before != 'undefined') before(bef);
1708
	else it('before', bef);
1709
	it('should use first-row headers and full sheet by default', function() {
1710
		var json = X.utils.sheet_to_json(ws);
1711
		assert.equal(json.length, data.length - 1);
1712
		assert.equal(json[0][1], "TRUE");
1713
		assert.equal(json[1][2], "bar");
1714
		assert.equal(json[2][3], "qux");
1715
		assert.doesNotThrow(function() { seeker(json, [1,2,3], "sheetjs"); });
1716
		assert.throws(function() { seeker(json, [1,2,3], "baz"); });
1717
	});
1718
	it('should create array of arrays if header == 1', function() {
1719
		var json = X.utils.sheet_to_json(ws, {header:1});
1720
		assert.equal(json.length, data.length);
1721
		assert.equal(json[1][0], "TRUE");
1722
		assert.equal(json[2][1], "bar");
1723
		assert.equal(json[3][2], "qux");
1724
		assert.doesNotThrow(function() { seeker(json, [0,1,2], "sheetjs"); });
1725
		assert.throws(function() { seeker(json, [0,1,2,3], "sheetjs"); });
1726
		assert.throws(function() { seeker(json, [0,1,2], "baz"); });
1727
	});
1728
	it('should use column names if header == "A"', function() {
1729
		var json = X.utils.sheet_to_json(ws, {header:'A'});
1730
		assert.equal(json.length, data.length);
1731
		assert.equal(json[1].A, "TRUE");
1732
		assert.equal(json[2].B, "bar");
1733
		assert.equal(json[3].C, "qux");
1734
		assert.doesNotThrow(function() { seeker(json, "ABC", "sheetjs"); });
1735
		assert.throws(function() { seeker(json, "ABCD", "sheetjs"); });
1736
		assert.throws(function() { seeker(json, "ABC", "baz"); });
1737
	});
1738
	it('should use column labels if specified', function() {
1739
		var json = X.utils.sheet_to_json(ws, {header:["O","D","I","N"]});
1740
		assert.equal(json.length, data.length);
1741
		assert.equal(json[1].O, "TRUE");
1742
		assert.equal(json[2].D, "bar");
1743
		assert.equal(json[3].I, "qux");
1744
		assert.doesNotThrow(function() { seeker(json, "ODI", "sheetjs"); });
1745
		assert.throws(function() { seeker(json, "ODIN", "sheetjs"); });
1746
		assert.throws(function() { seeker(json, "ODIN", "baz"); });
1747
	});
1748
	[["string", "A2:D4"], ["numeric", 1], ["object", {s:{r:1,c:0},e:{r:3,c:3}}]].forEach(function(w) {
1749
		it('should accept custom ' + w[0] + ' range', function() {
1750
			var json = X.utils.sheet_to_json(ws, {header:1, range:w[1]});
1751
			assert.equal(json.length, 3);
1752
			assert.equal(json[0][0], "TRUE");
1753
			assert.equal(json[1][1], "bar");
1754
			assert.equal(json[2][2], "qux");
1755
			assert.doesNotThrow(function() { seeker(json, [0,1,2], "sheetjs"); });
1756
			assert.throws(function() { seeker(json, [0,1,2,3], "sheetjs"); });
1757
			assert.throws(function() { seeker(json, [0,1,2], "baz"); });
1758
		});
1759
	});
1760
	it('should use defval if requested', function() {
1761
		var json = X.utils.sheet_to_json(ws, {defval: 'jimjin'});
1762
		assert.equal(json.length, data.length - 1);
1763
		assert.equal(json[0][1], "TRUE");
1764
		assert.equal(json[1][2], "bar");
1765
		assert.equal(json[2][3], "qux");
1766
		assert.equal(json[2][2], "jimjin");
1767
		assert.equal(json[0][3], "jimjin");
1768
		assert.doesNotThrow(function() { seeker(json, [1,2,3], "sheetjs"); });
1769
		assert.throws(function() { seeker(json, [1,2,3], "baz"); });
1770
		X.utils.sheet_to_json(ws, {raw:true});
1771
		X.utils.sheet_to_json(ws, {raw:true, defval: 'jimjin'});
1772
	});
1773
	it('should disambiguate headers', function() {
1774
		var _data = [["S","h","e","e","t","J","S"],[1,2,3,4,5,6,7],[2,3,4,5,6,7,8]];
1775
		var _ws = X.utils.aoa_to_sheet(_data);
1776
		var json = X.utils.sheet_to_json(_ws);
1777
		for(var i = 0; i < json.length; ++i) {
1778
			assert.equal(json[i].S,   1 + i);
1779
			assert.equal(json[i].h,   2 + i);
1780
			assert.equal(json[i].e,   3 + i);
1781
			assert.equal(json[i].e_1, 4 + i);
1782
			assert.equal(json[i].t,   5 + i);
1783
			assert.equal(json[i].J,   6 + i);
1784
			assert.equal(json[i].S_1, 7 + i);
1785
		}
1786
	});
1787
	it('should handle raw data if requested', function() {
1788
		var _ws = X.utils.aoa_to_sheet(data, {cellDates:true});
1789
		var json = X.utils.sheet_to_json(_ws, {header:1, raw:true});
1790
		assert.equal(json.length, data.length);
1791
		assert.equal(json[1][0], true);
1792
		assert.equal(json[1][2], null);
1793
		assert.equal(json[2][1], "bar");
1794
		assert.equal(json[2][2].getTime(), fixdate.getTime());
1795
		assert.equal(json[3][2], "qux");
1796
	});
1797
	it('should include __rowNum__', function() {
1798
		var _data = [["S","h","e","e","t","J","S"],[1,2,3,4,5,6,7],[],[2,3,4,5,6,7,8]];
1799
		var _ws = X.utils.aoa_to_sheet(_data);
1800
		var json = X.utils.sheet_to_json(_ws);
1801
		assert.equal(json[0].__rowNum__, 1);
1802
		assert.equal(json[1].__rowNum__, 3);
1803
	});
1804
	it('should handle blankrows', function() {
1805
		var _data = [["S","h","e","e","t","J","S"],[1,2,3,4,5,6,7],[],[2,3,4,5,6,7,8]];
1806
		var _ws = X.utils.aoa_to_sheet(_data);
1807
		var json1 = X.utils.sheet_to_json(_ws);
1808
		assert.equal(json1.length, 2); // = 2 non-empty records
1809
		var json2 = X.utils.sheet_to_json(_ws, {header:1});
1810
		assert.equal(json2.length, 4); // = 4 sheet rows
1811
		var json3 = X.utils.sheet_to_json(_ws, {blankrows:true});
1812
		assert.equal(json3.length, 3); // = 2 records + 1 blank row
1813
		var json4 = X.utils.sheet_to_json(_ws, {blankrows:true, header:1});
1814
		assert.equal(json4.length, 4); // = 4 sheet rows
1815
		var json5 = X.utils.sheet_to_json(_ws, {blankrows:false});
1816
		assert.equal(json5.length, 2); // = 2 records
1817
		var json6 = X.utils.sheet_to_json(_ws, {blankrows:false, header:1});
1818
		assert.equal(json6.length, 3); // = 4 sheet rows - 1 blank row
1819
	});
1820
	it('should have an index that starts with zero when selecting range', function() {
1821
		var _data = [["S","h","e","e","t","J","S"],[1,2,3,4,5,6,7],[7,6,5,4,3,2,1],[2,3,4,5,6,7,8]];
1822
		var _ws = X.utils.aoa_to_sheet(_data);
1823
		var json1 = X.utils.sheet_to_json(_ws, { header:1, raw: true, range: "B1:F3" });
1824
		assert.equal(json1[0][3], "t");
1825
		assert.equal(json1[1][0], 2);
1826
		assert.equal(json1[2][1], 5);
1827
		assert.equal(json1[2][3], 3);
1828
	});
1829
	it('should preserve values when column header is missing', function() {
1830
		/*jshint elision:true */
1831
		var _data = [[,"a","b",,"c"], [1,2,3,,5],[,3,4,5,6]]; // eslint-disable-line no-sparse-arrays
1832
		/*jshint elision:false */
1833
		var _ws = X.utils.aoa_to_sheet(_data);
1834
		var json1 = X.utils.sheet_to_json(_ws, { raw: true });
1835
		assert.equal(json1[0].__EMPTY, 1);
1836
		assert.equal(json1[1].__EMPTY_1, 5);
1837
	});
1838
	it('should ignore errors and support default values', function() {
1839
		var ws = {
1840
			A1: {t:'s', v:"Field"}, B1: {t:'s', v:"Text"},
1841
			A2: {t:'e', v:0x2A, w:"#N/A" }, B2: {t:'s', v:"#N/A"},
1842
			A3: {t:'e', v:0x0F }, B3: {t:'s', v:"#VALUE!"},
1843
			A4: {t:'e', w:"#NAME?" }, B4: {t:'s', v:"#NAME?"},
1844
			"!ref": "A1:B4" };
1845
		seq(8).forEach(function(n) {
1846
			var opts = {};
1847
			if(n & 1) opts.header = 1;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1848
			if(n & 2) opts.raw = 1;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1849
			if(n & 4) opts.defval = null;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1850
			var J = X.utils.sheet_to_json(ws, opts);
1851
			for(var i = 0; i < 3; ++i) {
1852
				var k = ((n&1) ? J[i+1][0] : J[i].Field);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1853
				assert((n&4) ? (k === null) : (k !== null));
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1854
			}
1855
		});
1856
	});
1857
});
1858
1859
1860
var codes = [["あ 1", "\u00E3\u0081\u0082 1"]];
1861
var plaintext_val = [
1862
	["A1", 'n', -0.08,  "-0.08"],
1863
	["B1", 'n', 4001,   "4,001"],
1864
	["C1", 's', "あ 1",  "あ 1"],
1865
	["A2", 'n', 41.08, "$41.08"],
1866
	["B2", 'n', 0.11,     "11%"],
1867
	["C3", 'b', true,    "TRUE"],
1868
	["D3", 'b', false,  "FALSE"],
1869
	["B3", 's', " ",        " "],
1870
	["A3"]
1871
];
1872
function plaintext_test(wb, raw) {
1873
	var sheet = wb.Sheets[wb.SheetNames[0]];
1874
	plaintext_val.forEach(function(x) {
1875
		var cell = get_cell(sheet, x[0]);
1876
		var tcval = x[2+!!raw];
1877
		var type = raw ? 's' : x[1];
1878
		if(x.length == 1) { if(cell) { assert.equal(cell.t, 'z'); assert(!cell.v); } return; }
1879
		assert.equal(cell.v, tcval); assert.equal(cell.t, type);
1880
	});
1881
}
1882
function make_html_str(idx) { return ["<table>",
1883
	"<tr><td>-0.08</td><td>4,001</td><td>", codes[0][idx], "</td></tr>",
1884
	"<tr><td>$41.08</td><td>11%</td></tr>",
1885
	"<tr><td></td><td> \n&nbsp;</td><td>TRUE</td><td>FALSE</td></tr>",
1886
"</table>" ].join(""); }
1887
function make_csv_str(idx) { return [ (idx == 1 ? '\u00EF\u00BB\u00BF' : "") +
1888
	'-0.08,"4,001",' + codes[0][idx] + '',
1889
	'$41.08,11%',
1890
	', ,TRUE,FALSE'
1891
].join("\n"); }
1892
var html_bstr = make_html_str(1), html_str = make_html_str(0);
1893
var csv_bstr = make_csv_str(1), csv_str = make_csv_str(0);
1894
1895
1896
describe('CSV', function() {
1897
	describe('input', function(){
1898
		var b = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n,,,\nbaz,,qux,\n";
1899
		it('should generate date numbers by default', function() {
1900
			var opts = {type:"binary"};
1901
			var cell = get_cell(X.read(b, opts).Sheets.Sheet1, "C3");
1902
			assert.equal(cell.w, '2/19/14');
1903
			assert.equal(cell.t, 'n');
1904
			assert(typeof cell.v == "number");
1905
		});
1906
		it('should generate dates when requested', function() {
1907
			var opts = {type:"binary", cellDates:true};
1908
			var cell = get_cell(X.read(b, opts).Sheets.Sheet1, "C3");
1909
			assert.equal(cell.w, '2/19/14');
1910
			assert.equal(cell.t, 'd');
1911
			assert(cell.v instanceof Date || typeof cell.v == "string");
1912
		});
1913
1914
		it('should use US date code 14 by default', function() {
1915
			var opts = ({type:"binary"}/*:any*/);
1916
			var cell = get_cell(X.read(b, opts).Sheets.Sheet1, "C3");
1917
			assert.equal(cell.w, '2/19/14');
1918
			opts.cellDates = true;
1919
			cell = get_cell(X.read(b, opts).Sheets.Sheet1, "C3");
1920
			assert.equal(cell.w, '2/19/14');
1921
		});
1922
		it('should honor dateNF override', function() {
1923
			var opts = ({type:"binary", dateNF:"YYYY-MM-DD"}/*:any*/);
1924
			var cell = get_cell(X.read(b, opts).Sheets.Sheet1, "C3");
1925
			/* NOTE: IE interprets 2-digit years as 19xx */
1926
			assert(cell.w == '2014-02-19' || cell.w == '1914-02-19');
1927
			opts.cellDates = true; opts.dateNF = "YY-MM-DD";
1928
			cell = get_cell(X.read(b, opts).Sheets.Sheet1, "C3");
1929
			assert.equal(cell.w, '14-02-19');
1930
		});
1931
		it('should interpret dateNF', function() {
1932
			var bb = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/3/14,0.3\n,,,\nbaz,,qux,\n";
1933
			var opts = {type:"binary", cellDates:true, dateNF:'m/d/yy'};
1934
			var cell = get_cell(X.read(bb, opts).Sheets.Sheet1, "C3");
1935
			assert.equal(cell.v.getMonth(), 1);
1936
			assert.equal(cell.w, "2/3/14");
1937
			opts = {type:"binary", cellDates:true, dateNF:'d/m/yy'};
1938
			cell = get_cell(X.read(bb, opts).Sheets.Sheet1, "C3");
1939
			assert.equal(cell.v.getMonth(), 2);
1940
			assert.equal(cell.w, "2/3/14");
1941
		});
1942
		it('should interpret values by default', function() { plaintext_test(X.read(csv_bstr, {type:"binary"}), false); });
1943
		it('should generate strings if raw option is passed', function() { plaintext_test(X.read(csv_str, {type:"string", raw:true}), true); });
1944
		it('should handle formulae', function() {
1945
			var bb = '=,=1+1,="100"';
1946
			var sheet = X.read(bb, {type:"binary"}).Sheets.Sheet1;
1947
			assert.equal(get_cell(sheet, "A1").t, 's');
1948
			assert.equal(get_cell(sheet, "A1").v, '=');
1949
			assert.equal(get_cell(sheet, "B1").f, '1+1');
1950
			assert.equal(get_cell(sheet, "C1").t, 's');
1951
			assert.equal(get_cell(sheet, "C1").v, '100');
1952
		});
1953
		if(!browser || typeof cptable !== 'undefined') it('should honor codepage for binary strings', function() {
1954
			var data = "abc,def\nghi,j\xD3l";
1955
			[[1251, 'У'],[1252, 'Ó'], [1253, 'Σ'], [1254, 'Ó'], [1255, '׃'], [1256, 'س'], [10000, '”']].forEach(function(m) {
1956
				var ws = X.read(data, {type:"binary", codepage:m[0]}).Sheets.Sheet1;
1957
				assert.equal(get_cell(ws, "B2").v,  "j" + m[1] + "l");
1958
			});
1959
		});
1960
	});
1961
	describe('output', function(){
1962
		var data, ws;
1963
		var bef = (function() {
1964
			data = [
1965
				[1,2,3,null],
1966
				[true, false, null, "sheetjs"],
1967
				["foo", "bar", fixdate, "0.3"],
1968
				[null, null, null],
1969
				["baz", undefined, "qux"]
1970
			];
1971
			ws = X.utils.aoa_to_sheet(data);
1972
		});
1973
		if(typeof before != 'undefined') before(bef);
1974
		else it('before', bef);
1975
		it('should generate csv', function() {
1976
			var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n,,,\nbaz,,qux,\n";
1977
			assert.equal(baseline, X.utils.sheet_to_csv(ws));
1978
		});
1979
		it('should handle FS', function() {
1980
			assert.equal(X.utils.sheet_to_csv(ws, {FS:"|"}).replace(/[|]/g,","), X.utils.sheet_to_csv(ws));
1981
			assert.equal(X.utils.sheet_to_csv(ws, {FS:";"}).replace(/[;]/g,","), X.utils.sheet_to_csv(ws));
1982
		});
1983
		it('should handle RS', function() {
1984
			assert.equal(X.utils.sheet_to_csv(ws, {RS:"|"}).replace(/[|]/g,"\n"), X.utils.sheet_to_csv(ws));
1985
			assert.equal(X.utils.sheet_to_csv(ws, {RS:";"}).replace(/[;]/g,"\n"), X.utils.sheet_to_csv(ws));
1986
		});
1987
		it('should handle dateNF', function() {
1988
			var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,20140219,0.3\n,,,\nbaz,,qux,\n";
1989
			var _ws =  X.utils.aoa_to_sheet(data, {cellDates:true});
1990
			delete get_cell(_ws,"C3").w;
1991
			delete get_cell(_ws,"C3").z;
1992
			assert.equal(baseline, X.utils.sheet_to_csv(_ws, {dateNF:"YYYYMMDD"}));
1993
		});
1994
		it('should handle strip', function() {
1995
			var baseline = "1,2,3\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n\nbaz,,qux\n";
1996
			assert.equal(baseline, X.utils.sheet_to_csv(ws, {strip:true}));
1997
		});
1998
		it('should handle blankrows', function() {
1999
			var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\nbaz,,qux,\n";
2000
			assert.equal(baseline, X.utils.sheet_to_csv(ws, {blankrows:false}));
2001
		});
2002
		it('should handle various line endings', function() {
2003
			var data = ["1,a", "2,b", "3,c"];
2004
			[ "\r", "\n", "\r\n" ].forEach(function(RS) {
2005
				var wb = X.read(data.join(RS), {type:'binary'});
2006
				assert.equal(get_cell(wb.Sheets.Sheet1, "A1").v, 1);
2007
				assert.equal(get_cell(wb.Sheets.Sheet1, "B3").v, "c");
2008
				assert.equal(wb.Sheets.Sheet1['!ref'], "A1:B3");
2009
			});
2010
		});
2011
		it('should handle skipHidden for rows if requested', function() {
2012
			var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n,,,\nbaz,,qux,\n";
2013
			delete ws["!rows"];
2014
			assert.equal(X.utils.sheet_to_csv(ws), baseline);
2015
			assert.equal(X.utils.sheet_to_csv(ws, {skipHidden:true}), baseline);
2016
			ws["!rows"] = [null,{hidden:true},null,null];
2017
			assert.equal(X.utils.sheet_to_csv(ws), baseline);
2018
			assert.equal(X.utils.sheet_to_csv(ws, {skipHidden:true}), "1,2,3,\nfoo,bar,2/19/14,0.3\n,,,\nbaz,,qux,\n");
2019
			delete ws["!rows"];
2020
		});
2021
		it('should handle skipHidden for columns if requested', function() {
2022
			var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n,,,\nbaz,,qux,\n";
2023
			delete ws["!cols"];
2024
			assert.equal(X.utils.sheet_to_csv(ws), baseline);
2025
			assert.equal(X.utils.sheet_to_csv(ws, {skipHidden:true}), baseline);
2026
			ws["!cols"] = [null,{hidden:true},null,null];
2027
			assert.equal(X.utils.sheet_to_csv(ws), baseline);
2028
			assert.equal(X.utils.sheet_to_csv(ws, {skipHidden:true}), "1,3,\nTRUE,,sheetjs\nfoo,2/19/14,0.3\n,,\nbaz,qux,\n");
2029
			ws["!cols"] = [{hidden:true},null,null,null];
2030
			assert.equal(X.utils.sheet_to_csv(ws, {skipHidden:true}), "2,3,\nFALSE,,sheetjs\nbar,2/19/14,0.3\n,,\n,qux,\n");
2031
			delete ws["!cols"];
2032
		});
2033
	});
2034
});
2035
2036
describe('sylk', function() {
2037
	var cpavail = true;
2038
	var bef = (function() {
2039
		if(typeof cptable == 'undefined') cpavail = false;
2040
	});
2041
	if(typeof before != 'undefined') before(bef);
2042
	describe('input', function(){
2043
		it('codepage', cpavail ? function() {
2044
			var str = "ID;PWXL;N;E\r\nC;X1;Y1;K\"a – b\"\r\nE", A1 =  "a – b";
2045
			assert.equal(get_cell(X.read(str, {type:"string"}).Sheets.Sheet1, "A1").v, A1);
2046
			assert.equal(get_cell(X.read(str.replace(/–/, "\x96"), {type:"binary", codepage:1252}).Sheets.Sheet1, "A1").v, A1);
2047
			if(typeof Buffer !== 'undefined' && !browser) {
2048
				// $FlowIgnore
2049
				assert.equal(get_cell(X.read(Buffer_from(str), {type:"buffer", codepage:65001}).Sheets.Sheet1, "A1").v, A1);
0 ignored issues
show
Bug introduced by
The call to Buffer_from seems to have too many arguments starting with str.
Loading history...
2050
				// $FlowIgnore
2051
				assert.equal(get_cell(X.read(Buffer_from(str.replace(/–/, "\x96"), "binary"), {type:"buffer", codepage:1252}).Sheets.Sheet1, "A1").v, A1);
2052
			}
2053
		} : null);
2054
	});
2055
});
2056
2057
if(fs.existsSync(dir + 'dbf/d11.dbf')) describe('dbf', function() {
2058
	var wbs/*:Array<any>*/ = ([
2059
		['d11',  dir + 'dbf/d11.dbf'],
2060
		['vfp3', dir + 'dbf/vfp3.dbf']
2061
	]/*:any*/);
2062
	var bef = (function() {
2063
		wbs = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), {type:TYPE})]; });
2064
	});
2065
	if(typeof before != 'undefined') before(bef);
2066
	else it('before', bef);
2067
	it(wbs[1][0], function() {
2068
		var ws = wbs[1][1].Sheets.Sheet1;
2069
		[
2070
			["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45],
2071
			["C2", "v", 12.345], ["D2", "v", 1234.1], ["E2", "w", "19170219"],
2072
			/* [F2", "w", "19170219"], */ ["G2", "v", 1231.4], ["H2", "v", 123234],
2073
			["I2", "v", true], ["L2", "v", "SheetJS"]
2074
		].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
2075
	});
2076
});
2077
var JSDOM = null;
2078
// $FlowIgnore
2079
var domtest = browser || (function(){try{return !!(JSDOM=require('jsdom').JSDOM);}catch(e){return 0;}})();
2080
var inserted_dom_elements = [];
2081
2082
function get_dom_element(html) {
2083
	if(browser) {
2084
		var domelt = document.createElement('div');
2085
		domelt.innerHTML = html;
2086
		if(document.body) document.body.appendChild(domelt);
2087
		inserted_dom_elements.push(domelt);
2088
		return domelt.children[0];
2089
	}
2090
	if(!JSDOM) throw new Error("Browser test fail");
2091
	return new JSDOM(html).window.document.body.children[0];
2092
}
2093
2094
describe('HTML', function() {
2095
	afterEach(function () {
2096
		// Remove the DOM elements inserted to the page by get_dom_element
2097
		inserted_dom_elements.forEach(function (element) {
2098
			if(element.parentNode) element.parentNode.removeChild(element);
2099
		});
2100
		inserted_dom_elements = [];
2101
	});
2102
	describe('input string', function() {
2103
		it('should interpret values by default', function() { plaintext_test(X.read(html_bstr, {type:"binary"}), false); });
2104
		it('should generate strings if raw option is passed', function() { plaintext_test(X.read(html_bstr, {type:"binary", raw:true}), true); });
2105
		it('should handle "string" type', function() { plaintext_test(X.read(html_str, {type:"string"}), false); });
2106
		it('should handle newlines correctly', function() {
2107
			var table = "<table><tr><td>foo<br/>bar</td><td>baz</td></tr></table>";
2108
			var wb = X.read(table, {type:"string"});
2109
			assert.equal(get_cell(wb.Sheets.Sheet1, "A1").v, "foo\nbar");
2110
		});
2111
	});
2112
	(domtest ? describe : describe.skip)('input DOM', function() {
2113
		it('should interpret values by default', function() { plaintext_test(X.utils.table_to_book(get_dom_element(html_str)), false); });
2114
		it('should generate strings if raw option is passed', function() { plaintext_test(X.utils.table_to_book(get_dom_element(html_str), {raw:true}), true); });
2115
		it('should handle newlines correctly', function() {
2116
			var table = get_dom_element("<table><tr><td>foo<br/>bar</td><td>baz</td></tr></table>");
2117
			var ws = X.utils.table_to_sheet(table);
2118
			assert.equal(get_cell(ws, "A1").v, "foo\nbar");
2119
		});
2120
		it('should trim whitespace', function() {
2121
			if(get_dom_element("foo <br> bar").innerHTML != "foo <br> bar") return;
2122
			var table = get_dom_element("<table><tr><td>   foo  <br/>  bar   </td><td>  baz  qux  </td></tr></table>");
2123
			var ws = X.utils.table_to_sheet(table);
2124
			assert.equal(get_cell(ws, "A1").v.replace(/\n/g, "|"), "foo | bar");
2125
			assert.equal(get_cell(ws, "B1").v, "baz qux");
2126
		});
2127
	});
2128
	if(domtest) it('should handle entities', function() {
2129
		var html = "<table><tr><td>A&amp;B</td><td>A&middot;B</td></tr></table>";
2130
		var ws = X.utils.table_to_sheet(get_dom_element(html));
2131
		assert.equal(get_cell(ws, "A1").v, "A&B");
2132
		assert.equal(get_cell(ws, "B1").v, "A·B");
2133
	});
2134
	if(domtest) it('should honor sheetRows', function() {
2135
		var html = X.utils.sheet_to_html(X.utils.aoa_to_sheet([[1,2],[3,4],[5,6]]));
2136
		// $FlowIgnore
2137
		html = /<body[^>]*>([\s\S]*)<\/body>/i.exec(html)[1];
2138
		var ws = X.utils.table_to_sheet(get_dom_element(html));
2139
		assert.equal(ws['!ref'], "A1:B3");
2140
		ws = X.utils.table_to_sheet(get_dom_element(html), {sheetRows:1});
2141
		assert.equal(ws['!ref'], "A1:B1");
2142
		assert.equal(ws['!fullref'], "A1:B3");
2143
		ws = X.utils.table_to_sheet(get_dom_element(html), {sheetRows:2});
2144
		assert.equal(ws['!ref'], "A1:B2");
2145
		assert.equal(ws['!fullref'], "A1:B3");
2146
	});
2147
	if(domtest) it('should hide hidden rows', function() {
2148
		var html = "<table><tr style='display: none;'><td>Foo</td></tr><tr><td style='display: none;'>Bar</td></tr><tr class='hidden'><td>Baz</td></tr></table><style>.hidden {display: none}</style>";
2149
		var ws = X.utils.table_to_sheet(get_dom_element(html));
2150
		var expected_rows = [];
2151
		expected_rows[0] = expected_rows[2] = {hidden: true};
2152
		assert.equal(ws['!ref'], "A1:A3");
2153
		assert.deepEqual(ws['!rows'], expected_rows);
2154
		assert.equal(get_cell(ws, "A1").v, "Foo");
2155
		assert.equal(get_cell(ws, "A2").v, "Bar");
2156
		assert.equal(get_cell(ws, "A3").v, "Baz");
2157
	});
2158
	if(domtest) it('should ignore hidden rows and cells when the `display` option is on', function() {
2159
		var html = "<table><tr style='display: none;'><td>1</td><td>2</td><td>3</td></tr><tr><td class='hidden'>Foo</td><td>Bar</td><td style='display: none;'>Baz</td></tr></table><style>.hidden {display: none}</style>";
2160
		var ws = X.utils.table_to_sheet(get_dom_element(html), {display: true});
2161
		assert.equal(ws['!ref'], "A1");
2162
		assert.equal(ws.hasOwnProperty('!rows'), false);
2163
		assert.equal(get_cell(ws, "A1").v, "Bar");
2164
	});
2165
	describe('type override', function() {
2166
		function chk(ws) {
2167
			assert.equal(get_cell(ws, "A1").t, "s");
2168
			assert.equal(get_cell(ws, "A1").v, "1234567890");
2169
			assert.equal(get_cell(ws, "B1").t, "n");
2170
			assert.equal(get_cell(ws, "B1").v, 1234567890);
2171
		}
2172
		var html = "<table><tr><td t=\"s\">1234567890</td><td>1234567890</td></tr></table>";
2173
		it('HTML string', function() {
2174
			var ws = X.read(html, {type:'string'}).Sheets.Sheet1; chk(ws);
2175
			chk(X.read(X.utils.sheet_to_html(ws), {type:'string'}).Sheets.Sheet1);
2176
		});
2177
		if(domtest) it('DOM', function() { chk(X.utils.table_to_sheet(get_dom_element(html))); });
2178
	});
2179
	describe('TH/THEAD/TBODY/TFOOT elements', function() {
2180
		var html = "<table><thead><tr><th>A</th><th>B</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></tbody><tfoot><tr><th>4</th><th>6</th></tr></tfoot></table>";
2181
		it('HTML string', function() {
2182
			var ws = X.read(html, {type:'string'}).Sheets.Sheet1;
2183
			assert.equal(X.utils.sheet_to_csv(ws),  "A,B\n1,2\n3,4\n4,6\n");
2184
		});
2185
		if(domtest) it('DOM', function() {
2186
			var ws = X.utils.table_to_sheet(get_dom_element(html));
2187
			assert.equal(X.utils.sheet_to_csv(ws),  "A,B\n1,2\n3,4\n4,6\n");
2188
		});
2189
	});
2190
});
2191
2192
describe('js -> file -> js', function() {
2193
	var wb, BIN="binary";
2194
	var bef = (function() {
2195
		var ws = X.utils.aoa_to_sheet([
2196
			["number", "bool", "string",  "date"],
2197
			[1,        true,   "sheet"],
2198
			[2,        false,  "dot"],
2199
			[6.9,      false,  "JS", fixdate],
2200
			[72.62,    true,   "0.3"]
2201
		]);
2202
		wb = { SheetNames: ['Sheet1'], Sheets: {Sheet1: ws} };
2203
	});
2204
	if(typeof before != 'undefined') before(bef);
2205
	else it('before', bef);
2206
	function eqcell(wb1, wb2, s, a) {
2207
		assert.equal(get_cell(wb1.Sheets[s], a).v, get_cell(wb2.Sheets[s], a).v);
2208
		assert.equal(get_cell(wb1.Sheets[s], a).t, get_cell(wb2.Sheets[s], a).t);
2209
	}
2210
	ofmt.forEach(function(f) {
2211
		it(f, function() {
2212
			var newwb = X.read(X.write(wb, {type:BIN, bookType: f}), {type:BIN});
2213
			var cb = function(cell) { eqcell(wb, newwb, 'Sheet1', cell); };
2214
			['A2', 'A3'].forEach(cb); /* int */
2215
			['A4', 'A5'].forEach(cb); /* double */
2216
			['B2', 'B3'].forEach(cb); /* bool */
2217
			['C2', 'C3'].forEach(cb); /* string */
2218
			if(!DIF_XL) cb('D4'); /* date */
2219
			if(DIF_XL && f == "dif") assert.equal(get_cell(newwb.Sheets.Sheet1, 'C5').v, '=""0.3""');// dif forces string formula
2220
			else if(f != 'csv' && f != 'txt') eqcell(wb, newwb, 'Sheet1', 'C5');
2221
		});
2222
	});
2223
});
2224
2225
describe('corner cases', function() {
2226
	it('output functions', function() {
2227
		var ws = X.utils.aoa_to_sheet([
2228
			[1,2,3],
2229
			[true, false, null, "sheetjs"],
2230
			["foo", "bar", fixdate, "0.3"],
2231
			["baz", null, "q\"ux"]
2232
		]);
2233
		get_cell(ws,"A1").f = ""; get_cell(ws,"A1").w = "";
2234
		delete get_cell(ws,"C3").w; delete get_cell(ws,"C3").z; get_cell(ws,"C3").XF = {ifmt:14};
2235
		get_cell(ws,"A4").t = "e";
2236
		X.utils.get_formulae(ws);
2237
		X.utils.make_csv(ws);
2238
		X.utils.make_json(ws);
2239
		ws['!cols'] = [ {wch:6}, {wch:7}, {wch:10}, {wch:20} ];
2240
2241
		var wb = {SheetNames:['sheetjs'], Sheets:{sheetjs:ws}};
2242
		X.write(wb, {type: "binary", bookType: 'xlsx'});
2243
		X.write(wb, {type: TYPE, bookType: 'xlsm'});
2244
		X.write(wb, {type: "base64", bookType: 'xlsb'});
2245
		X.write(wb, {type: "binary", bookType: 'ods'});
2246
		X.write(wb, {type: "binary", bookType: 'biff2'});
2247
		X.write(wb, {type: "binary", bookType: 'biff5'});
2248
		X.write(wb, {type: "binary", bookType: 'biff8'});
2249
		get_cell(ws,"A2").t = "f";
2250
		assert.throws(function() { X.utils.make_json(ws); });
2251
	});
2252
	it('SSF', function() {
2253
		X.SSF.format("General", "dafuq");
2254
		assert.throws(function() { return X.SSF.format("General", {sheet:"js"});});
2255
		X.SSF.format("b e ddd hh AM/PM", 41722.4097222222);
2256
		X.SSF.format("b ddd hh m", 41722.4097222222);
2257
		["hhh","hhh A/P","hhmmm","sss","[hhh]","G eneral"].forEach(function(f) {
2258
			assert.throws(function() { return X.SSF.format(f, 12345.6789);});
2259
		});
2260
		["[m]","[s]"].forEach(function(f) {
2261
			assert.doesNotThrow(function() { return X.SSF.format(f, 12345.6789);});
2262
		});
2263
	});
2264
	if(typeof JSON !== 'undefined') it('SSF oddities', function() {
2265
		// $FlowIgnore
2266
		var ssfdata = require('./misc/ssf.json');
2267
		var cb = function(d, j) { return function() { return X.SSF.format(d[0], d[j][0]); }; };
2268
		ssfdata.forEach(function(d) {
2269
			for(var j=1;j<d.length;++j) {
2270
				if(d[j].length == 2) {
2271
					var expected = d[j][1], actual = X.SSF.format(d[0], d[j][0], {});
2272
					assert.equal(actual, expected);
2273
				} else if(d[j][2] !== "#") assert.throws(cb(d, j));
2274
			}
2275
		});
2276
	});
2277
	it('codepage', function() {
2278
		X.read(fs.readFileSync(dir + "biff5/number_format_greek.xls"), {type:TYPE});
2279
	});
2280
	it('large binary files', function() {
2281
		var data = [["Row Number"]];
2282
		for(var j = 0; j < 19; ++j) data[0].push("Column " + j+1);
2283
		for(var i = 0; i < 499; ++i) {
2284
			var o = ["Row " + i];
2285
			for(j = 0; j < 19; ++j) o.push(i + j);
2286
			data.push(o);
2287
		}
2288
		var ws = X.utils.aoa_to_sheet(data);
2289
		var wb = { Sheets:{ Sheet1: ws }, SheetNames: ["Sheet1"] };
2290
		var type = "binary";
2291
		["xlsb", "biff8", "biff5", "biff2"].forEach(function(btype) {
2292
			void X.read(X.write(wb, {bookType:btype, type:type}), {type:type});
2293
		});
2294
	});
2295
	if(fs.existsSync(dir + 'wtf_path.xlsx')) it('OPC oddities', function() {
2296
		X.read(fs.readFileSync(dir + 'wtf_path.xlsx'), {WTF:1, type:TYPE});
2297
		X.read(fs.readFileSync(dir + 'wtf_path.xlsb'), {WTF:1, type:TYPE});
2298
	});
2299
});
2300
2301
describe('encryption', function() {
2302
	password_files.forEach(function(x) {
2303
		describe(x, function() {
2304
			it('should throw with no password', function() {assert.throws(function() { X.read(fs.readFileSync(dir + x), {type:TYPE}); }); });
2305
			it('should throw with wrong password', function() {
2306
				try {
2307
					X.read(fs.readFileSync(dir + x), {type:TYPE,password:'Password',WTF:opts.WTF});
2308
					throw new Error("incorrect password was accepted");
2309
				} catch(e) {
2310
					if(e.message != "Password is incorrect") throw e;
2311
				}
2312
			});
2313
			it('should recognize correct password', function() {
2314
				try {
2315
					X.read(fs.readFileSync(dir + x), {type:TYPE,password:'password',WTF:opts.WTF});
2316
				} catch(e) {
2317
					if(e.message == "Password is incorrect") throw e;
2318
				}
2319
			});
2320
			it.skip('should decrypt file', function() {
2321
				/*var wb = */X.read(fs.readFileSync(dir + x), {type:TYPE,password:'password',WTF:opts.WTF});
2322
			});
2323
		});
2324
	});
2325
});
2326
2327
if(!browser || typeof cptable !== 'undefined')
2328
describe('multiformat tests', function() {
2329
var mfopts = opts;
2330
var mft = fs.readFileSync('multiformat.lst','utf-8').split("\n").map(function(x) { return x.trim(); });
2331
var csv = true, formulae = false;
2332
mft.forEach(function(x) {
2333
	if(x.charAt(0)!="#") describe('MFT ' + x, function() {
2334
		var f = [], r = x.split(/\s+/);
2335
		if(r.length < 3) return;
2336
		if(!fs.existsSync(dir + r[0] + r[1])) return;
2337
		it('should parse all', function() {
2338
			for(var j = 1; j < r.length; ++j) f[j-1] = X.read(fs.readFileSync(dir + r[0] + r[j]), mfopts);
2339
		});
2340
		it('should have the same sheetnames', function() {
2341
			cmparr(f.map(function(x) { return x.SheetNames; }));
2342
		});
2343
		it('should have the same ranges', function() {
2344
			f[0].SheetNames.forEach(function(s) {
2345
				var ss = f.map(function(x) { return x.Sheets[s]; });
2346
				cmparr(ss.map(function(s) { return s['!ref']; }));
2347
			});
2348
		});
2349
		it('should have the same merges', function() {
2350
			f[0].SheetNames.forEach(function(s) {
2351
				var ss = f.map(function(x) { return x.Sheets[s]; });
2352
				cmparr(ss.map(function(s) { return (s['!merges']||[]).map(function(y) { return X.utils.encode_range(y); }).sort(); }));
2353
			});
2354
		});
2355
		it('should have the same CSV', csv ? function() {
2356
			cmparr(f.map(function(x) { return x.SheetNames; }));
2357
			f[0].SheetNames.forEach(function(name) {
2358
				cmparr(f.map(function(x) { return X.utils.sheet_to_csv(x.Sheets[name]); }));
2359
			});
2360
		} : null);
2361
		it('should have the same formulae', formulae ? function() {
2362
			cmparr(f.map(function(x) { return x.SheetNames; }));
2363
			f[0].SheetNames.forEach(function(name) {
2364
				cmparr(f.map(function(x) { return X.utils.sheet_to_formulae(x.Sheets[name]).sort(); }));
2365
			});
2366
		} : null);
2367
2368
	});
2369
	else x.split(/\s+/).forEach(function(w) { switch(w) {
2370
		case "no-csv": csv = false; break;
2371
		case "yes-csv": csv = true; break;
2372
		case "no-formula": formulae = false; break;
2373
		case "yes-formula": formulae = true; break;
2374
	}});
2375
}); });
2376
2377