bare-script 3.5.5 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -19
- package/lib/bare.js +6 -10
- package/lib/include/args.bare +8 -8
- package/lib/include/dataTable.bare +211 -0
- package/lib/include/diff.bare +1 -1
- package/lib/include/markdownUp.bare +8 -117
- package/lib/include/pager.bare +3 -3
- package/lib/include/unittest.bare +365 -89
- package/lib/library.js +76 -0
- package/lib/model.js +70 -12
- package/lib/options.js +45 -2
- package/lib/parser.js +224 -84
- package/lib/runtime.js +87 -28
- package/lib/runtimeAsync.js +68 -49
- package/package.json +2 -2
|
@@ -9,7 +9,9 @@ endif
|
|
|
9
9
|
unittestSentinel = true
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
include
|
|
12
|
+
include <args.bare>
|
|
13
|
+
include <dataTable.bare>
|
|
14
|
+
include <diff.bare>
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
# Test statistics
|
|
@@ -21,7 +23,7 @@ unittestWarnings = arrayNew()
|
|
|
21
23
|
# $group: unittest.bare
|
|
22
24
|
# $doc: Run a unit test
|
|
23
25
|
# $arg testName: The test function name
|
|
24
|
-
function unittestRunTest(testName):
|
|
26
|
+
async function unittestRunTest(testName):
|
|
25
27
|
testFn = unittestRunTestHelper(testName)
|
|
26
28
|
if testFn:
|
|
27
29
|
testFn()
|
|
@@ -30,23 +32,17 @@ function unittestRunTest(testName):
|
|
|
30
32
|
endfunction
|
|
31
33
|
|
|
32
34
|
|
|
33
|
-
#
|
|
34
|
-
# $group: unittest.bare
|
|
35
|
-
# $doc: Run an asyncronous unit test
|
|
36
|
-
# $arg testName: The test function name
|
|
35
|
+
# For backward compatibility
|
|
37
36
|
async function unittestRunTestAsync(testName):
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
testFn()
|
|
41
|
-
systemGlobalSet('unittestTestName', null)
|
|
42
|
-
endif
|
|
37
|
+
systemLogDebug('unittest.bare: unittestRunTestAsync is deprecated - use unittestRunTest')
|
|
38
|
+
return unittestRunTest(testName)
|
|
43
39
|
endfunction
|
|
44
40
|
|
|
45
41
|
|
|
46
42
|
# unittestRunTest helper function
|
|
47
43
|
function unittestRunTestHelper(testName):
|
|
48
44
|
# Single test argument?
|
|
49
|
-
if
|
|
45
|
+
if vUnittestTest && vUnittestTest != testName:
|
|
50
46
|
return null
|
|
51
47
|
endif
|
|
52
48
|
|
|
@@ -58,7 +54,7 @@ function unittestRunTestHelper(testName):
|
|
|
58
54
|
|
|
59
55
|
# Get the test func
|
|
60
56
|
testFn = systemGlobalGet(testName)
|
|
61
|
-
if testFn
|
|
57
|
+
if !testFn:
|
|
62
58
|
arrayPush(unittestWarnings, 'Test "' + testName + '" not found')
|
|
63
59
|
return null
|
|
64
60
|
endif
|
|
@@ -72,78 +68,6 @@ function unittestRunTestHelper(testName):
|
|
|
72
68
|
endfunction
|
|
73
69
|
|
|
74
70
|
|
|
75
|
-
# $function: unittestReport
|
|
76
|
-
# $group: unittest.bare
|
|
77
|
-
# $doc: Render the unit test report
|
|
78
|
-
# $return: The number of unit test failures
|
|
79
|
-
function unittestReport():
|
|
80
|
-
# Compute test statistics
|
|
81
|
-
testNames = arraySort(objectKeys(unittestTests))
|
|
82
|
-
testCount = arrayLength(testNames)
|
|
83
|
-
testFailCount = 0
|
|
84
|
-
for testName in testNames:
|
|
85
|
-
testFailures = objectGet(unittestTests, testName)
|
|
86
|
-
if arrayLength(testFailures):
|
|
87
|
-
testFailCount = testFailCount + 1
|
|
88
|
-
endif
|
|
89
|
-
endfor
|
|
90
|
-
testPassCount = testCount - testFailCount
|
|
91
|
-
|
|
92
|
-
# Report statistics
|
|
93
|
-
markdownPrint('', 'Ran ' + testCount + ' tests - ' + testPassCount + ' passed, ' + testFailCount + ' failed')
|
|
94
|
-
if vTest != null:
|
|
95
|
-
testURL = if(vTestArgs != null, '#' + vTestArgs, '#var=')
|
|
96
|
-
markdownPrint('([all tests](' + testURL + '))')
|
|
97
|
-
endif
|
|
98
|
-
|
|
99
|
-
# Report any warnings
|
|
100
|
-
testWarningCount = arrayLength(unittestWarnings)
|
|
101
|
-
if testWarningCount:
|
|
102
|
-
markdownPrint('', '## Warnings')
|
|
103
|
-
for warning in unittestWarnings:
|
|
104
|
-
markdownPrint('', '- ' + markdownEscape(warning))
|
|
105
|
-
endfor
|
|
106
|
-
endif
|
|
107
|
-
|
|
108
|
-
# Report the failing tests
|
|
109
|
-
if testFailCount:
|
|
110
|
-
markdownPrint('', '## Failing Tests')
|
|
111
|
-
for testName in testNames:
|
|
112
|
-
testFailures = objectGet(unittestTests, testName)
|
|
113
|
-
if arrayLength(testFailures):
|
|
114
|
-
testURL = '#' + if(vTestArgs != null, vTestArgs + '&', '') + "var.vTest='" + urlEncodeComponent(testName) + "'"
|
|
115
|
-
failureLines = arrayNew('', '[' + markdownEscape(testName) + '](' + testURL + ") - FAIL")
|
|
116
|
-
for errorLines in testFailures:
|
|
117
|
-
for errorLine, ixErrorLine in errorLines:
|
|
118
|
-
if ixErrorLine == 0:
|
|
119
|
-
arrayPush(failureLines, '')
|
|
120
|
-
arrayPush(failureLines, '- ' + errorLine)
|
|
121
|
-
else:
|
|
122
|
-
arrayPush(failureLines, if(errorLine, ' ' + errorLine, ''))
|
|
123
|
-
endif
|
|
124
|
-
endfor
|
|
125
|
-
endfor
|
|
126
|
-
markdownPrint(failureLines)
|
|
127
|
-
endif
|
|
128
|
-
endfor
|
|
129
|
-
endif
|
|
130
|
-
|
|
131
|
-
# Report the passing tests
|
|
132
|
-
if testPassCount:
|
|
133
|
-
markdownPrint('', '## Passing Tests')
|
|
134
|
-
for testName in testNames:
|
|
135
|
-
testFailures = objectGet(unittestTests, testName)
|
|
136
|
-
if !arrayLength(testFailures):
|
|
137
|
-
testURL = '#' + if(vTestArgs != null, vTestArgs + '&', '') + "var.vTest='" + urlEncodeComponent(testName) + "'"
|
|
138
|
-
markdownPrint('', '[' + markdownEscape(testName) + '](' + testURL + ") - OK")
|
|
139
|
-
endif
|
|
140
|
-
endfor
|
|
141
|
-
endif
|
|
142
|
-
|
|
143
|
-
return testWarningCount + testFailCount
|
|
144
|
-
endfunction
|
|
145
|
-
|
|
146
|
-
|
|
147
71
|
# $function: unittestEqual
|
|
148
72
|
# $group: unittest.bare
|
|
149
73
|
# $doc: Assert an actual value is equal to the expected value
|
|
@@ -168,8 +92,8 @@ function unittestEqual(actual, expected, description):
|
|
|
168
92
|
jsonStringify(expected), \
|
|
169
93
|
'```' \
|
|
170
94
|
)
|
|
171
|
-
if description
|
|
172
|
-
arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), errorLines))
|
|
95
|
+
if description:
|
|
96
|
+
arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), ''), errorLines))
|
|
173
97
|
else:
|
|
174
98
|
arrayPush(testFailures, errorLines)
|
|
175
99
|
endif
|
|
@@ -221,9 +145,361 @@ function unittestDeepEqual(actual, expected, description):
|
|
|
221
145
|
|
|
222
146
|
# Add the test failure error lines
|
|
223
147
|
testFailures = objectGet(unittestTests, unittestTestName)
|
|
224
|
-
if description
|
|
225
|
-
arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), errorLines))
|
|
148
|
+
if description:
|
|
149
|
+
arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), ''), errorLines))
|
|
226
150
|
else:
|
|
227
151
|
arrayPush(testFailures, errorLines)
|
|
228
152
|
endif
|
|
229
153
|
endfunction
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# $function: unittestReport
|
|
157
|
+
# $group: unittest.bare
|
|
158
|
+
# $doc: Render the unit test report
|
|
159
|
+
# $arg options: Optional unittest report options object. The following options are available:
|
|
160
|
+
# $arg options: - **coverageExclude** - array of script names to exclude from coverage
|
|
161
|
+
# $arg options: - **coverageMin** - verify minimum coverage percent (0 - 100)
|
|
162
|
+
# $arg options: - **links** - the array of page links
|
|
163
|
+
# $arg options: - **title** - the page title
|
|
164
|
+
# $return: The number of unit test failures
|
|
165
|
+
function unittestReport(options):
|
|
166
|
+
coverageMin = if(options, objectGet(options, 'coverageMin', 0), 0)
|
|
167
|
+
coverageExclude = if(options, objectGet(options, 'coverageExclude'))
|
|
168
|
+
links = if(options, objectGet(options, 'links'))
|
|
169
|
+
defaultTitle = 'unittestReport'
|
|
170
|
+
title = if(options, objectGet(options, 'title', defaultTitle), defaultTitle)
|
|
171
|
+
|
|
172
|
+
# Parse arguments
|
|
173
|
+
args = argsParse(unittestReportArguments)
|
|
174
|
+
testNameArg = objectGet(args, 'test')
|
|
175
|
+
scriptName = objectGet(args, 'script')
|
|
176
|
+
hideTests = objectGet(args, 'hideTests')
|
|
177
|
+
isReport = objectGet(args, 'report')
|
|
178
|
+
|
|
179
|
+
# Script coverage details page?
|
|
180
|
+
if scriptName:
|
|
181
|
+
unittestReportScript(scriptName)
|
|
182
|
+
return 0
|
|
183
|
+
endif
|
|
184
|
+
|
|
185
|
+
# Compute test statistics
|
|
186
|
+
testNames = arraySort(objectKeys(unittestTests))
|
|
187
|
+
testCount = arrayLength(testNames)
|
|
188
|
+
testFailCount = 0
|
|
189
|
+
for testName in testNames:
|
|
190
|
+
testFailures = objectGet(unittestTests, testName)
|
|
191
|
+
if arrayLength(testFailures):
|
|
192
|
+
testFailCount = testFailCount + 1
|
|
193
|
+
endif
|
|
194
|
+
endfor
|
|
195
|
+
testPassCount = testCount - testFailCount
|
|
196
|
+
|
|
197
|
+
# Render the links
|
|
198
|
+
if !isReport && links:
|
|
199
|
+
markdownPrint(arrayJoin(links, ' | '))
|
|
200
|
+
endif
|
|
201
|
+
|
|
202
|
+
# Render the page title
|
|
203
|
+
documentSetTitle(title)
|
|
204
|
+
markdownPrint( \
|
|
205
|
+
'# ' + markdownEscape(title), \
|
|
206
|
+
'', \
|
|
207
|
+
'Ran ' + testCount + ' tests - ' + testPassCount + ' passed, ' + testFailCount + ' failed' \
|
|
208
|
+
)
|
|
209
|
+
if !isReport:
|
|
210
|
+
if testNameArg:
|
|
211
|
+
markdownPrint('', argsLink(unittestReportArguments, 'All tests', null, true))
|
|
212
|
+
else:
|
|
213
|
+
markdownPrint('', argsLink(unittestReportArguments, if(hideTests, 'Show', 'Hide') + ' tests', objectNew('hideTests', !hideTests)))
|
|
214
|
+
endif
|
|
215
|
+
endif
|
|
216
|
+
|
|
217
|
+
# Report any warnings
|
|
218
|
+
testWarningCount = arrayLength(unittestWarnings)
|
|
219
|
+
if testWarningCount:
|
|
220
|
+
markdownPrint('', '## Warnings')
|
|
221
|
+
for warning in unittestWarnings:
|
|
222
|
+
markdownPrint('', '- ' + markdownEscape(warning))
|
|
223
|
+
endfor
|
|
224
|
+
endif
|
|
225
|
+
|
|
226
|
+
# Report the failing tests
|
|
227
|
+
if testFailCount:
|
|
228
|
+
markdownPrint('', '## Failing Tests')
|
|
229
|
+
if hideTests && !isReport && !testNameArg:
|
|
230
|
+
markdownPrint('', argsLink(unittestReportArguments, 'Show', objectNew('hideTests', false)))
|
|
231
|
+
endif
|
|
232
|
+
if !hideTests || testNameArg:
|
|
233
|
+
for testName in testNames:
|
|
234
|
+
testFailures = objectGet(unittestTests, testName)
|
|
235
|
+
if arrayLength(testFailures):
|
|
236
|
+
failureLink = if(isReport, testName, \
|
|
237
|
+
argsLink(unittestReportArguments, testName, objectNew('test', testName), false, '_top'))
|
|
238
|
+
failureLines = arrayNew('', failureLink + ' - FAIL')
|
|
239
|
+
for errorLines in testFailures:
|
|
240
|
+
for errorLine, ixErrorLine in errorLines:
|
|
241
|
+
if ixErrorLine == 0:
|
|
242
|
+
arrayPush(failureLines, '')
|
|
243
|
+
arrayPush(failureLines, '- ' + errorLine)
|
|
244
|
+
else:
|
|
245
|
+
arrayPush(failureLines, if(errorLine, ' ' + errorLine, ''))
|
|
246
|
+
endif
|
|
247
|
+
endfor
|
|
248
|
+
endfor
|
|
249
|
+
markdownPrint(failureLines)
|
|
250
|
+
endif
|
|
251
|
+
endfor
|
|
252
|
+
endif
|
|
253
|
+
endif
|
|
254
|
+
|
|
255
|
+
# Report the passing tests
|
|
256
|
+
if testPassCount:
|
|
257
|
+
markdownPrint('', '## Passing Tests')
|
|
258
|
+
if hideTests && !isReport && !testNameArg:
|
|
259
|
+
markdownPrint('', argsLink(unittestReportArguments, 'Show', objectNew('hideTests', false)))
|
|
260
|
+
endif
|
|
261
|
+
if !hideTests || testNameArg:
|
|
262
|
+
for testName in testNames:
|
|
263
|
+
testFailures = objectGet(unittestTests, testName)
|
|
264
|
+
if !arrayLength(testFailures):
|
|
265
|
+
testLink = if(isReport, testName, \
|
|
266
|
+
argsLink(unittestReportArguments, testName, objectNew('test', testName), false, '_top'))
|
|
267
|
+
markdownPrint('', testLink + ' - OK')
|
|
268
|
+
endif
|
|
269
|
+
endfor
|
|
270
|
+
endif
|
|
271
|
+
endif
|
|
272
|
+
|
|
273
|
+
# Coverage report
|
|
274
|
+
coverage = coverageGlobalGet()
|
|
275
|
+
coverageFailCount = 0
|
|
276
|
+
if !testNameArg && coverage:
|
|
277
|
+
markdownPrint('', '## Coverage Report')
|
|
278
|
+
|
|
279
|
+
# Compute the coverage data table
|
|
280
|
+
coverageData = unittestCoverageData(coverageExclude)
|
|
281
|
+
if coverageData:
|
|
282
|
+
# Verify the coverage percent
|
|
283
|
+
coveragePercent = objectGet(arrayGet(coverageData, arrayLength(coverageData) - 1), 'Coverage')
|
|
284
|
+
if coveragePercent < coverageMin:
|
|
285
|
+
markdownPrint( \
|
|
286
|
+
'', \
|
|
287
|
+
'**Error**: Coverage percentage, ' + numberToFixed(coveragePercent, 1, true) + \
|
|
288
|
+
'%, is below the minimum coverage percentage of ' + numberToFixed(coverageMin, 1, true) + '%.' \
|
|
289
|
+
)
|
|
290
|
+
coverageFailCount = coverageFailCount + 1
|
|
291
|
+
endif
|
|
292
|
+
|
|
293
|
+
# Render the coverage data table
|
|
294
|
+
for row in coverageData:
|
|
295
|
+
scriptName = objectGet(row, 'Script')
|
|
296
|
+
if !isReport && !stringStartsWith(scriptName, '**'):
|
|
297
|
+
objectSet(row, 'Script', argsLink(unittestReportArguments, scriptName, objectNew("script", scriptName), false, "_top"))
|
|
298
|
+
endif
|
|
299
|
+
objectSet(row, 'Coverage', numberToFixed(objectGet(row, 'Coverage'), 1) + '%')
|
|
300
|
+
endfor
|
|
301
|
+
markdownPrint('', dataTableMarkdown(coverageData, objectNew( \
|
|
302
|
+
'fields', arrayNew('Script', 'Statements', 'Missing', 'Coverage'), \
|
|
303
|
+
'formats', objectNew( \
|
|
304
|
+
'Statements', objectNew('align', 'right'), \
|
|
305
|
+
'Missing', objectNew('align', 'right'), \
|
|
306
|
+
'Coverage', objectNew('align', 'right') \
|
|
307
|
+
) \
|
|
308
|
+
)))
|
|
309
|
+
else:
|
|
310
|
+
markdownPrint('', '*No data.*')
|
|
311
|
+
endif
|
|
312
|
+
endif
|
|
313
|
+
|
|
314
|
+
# Return status code
|
|
315
|
+
return testWarningCount + testFailCount + coverageFailCount
|
|
316
|
+
endfunction
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# unittestReport application arguments
|
|
320
|
+
unittestReportArguments = argsValidate(arrayNew( \
|
|
321
|
+
objectNew('name', 'test', 'global', 'vUnittestTest'), \
|
|
322
|
+
objectNew('name', 'script', 'global', 'vUnittestScript'), \
|
|
323
|
+
objectNew('name', 'hideTests', 'global', 'vUnittestHideTests', 'type', 'bool', 'default', false), \
|
|
324
|
+
objectNew('name', 'report', 'global', 'vUnittestReport', 'type', 'bool', 'default', false) \
|
|
325
|
+
))
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# Render the script coverage details page
|
|
329
|
+
function unittestReportScript(scriptName):
|
|
330
|
+
# Render the script coverage page title
|
|
331
|
+
title = scriptName + ' Coverage'
|
|
332
|
+
documentSetTitle(title)
|
|
333
|
+
markdownPrint( \
|
|
334
|
+
argsLink(unittestReportArguments, 'Back', objectNew('script', null), false, '_top'), \
|
|
335
|
+
'', \
|
|
336
|
+
'# ' + markdownEscape(title) \
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
# Get the script coverage data
|
|
340
|
+
coverage = coverageGlobalGet()
|
|
341
|
+
scripts = if(coverage, objectGet(coverage, 'scripts'))
|
|
342
|
+
coverageScript = if(scripts, objectGet(scripts, scriptName))
|
|
343
|
+
if !coverageScript:
|
|
344
|
+
markdownPrint('', '*No data.*')
|
|
345
|
+
return
|
|
346
|
+
endif
|
|
347
|
+
script = objectGet(coverageScript, 'script')
|
|
348
|
+
covered = objectGet(coverageScript, 'covered')
|
|
349
|
+
scriptLines = objectGet(script, 'scriptLines')
|
|
350
|
+
|
|
351
|
+
# Mark the statements covered or not-covered
|
|
352
|
+
lineColors = objectNew()
|
|
353
|
+
statements = unittestScriptStatements(script)
|
|
354
|
+
for statement in statements:
|
|
355
|
+
statementKey = arrayGet(objectKeys(statement), 0)
|
|
356
|
+
lineNumber = objectGet(objectGet(statement, statementKey), 'lineNumber')
|
|
357
|
+
lineCount = objectGet(objectGet(statement, statementKey), 'lineCount', 1)
|
|
358
|
+
lineStr = stringNew(lineNumber)
|
|
359
|
+
lineColor = if(objectHas(covered, lineStr), '#a0a0a030', '#f0808080')
|
|
360
|
+
objectSet(lineColors, lineStr, lineColor)
|
|
361
|
+
if lineCount > 1:
|
|
362
|
+
lineNumberEnd = lineNumber + lineCount
|
|
363
|
+
lineNumber = lineNumber + 1
|
|
364
|
+
while lineNumber < lineNumberEnd:
|
|
365
|
+
objectSet(lineColors, stringNew(lineNumber), lineColor)
|
|
366
|
+
lineNumber = lineNumber + 1
|
|
367
|
+
endwhile
|
|
368
|
+
endif
|
|
369
|
+
endfor
|
|
370
|
+
|
|
371
|
+
# Generate the code coverage details
|
|
372
|
+
codeLineElements = arrayNew()
|
|
373
|
+
codeElements = objectNew('html', 'pre', 'elem', codeLineElements)
|
|
374
|
+
currentLines = arrayNew()
|
|
375
|
+
currentColor = null
|
|
376
|
+
for line, ixLine in scriptLines:
|
|
377
|
+
# Accumulate lines of the same color
|
|
378
|
+
lineColor = objectGet(lineColors, stringNew(ixLine + 1))
|
|
379
|
+
if lineColor == currentColor:
|
|
380
|
+
arrayPush(currentLines, line)
|
|
381
|
+
continue
|
|
382
|
+
endif
|
|
383
|
+
|
|
384
|
+
# Render the current lines
|
|
385
|
+
unittestReportScriptLines(codeLineElements, currentLines, currentColor)
|
|
386
|
+
currentLines = arrayNew(line)
|
|
387
|
+
currentColor = lineColor
|
|
388
|
+
endfor
|
|
389
|
+
unittestReportScriptLines(codeLineElements, currentLines, currentColor, true)
|
|
390
|
+
elementModelRender(codeElements)
|
|
391
|
+
endfunction
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
function unittestReportScriptLines(codeLineElements, lines, color, noNewline):
|
|
395
|
+
if lines:
|
|
396
|
+
linesStr = arrayJoin(lines, stringFromCharCode(10)) + if(noNewline, '', stringFromCharCode(10))
|
|
397
|
+
if !color:
|
|
398
|
+
arrayPush(codeLineElements, objectNew('text', linesStr))
|
|
399
|
+
else:
|
|
400
|
+
arrayPush(codeLineElements, objectNew( \
|
|
401
|
+
'html', 'span', \
|
|
402
|
+
'attr', objectNew('style', 'display: block; background-color: ' + color), \
|
|
403
|
+
'elem', objectNew('text', linesStr) \
|
|
404
|
+
))
|
|
405
|
+
endif
|
|
406
|
+
endif
|
|
407
|
+
endfunction
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
# Get the coverage data table - columns are "Script", "Statement", "Covered", and "Percent"
|
|
411
|
+
function unittestCoverageData(coverageExclude):
|
|
412
|
+
data = arrayNew()
|
|
413
|
+
|
|
414
|
+
# Get the global coverage object
|
|
415
|
+
coverage = coverageGlobalGet()
|
|
416
|
+
if coverage:
|
|
417
|
+
# Get the script names with coverage data
|
|
418
|
+
scripts = objectGet(coverage, 'scripts')
|
|
419
|
+
scriptNames = if(scripts, arraySort(objectKeys(scripts)), arrayNew())
|
|
420
|
+
|
|
421
|
+
# Compute script statement coverage
|
|
422
|
+
totalStatements = 0
|
|
423
|
+
totalMissing = 0
|
|
424
|
+
for scriptName in scriptNames:
|
|
425
|
+
# Excluded?
|
|
426
|
+
if coverageExclude:
|
|
427
|
+
isExcluded = false
|
|
428
|
+
for excludeScriptName in coverageExclude:
|
|
429
|
+
if stringEndsWith(scriptName, excludeScriptName):
|
|
430
|
+
isExcluded = true
|
|
431
|
+
break
|
|
432
|
+
endif
|
|
433
|
+
endfor
|
|
434
|
+
if isExcluded:
|
|
435
|
+
continue
|
|
436
|
+
endif
|
|
437
|
+
endif
|
|
438
|
+
|
|
439
|
+
# Get the script members
|
|
440
|
+
coverageScript = objectGet(scripts, scriptName)
|
|
441
|
+
script = objectGet(coverageScript, 'script')
|
|
442
|
+
covered = objectGet(coverageScript, 'covered')
|
|
443
|
+
statements = unittestScriptStatements(script)
|
|
444
|
+
statementCount = arrayLength(statements)
|
|
445
|
+
|
|
446
|
+
# Count statements with coverage
|
|
447
|
+
missingCount = 0
|
|
448
|
+
for statement in statements:
|
|
449
|
+
statementKey = arrayGet(objectKeys(statement), 0)
|
|
450
|
+
lineNumber = objectGet(objectGet(statement, statementKey), 'lineNumber')
|
|
451
|
+
lineStr = stringNew(lineNumber)
|
|
452
|
+
if !objectHas(covered, lineStr):
|
|
453
|
+
missingCount = missingCount + 1
|
|
454
|
+
totalMissing = totalMissing + 1
|
|
455
|
+
endif
|
|
456
|
+
totalStatements = totalStatements + 1
|
|
457
|
+
endfor
|
|
458
|
+
|
|
459
|
+
# Add the script coverage data row
|
|
460
|
+
coveragePercent = if(statementCount, 100 * (statementCount - missingCount) / statementCount, 100)
|
|
461
|
+
arrayPush(data, objectNew( \
|
|
462
|
+
'Script', scriptName, \
|
|
463
|
+
'Statements', statementCount, \
|
|
464
|
+
'Missing', missingCount, \
|
|
465
|
+
'Coverage', coveragePercent, \
|
|
466
|
+
'CoverageStr', numberToFixed(coveragePercent, 1) + '%' \
|
|
467
|
+
))
|
|
468
|
+
endfor
|
|
469
|
+
|
|
470
|
+
# Add the coverage totals data row
|
|
471
|
+
if scriptNames:
|
|
472
|
+
coveragePercent = if(totalStatements, 100 * (totalStatements - totalMissing) / totalStatements, 100)
|
|
473
|
+
arrayPush(data, objectNew( \
|
|
474
|
+
'Script', '**Total**', \
|
|
475
|
+
'Statements', totalStatements, \
|
|
476
|
+
'Missing', totalMissing, \
|
|
477
|
+
'Coverage', coveragePercent, \
|
|
478
|
+
'CoverageStr', numberToFixed(coveragePercent, 1) + '%' \
|
|
479
|
+
))
|
|
480
|
+
endif
|
|
481
|
+
endif
|
|
482
|
+
|
|
483
|
+
return data
|
|
484
|
+
endfunction
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
# Get a script's array of statements
|
|
488
|
+
function unittestScriptStatements(script):
|
|
489
|
+
statements = arrayNew()
|
|
490
|
+
|
|
491
|
+
# Add the top-level script statements
|
|
492
|
+
for statement in objectGet(script, 'statements'):
|
|
493
|
+
arrayPush(statements, statement)
|
|
494
|
+
|
|
495
|
+
# Add function statements
|
|
496
|
+
statementKey = arrayGet(objectKeys(statement), 0)
|
|
497
|
+
if statementKey == 'function':
|
|
498
|
+
for funcStatement in objectGet(objectGet(statement, statementKey), 'statements'):
|
|
499
|
+
arrayPush(statements, funcStatement)
|
|
500
|
+
endfor
|
|
501
|
+
endif
|
|
502
|
+
endfor
|
|
503
|
+
|
|
504
|
+
return statements
|
|
505
|
+
endfunction
|
package/lib/library.js
CHANGED
|
@@ -78,6 +78,21 @@ const arrayExtendArgs = valueArgsModel([
|
|
|
78
78
|
]);
|
|
79
79
|
|
|
80
80
|
|
|
81
|
+
// $function: arrayFlat
|
|
82
|
+
// $group: Array
|
|
83
|
+
// $doc: Flat an array hierarchy
|
|
84
|
+
// $arg array: The array to flat
|
|
85
|
+
// $return: The flated array
|
|
86
|
+
function arrayFlat(args) {
|
|
87
|
+
const [array] = valueArgsValidate(arrayFlatArgs, args);
|
|
88
|
+
return array.flat(Infinity);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const arrayFlatArgs = valueArgsModel([
|
|
92
|
+
{'name': 'array', 'type': 'array'}
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
|
|
81
96
|
// $function: arrayGet
|
|
82
97
|
// $group: Array
|
|
83
98
|
// $doc: Get an array element
|
|
@@ -353,6 +368,60 @@ const arraySortArgs = valueArgsModel([
|
|
|
353
368
|
]);
|
|
354
369
|
|
|
355
370
|
|
|
371
|
+
//
|
|
372
|
+
// Coverage functions
|
|
373
|
+
//
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
// Coverage configuration object global variable name
|
|
377
|
+
export const coverageGlobalName = '__bareScriptCoverage';
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
// $function: coverageGlobalGet
|
|
381
|
+
// $group: Coverage
|
|
382
|
+
// $doc: Get the coverage global object
|
|
383
|
+
// $return: The [coverage global object](https://craigahobbs.github.io/bare-script/model/#var.vName='CoverageGlobal')
|
|
384
|
+
function coverageGlobalGet(unusedArgs, options) {
|
|
385
|
+
const globals = (options !== null ? (options.globals ?? null) : null);
|
|
386
|
+
return globals !== null ? (globals[coverageGlobalName] ?? null) : null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
// $function: coverageGlobalName
|
|
391
|
+
// $group: Coverage
|
|
392
|
+
// $doc: Get the coverage global variable name
|
|
393
|
+
// $return: The coverage global variable name
|
|
394
|
+
function coverageGlobalNameFn() {
|
|
395
|
+
return coverageGlobalName;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
// $function: coverageStart
|
|
400
|
+
// $group: Coverage
|
|
401
|
+
// $doc: Start coverage data collection
|
|
402
|
+
function coverageStart(unusedArgs, options) {
|
|
403
|
+
const globals = (options !== null ? (options.globals ?? null) : null);
|
|
404
|
+
if (globals !== null) {
|
|
405
|
+
const coverageGlobal = {'enabled': true};
|
|
406
|
+
globals[coverageGlobalName] = coverageGlobal;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
// $function: coverageStop
|
|
412
|
+
// $group: Coverage
|
|
413
|
+
// $doc: Stop coverage data collection
|
|
414
|
+
function coverageStop(unusedArgs, options) {
|
|
415
|
+
const globals = (options !== null ? (options.globals ?? null) : null);
|
|
416
|
+
if (globals !== null) {
|
|
417
|
+
const coverageGlobal = globals[coverageGlobalName] ?? null;
|
|
418
|
+
if (coverageGlobal !== null) {
|
|
419
|
+
globals[coverageGlobalName].enabled = false;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
|
|
356
425
|
//
|
|
357
426
|
// Data functions
|
|
358
427
|
//
|
|
@@ -2079,6 +2148,7 @@ export const scriptFunctions = {
|
|
|
2079
2148
|
arrayCopy,
|
|
2080
2149
|
arrayDelete,
|
|
2081
2150
|
arrayExtend,
|
|
2151
|
+
arrayFlat,
|
|
2082
2152
|
arrayGet,
|
|
2083
2153
|
arrayIndexOf,
|
|
2084
2154
|
arrayJoin,
|
|
@@ -2092,6 +2162,10 @@ export const scriptFunctions = {
|
|
|
2092
2162
|
arrayShift,
|
|
2093
2163
|
arraySlice,
|
|
2094
2164
|
arraySort,
|
|
2165
|
+
coverageGlobalGet,
|
|
2166
|
+
'coverageGlobalName': coverageGlobalNameFn,
|
|
2167
|
+
coverageStart,
|
|
2168
|
+
coverageStop,
|
|
2095
2169
|
dataAggregate,
|
|
2096
2170
|
dataCalculatedField,
|
|
2097
2171
|
dataFilter,
|
|
@@ -2189,6 +2263,7 @@ export const scriptFunctions = {
|
|
|
2189
2263
|
export const expressionFunctionMap = {
|
|
2190
2264
|
'abs': 'mathAbs',
|
|
2191
2265
|
'acos': 'mathAcos',
|
|
2266
|
+
'arrayNew': 'arrayNew',
|
|
2192
2267
|
'asin': 'mathAsin',
|
|
2193
2268
|
'atan': 'mathAtan',
|
|
2194
2269
|
'atan2': 'mathAtan2',
|
|
@@ -2213,6 +2288,7 @@ export const expressionFunctionMap = {
|
|
|
2213
2288
|
'minute': 'datetimeMinute',
|
|
2214
2289
|
'month': 'datetimeMonth',
|
|
2215
2290
|
'now': 'datetimeNow',
|
|
2291
|
+
'objectNew': 'objectNew',
|
|
2216
2292
|
'parseInt': 'numberParseInt',
|
|
2217
2293
|
'parseFloat': 'numberParseFloat',
|
|
2218
2294
|
'pi': 'mathPi',
|