bare-script 3.8.2__py3-none-any.whl
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.
- bare_script/__init__.py +37 -0
- bare_script/__main__.py +12 -0
- bare_script/bare.py +165 -0
- bare_script/baredoc.py +177 -0
- bare_script/data.py +477 -0
- bare_script/include/__init__.py +0 -0
- bare_script/include/args.bare +340 -0
- bare_script/include/baredoc.bare +313 -0
- bare_script/include/dataLineChart.bare +90 -0
- bare_script/include/dataTable.bare +204 -0
- bare_script/include/diff.bare +148 -0
- bare_script/include/forms.bare +72 -0
- bare_script/include/markdownUp.bare +662 -0
- bare_script/include/pager.bare +301 -0
- bare_script/include/unittest.bare +529 -0
- bare_script/include/unittestMock.bare +456 -0
- bare_script/library.py +2273 -0
- bare_script/model.py +547 -0
- bare_script/options.py +119 -0
- bare_script/parser.py +859 -0
- bare_script/runtime.py +471 -0
- bare_script/value.py +530 -0
- bare_script-3.8.2.dist-info/METADATA +201 -0
- bare_script-3.8.2.dist-info/RECORD +28 -0
- bare_script-3.8.2.dist-info/WHEEL +5 -0
- bare_script-3.8.2.dist-info/entry_points.txt +3 -0
- bare_script-3.8.2.dist-info/licenses/LICENSE +21 -0
- bare_script-3.8.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
# Licensed under the MIT License
|
|
2
|
+
# https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
include <args.bare>
|
|
6
|
+
include <dataTable.bare>
|
|
7
|
+
include <diff.bare>
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# $function: unittestRunTest
|
|
11
|
+
# $group: unittest.bare
|
|
12
|
+
# $doc: Run a unit test
|
|
13
|
+
# $arg testName: The test function name
|
|
14
|
+
async function unittestRunTest(testName):
|
|
15
|
+
# Tests disabled?
|
|
16
|
+
if systemGlobalGet('vUnittestDisabled'):
|
|
17
|
+
return
|
|
18
|
+
endif
|
|
19
|
+
|
|
20
|
+
# Single test argument?
|
|
21
|
+
vUnittestTest = systemGlobalGet('vUnittestTest')
|
|
22
|
+
if vUnittestTest && vUnittestTest != testName:
|
|
23
|
+
return
|
|
24
|
+
endif
|
|
25
|
+
|
|
26
|
+
# Get the global unittest data
|
|
27
|
+
unittestData = unittestDataGet()
|
|
28
|
+
unittestTests = objectGet(unittestData, 'tests')
|
|
29
|
+
unittestWarnings = objectGet(unittestData, 'warnings')
|
|
30
|
+
|
|
31
|
+
# Test run multiple times?
|
|
32
|
+
if objectHas(unittestTests, testName):
|
|
33
|
+
arrayPush(unittestWarnings, 'Test "' + testName + '" run multiple times')
|
|
34
|
+
return
|
|
35
|
+
endif
|
|
36
|
+
|
|
37
|
+
# Get the test func
|
|
38
|
+
testFn = systemGlobalGet(testName)
|
|
39
|
+
if !testFn:
|
|
40
|
+
arrayPush(unittestWarnings, 'Test "' + testName + '" not found')
|
|
41
|
+
return
|
|
42
|
+
endif
|
|
43
|
+
|
|
44
|
+
# Add the unit test result array
|
|
45
|
+
testFailures = []
|
|
46
|
+
objectSet(unittestTests, testName, testFailures)
|
|
47
|
+
|
|
48
|
+
# Run the test
|
|
49
|
+
objectSet(unittestData, 'current', testName)
|
|
50
|
+
testFn()
|
|
51
|
+
objectSet(unittestData, 'current', null)
|
|
52
|
+
endfunction
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# For backward compatibility
|
|
56
|
+
async function unittestRunTestAsync(testName):
|
|
57
|
+
systemLogDebug('unittest.bare: unittestRunTestAsync is deprecated - use unittestRunTest')
|
|
58
|
+
return unittestRunTest(testName)
|
|
59
|
+
endfunction
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# $function: unittestEqual
|
|
63
|
+
# $group: unittest.bare
|
|
64
|
+
# $doc: Assert an actual value is equal to the expected value
|
|
65
|
+
# $arg actual: The actual value
|
|
66
|
+
# $arg expected: The expected value
|
|
67
|
+
# $arg description: The description of the assertion
|
|
68
|
+
function unittestEqual(actual, expected, description):
|
|
69
|
+
if actual == expected:
|
|
70
|
+
return
|
|
71
|
+
endif
|
|
72
|
+
|
|
73
|
+
# Get the global unittest data
|
|
74
|
+
unittestData = unittestDataGet()
|
|
75
|
+
unittestTests = objectGet(unittestData, 'tests')
|
|
76
|
+
unittestCurrent = objectGet(unittestData, 'current')
|
|
77
|
+
testFailures = objectGet(unittestTests, unittestCurrent)
|
|
78
|
+
|
|
79
|
+
# Add the test failure error lines
|
|
80
|
+
errorLines = [ \
|
|
81
|
+
'Equal:', \
|
|
82
|
+
'', \
|
|
83
|
+
'```', \
|
|
84
|
+
jsonStringify(actual), \
|
|
85
|
+
'```', \
|
|
86
|
+
'', \
|
|
87
|
+
'```', \
|
|
88
|
+
jsonStringify(expected), \
|
|
89
|
+
'```' \
|
|
90
|
+
]
|
|
91
|
+
if description:
|
|
92
|
+
arrayPush(testFailures, arrayExtend([markdownEscape(description), ''], errorLines))
|
|
93
|
+
else:
|
|
94
|
+
arrayPush(testFailures, errorLines)
|
|
95
|
+
endif
|
|
96
|
+
endfunction
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# $function: unittestDeepEqual
|
|
100
|
+
# $group: unittest.bare
|
|
101
|
+
# $doc: Assert an actual value is *deeply* equal to the expected value
|
|
102
|
+
# $arg actual: The actual value
|
|
103
|
+
# $arg expected: The expected value
|
|
104
|
+
# $arg description: The description of the assertion
|
|
105
|
+
function unittestDeepEqual(actual, expected, description):
|
|
106
|
+
# Serialize as JSON
|
|
107
|
+
actualJSON = if(systemType(actual) == 'string', actual, jsonStringify(actual, 4))
|
|
108
|
+
expectedJSON = if(systemType(expected) == 'string', expected, jsonStringify(expected, 4))
|
|
109
|
+
if actualJSON == expectedJSON:
|
|
110
|
+
return
|
|
111
|
+
endif
|
|
112
|
+
|
|
113
|
+
# Compute the difference lines
|
|
114
|
+
errorLines = []
|
|
115
|
+
diffErrorLines = []
|
|
116
|
+
for diff in diffLines(actualJSON, expectedJSON):
|
|
117
|
+
diffType = objectGet(diff, 'type')
|
|
118
|
+
if diffType == 'Remove':
|
|
119
|
+
for diffLine in objectGet(diff, 'lines'):
|
|
120
|
+
arrayPush(diffErrorLines, '--- ' + diffLine)
|
|
121
|
+
endfor
|
|
122
|
+
elif diffType == 'Add':
|
|
123
|
+
for diffLine in objectGet(diff, 'lines'):
|
|
124
|
+
arrayPush(diffErrorLines, '+++ ' + diffLine)
|
|
125
|
+
endfor
|
|
126
|
+
else:
|
|
127
|
+
# diffType == 'Identical'
|
|
128
|
+
if diffErrorLines:
|
|
129
|
+
arrayExtend(errorLines, ['Deep-equal:', '', '```'])
|
|
130
|
+
arrayExtend(errorLines, diffErrorLines)
|
|
131
|
+
arrayPush(errorLines, '```')
|
|
132
|
+
diffErrorLines = []
|
|
133
|
+
endif
|
|
134
|
+
endif
|
|
135
|
+
endfor
|
|
136
|
+
if diffErrorLines:
|
|
137
|
+
arrayExtend(errorLines, ['Deep-equal:', '', '```'])
|
|
138
|
+
arrayExtend(errorLines, diffErrorLines)
|
|
139
|
+
arrayPush(errorLines, '```')
|
|
140
|
+
endif
|
|
141
|
+
|
|
142
|
+
# Get the global unittest data
|
|
143
|
+
unittestData = unittestDataGet()
|
|
144
|
+
unittestTests = objectGet(unittestData, 'tests')
|
|
145
|
+
unittestCurrent = objectGet(unittestData, 'current')
|
|
146
|
+
testFailures = objectGet(unittestTests, unittestCurrent)
|
|
147
|
+
|
|
148
|
+
# Add the test failure error lines
|
|
149
|
+
if description:
|
|
150
|
+
arrayPush(testFailures, arrayExtend([markdownEscape(description), ''], errorLines))
|
|
151
|
+
else:
|
|
152
|
+
arrayPush(testFailures, errorLines)
|
|
153
|
+
endif
|
|
154
|
+
endfunction
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# Helper to get the global unittest data object
|
|
158
|
+
function unittestDataGet():
|
|
159
|
+
unittestData = systemGlobalGet('unittestData')
|
|
160
|
+
if unittestData == null:
|
|
161
|
+
unittestData = {'tests': {}, 'warnings': [], 'current': null}
|
|
162
|
+
systemGlobalSet('unittestData', unittestData)
|
|
163
|
+
endif
|
|
164
|
+
return unittestData
|
|
165
|
+
endfunction
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# $function: unittestReport
|
|
169
|
+
# $group: unittest.bare
|
|
170
|
+
# $doc: Render the unit test report
|
|
171
|
+
# $arg options: Optional unittest report options object. The following options are available:
|
|
172
|
+
# $arg options: - **coverageExclude** - array of script names to exclude from coverage
|
|
173
|
+
# $arg options: - **coverageMin** - verify minimum coverage percent (0 - 100)
|
|
174
|
+
# $arg options: - **links** - the array of page links
|
|
175
|
+
# $arg options: - **title** - the page title
|
|
176
|
+
# $return: The number of unit test failures
|
|
177
|
+
function unittestReport(options):
|
|
178
|
+
coverageMin = if(options, objectGet(options, 'coverageMin', 0), 0)
|
|
179
|
+
coverageExclude = if(options, objectGet(options, 'coverageExclude'))
|
|
180
|
+
links = if(options, objectGet(options, 'links'))
|
|
181
|
+
defaultTitle = 'unittestReport'
|
|
182
|
+
title = if(options, objectGet(options, 'title', defaultTitle), defaultTitle)
|
|
183
|
+
|
|
184
|
+
# Parse arguments
|
|
185
|
+
args = argsParse(unittestReportArguments)
|
|
186
|
+
isDisabled = objectGet(args, 'disabled')
|
|
187
|
+
hideTests = objectGet(args, 'hideTests')
|
|
188
|
+
isReport = objectGet(args, 'report')
|
|
189
|
+
scriptName = objectGet(args, 'script')
|
|
190
|
+
testNameArg = objectGet(args, 'test')
|
|
191
|
+
|
|
192
|
+
# Disabled?
|
|
193
|
+
if isDisabled:
|
|
194
|
+
return 0
|
|
195
|
+
endif
|
|
196
|
+
|
|
197
|
+
# Script coverage details page?
|
|
198
|
+
if scriptName:
|
|
199
|
+
unittestReportScript(scriptName)
|
|
200
|
+
return 0
|
|
201
|
+
endif
|
|
202
|
+
|
|
203
|
+
# Get the global unittest data
|
|
204
|
+
unittestData = unittestDataGet()
|
|
205
|
+
unittestTests = objectGet(unittestData, 'tests')
|
|
206
|
+
unittestWarnings = objectGet(unittestData, 'warnings')
|
|
207
|
+
|
|
208
|
+
# Compute test statistics
|
|
209
|
+
testNames = arraySort(objectKeys(unittestTests))
|
|
210
|
+
testCount = arrayLength(testNames)
|
|
211
|
+
testFailCount = 0
|
|
212
|
+
for testName in testNames:
|
|
213
|
+
testFailures = objectGet(unittestTests, testName)
|
|
214
|
+
if arrayLength(testFailures):
|
|
215
|
+
testFailCount = testFailCount + 1
|
|
216
|
+
endif
|
|
217
|
+
endfor
|
|
218
|
+
testPassCount = testCount - testFailCount
|
|
219
|
+
|
|
220
|
+
# Render the links
|
|
221
|
+
if !isReport && links:
|
|
222
|
+
markdownPrint(arrayJoin(links, ' | '))
|
|
223
|
+
endif
|
|
224
|
+
|
|
225
|
+
# Render the page title
|
|
226
|
+
documentSetTitle(title)
|
|
227
|
+
markdownPrint( \
|
|
228
|
+
'# ' + markdownEscape(title), \
|
|
229
|
+
'', \
|
|
230
|
+
'Ran ' + testCount + ' tests - ' + testPassCount + ' passed, ' + testFailCount + ' failed' \
|
|
231
|
+
)
|
|
232
|
+
if !isReport:
|
|
233
|
+
if testNameArg:
|
|
234
|
+
markdownPrint('', argsLink(unittestReportArguments, 'All tests', null, true))
|
|
235
|
+
else:
|
|
236
|
+
markdownPrint('', argsLink(unittestReportArguments, if(hideTests, 'Show', 'Hide') + ' tests', {'hideTests': !hideTests}))
|
|
237
|
+
endif
|
|
238
|
+
endif
|
|
239
|
+
|
|
240
|
+
# Report any warnings
|
|
241
|
+
testWarningCount = arrayLength(unittestWarnings)
|
|
242
|
+
if testWarningCount:
|
|
243
|
+
markdownPrint('', '## Warnings')
|
|
244
|
+
for warning in unittestWarnings:
|
|
245
|
+
markdownPrint('', '- ' + markdownEscape(warning))
|
|
246
|
+
endfor
|
|
247
|
+
endif
|
|
248
|
+
|
|
249
|
+
# Report the failing tests
|
|
250
|
+
if testFailCount:
|
|
251
|
+
markdownPrint('', '## Failing Tests')
|
|
252
|
+
if hideTests && !isReport && !testNameArg:
|
|
253
|
+
markdownPrint('', argsLink(unittestReportArguments, 'Show', {'hideTests': false}))
|
|
254
|
+
endif
|
|
255
|
+
if !hideTests || testNameArg:
|
|
256
|
+
for testName in testNames:
|
|
257
|
+
testFailures = objectGet(unittestTests, testName)
|
|
258
|
+
if arrayLength(testFailures):
|
|
259
|
+
failureLink = if(isReport, testName, \
|
|
260
|
+
argsLink(unittestReportArguments, testName, {'test': testName}, false, '_top'))
|
|
261
|
+
failureLines = ['', failureLink + ' - FAIL']
|
|
262
|
+
for errorLines in testFailures:
|
|
263
|
+
for errorLine, ixErrorLine in errorLines:
|
|
264
|
+
if ixErrorLine == 0:
|
|
265
|
+
arrayPush(failureLines, '')
|
|
266
|
+
arrayPush(failureLines, '- ' + errorLine)
|
|
267
|
+
else:
|
|
268
|
+
arrayPush(failureLines, if(errorLine, ' ' + errorLine, ''))
|
|
269
|
+
endif
|
|
270
|
+
endfor
|
|
271
|
+
endfor
|
|
272
|
+
markdownPrint(failureLines)
|
|
273
|
+
endif
|
|
274
|
+
endfor
|
|
275
|
+
endif
|
|
276
|
+
endif
|
|
277
|
+
|
|
278
|
+
# Report the passing tests
|
|
279
|
+
if testPassCount:
|
|
280
|
+
markdownPrint('', '## Passing Tests')
|
|
281
|
+
if hideTests && !isReport && !testNameArg:
|
|
282
|
+
markdownPrint('', argsLink(unittestReportArguments, 'Show', {'hideTests': false}))
|
|
283
|
+
endif
|
|
284
|
+
if !hideTests || testNameArg:
|
|
285
|
+
for testName in testNames:
|
|
286
|
+
testFailures = objectGet(unittestTests, testName)
|
|
287
|
+
if !arrayLength(testFailures):
|
|
288
|
+
testLink = if(isReport, testName, \
|
|
289
|
+
argsLink(unittestReportArguments, testName, {'test': testName}, false, '_top'))
|
|
290
|
+
markdownPrint('', testLink + ' - OK')
|
|
291
|
+
endif
|
|
292
|
+
endfor
|
|
293
|
+
endif
|
|
294
|
+
endif
|
|
295
|
+
|
|
296
|
+
# Coverage report
|
|
297
|
+
coverage = coverageGlobalGet()
|
|
298
|
+
coverageFailCount = 0
|
|
299
|
+
if !testNameArg && coverage:
|
|
300
|
+
markdownPrint('', '## Coverage Report')
|
|
301
|
+
|
|
302
|
+
# Compute the coverage data table
|
|
303
|
+
coverageData = unittestCoverageData(coverageExclude)
|
|
304
|
+
if coverageData:
|
|
305
|
+
# Verify the coverage percent
|
|
306
|
+
coveragePercent = objectGet(arrayGet(coverageData, arrayLength(coverageData) - 1), 'Coverage')
|
|
307
|
+
if coveragePercent < coverageMin:
|
|
308
|
+
markdownPrint( \
|
|
309
|
+
'', \
|
|
310
|
+
'**Error**: Coverage percentage, ' + numberToFixed(coveragePercent, 1, true) + \
|
|
311
|
+
'%, is below the minimum coverage percentage of ' + numberToFixed(coverageMin, 1, true) + '%.' \
|
|
312
|
+
)
|
|
313
|
+
coverageFailCount = coverageFailCount + 1
|
|
314
|
+
endif
|
|
315
|
+
|
|
316
|
+
# Render the coverage data table
|
|
317
|
+
for row in coverageData:
|
|
318
|
+
scriptName = objectGet(row, 'Script')
|
|
319
|
+
if !isReport && !stringStartsWith(scriptName, '**'):
|
|
320
|
+
objectSet(row, 'Script', argsLink(unittestReportArguments, scriptName, {"script": scriptName}, false, "_top"))
|
|
321
|
+
endif
|
|
322
|
+
objectSet(row, 'Coverage', numberToFixed(objectGet(row, 'Coverage'), 1) + '%')
|
|
323
|
+
endfor
|
|
324
|
+
markdownPrint('', dataTableMarkdown(coverageData, { \
|
|
325
|
+
'fields': ['Script', 'Statements', 'Missing', 'Coverage'], \
|
|
326
|
+
'formats': { \
|
|
327
|
+
'Statements': {'align': 'right'}, \
|
|
328
|
+
'Missing': {'align': 'right'}, \
|
|
329
|
+
'Coverage': {'align': 'right'} \
|
|
330
|
+
} \
|
|
331
|
+
}))
|
|
332
|
+
else:
|
|
333
|
+
markdownPrint('', '*No data.*')
|
|
334
|
+
endif
|
|
335
|
+
endif
|
|
336
|
+
|
|
337
|
+
# Return status code
|
|
338
|
+
return testWarningCount + testFailCount + coverageFailCount
|
|
339
|
+
endfunction
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
# unittestReport application arguments
|
|
343
|
+
unittestReportArguments = argsValidate([ \
|
|
344
|
+
{'name': 'disabled', 'global': 'vUnittestDisabled', 'type': 'bool', 'default': false}, \
|
|
345
|
+
{'name': 'hideTests', 'global': 'vUnittestHideTests', 'type': 'bool', 'default': false}, \
|
|
346
|
+
{'name': 'report', 'global': 'vUnittestReport', 'type': 'bool', 'default': false}, \
|
|
347
|
+
{'name': 'script', 'global': 'vUnittestScript'}, \
|
|
348
|
+
{'name': 'test', 'global': 'vUnittestTest'} \
|
|
349
|
+
])
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
# Render the script coverage details page
|
|
353
|
+
function unittestReportScript(scriptName):
|
|
354
|
+
# Render the script coverage page title
|
|
355
|
+
title = scriptName + ' Coverage'
|
|
356
|
+
documentSetTitle(title)
|
|
357
|
+
markdownPrint( \
|
|
358
|
+
argsLink(unittestReportArguments, 'Back', {'script': null}, false, '_top'), \
|
|
359
|
+
'', \
|
|
360
|
+
'# ' + markdownEscape(title) \
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
# Get the script coverage data
|
|
364
|
+
coverage = coverageGlobalGet()
|
|
365
|
+
scripts = if(coverage, objectGet(coverage, 'scripts'))
|
|
366
|
+
coverageScript = if(scripts, objectGet(scripts, scriptName))
|
|
367
|
+
if !coverageScript:
|
|
368
|
+
markdownPrint('', '*No data.*')
|
|
369
|
+
return
|
|
370
|
+
endif
|
|
371
|
+
script = objectGet(coverageScript, 'script')
|
|
372
|
+
covered = objectGet(coverageScript, 'covered')
|
|
373
|
+
scriptLines = objectGet(script, 'scriptLines')
|
|
374
|
+
|
|
375
|
+
# Mark the statements covered or not-covered
|
|
376
|
+
lineColors = {}
|
|
377
|
+
statements = unittestScriptStatements(script)
|
|
378
|
+
for statement in statements:
|
|
379
|
+
statementKey = arrayGet(objectKeys(statement), 0)
|
|
380
|
+
lineNumber = objectGet(objectGet(statement, statementKey), 'lineNumber')
|
|
381
|
+
lineCount = objectGet(objectGet(statement, statementKey), 'lineCount', 1)
|
|
382
|
+
lineStr = stringNew(lineNumber)
|
|
383
|
+
lineColor = if(objectHas(covered, lineStr), '#a0a0a030', '#f0808080')
|
|
384
|
+
objectSet(lineColors, lineStr, lineColor)
|
|
385
|
+
if lineCount > 1:
|
|
386
|
+
lineNumberEnd = lineNumber + lineCount
|
|
387
|
+
lineNumber = lineNumber + 1
|
|
388
|
+
while lineNumber < lineNumberEnd:
|
|
389
|
+
objectSet(lineColors, stringNew(lineNumber), lineColor)
|
|
390
|
+
lineNumber = lineNumber + 1
|
|
391
|
+
endwhile
|
|
392
|
+
endif
|
|
393
|
+
endfor
|
|
394
|
+
|
|
395
|
+
# Generate the code coverage details
|
|
396
|
+
codeLineElements = []
|
|
397
|
+
codeElements = {'html': 'pre', 'elem': codeLineElements}
|
|
398
|
+
currentLines = []
|
|
399
|
+
currentColor = null
|
|
400
|
+
for line, ixLine in scriptLines:
|
|
401
|
+
# Accumulate lines of the same color
|
|
402
|
+
lineColor = objectGet(lineColors, stringNew(ixLine + 1))
|
|
403
|
+
if lineColor == currentColor:
|
|
404
|
+
arrayPush(currentLines, line)
|
|
405
|
+
continue
|
|
406
|
+
endif
|
|
407
|
+
|
|
408
|
+
# Render the current lines
|
|
409
|
+
unittestReportScriptLines(codeLineElements, currentLines, currentColor)
|
|
410
|
+
currentLines = [line]
|
|
411
|
+
currentColor = lineColor
|
|
412
|
+
endfor
|
|
413
|
+
unittestReportScriptLines(codeLineElements, currentLines, currentColor, true)
|
|
414
|
+
elementModelRender(codeElements)
|
|
415
|
+
endfunction
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
function unittestReportScriptLines(codeLineElements, lines, color, noNewline):
|
|
419
|
+
if lines:
|
|
420
|
+
linesStr = arrayJoin(lines, '\n') + if(noNewline, '', '\n')
|
|
421
|
+
if !color:
|
|
422
|
+
arrayPush(codeLineElements, {'text': linesStr})
|
|
423
|
+
else:
|
|
424
|
+
arrayPush(codeLineElements, { \
|
|
425
|
+
'html': 'span', \
|
|
426
|
+
'attr': {'style': 'display: block; background-color: ' + color}, \
|
|
427
|
+
'elem': {'text': linesStr} \
|
|
428
|
+
})
|
|
429
|
+
endif
|
|
430
|
+
endif
|
|
431
|
+
endfunction
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
# Get the coverage data table - columns are "Script", "Statement", "Covered", and "Percent"
|
|
435
|
+
function unittestCoverageData(coverageExclude):
|
|
436
|
+
data = []
|
|
437
|
+
|
|
438
|
+
# Get the global coverage object
|
|
439
|
+
coverage = coverageGlobalGet()
|
|
440
|
+
if coverage:
|
|
441
|
+
# Get the script names with coverage data
|
|
442
|
+
scripts = objectGet(coverage, 'scripts')
|
|
443
|
+
scriptNames = if(scripts, arraySort(objectKeys(scripts)), [])
|
|
444
|
+
|
|
445
|
+
# Compute script statement coverage
|
|
446
|
+
totalStatements = 0
|
|
447
|
+
totalMissing = 0
|
|
448
|
+
for scriptName in scriptNames:
|
|
449
|
+
# Excluded?
|
|
450
|
+
if coverageExclude:
|
|
451
|
+
isExcluded = false
|
|
452
|
+
for excludeScriptName in coverageExclude:
|
|
453
|
+
if stringEndsWith(scriptName, excludeScriptName):
|
|
454
|
+
isExcluded = true
|
|
455
|
+
break
|
|
456
|
+
endif
|
|
457
|
+
endfor
|
|
458
|
+
if isExcluded:
|
|
459
|
+
continue
|
|
460
|
+
endif
|
|
461
|
+
endif
|
|
462
|
+
|
|
463
|
+
# Get the script members
|
|
464
|
+
coverageScript = objectGet(scripts, scriptName)
|
|
465
|
+
script = objectGet(coverageScript, 'script')
|
|
466
|
+
covered = objectGet(coverageScript, 'covered')
|
|
467
|
+
statements = unittestScriptStatements(script)
|
|
468
|
+
statementCount = arrayLength(statements)
|
|
469
|
+
|
|
470
|
+
# Count statements with coverage
|
|
471
|
+
missingCount = 0
|
|
472
|
+
for statement in statements:
|
|
473
|
+
statementKey = arrayGet(objectKeys(statement), 0)
|
|
474
|
+
lineNumber = objectGet(objectGet(statement, statementKey), 'lineNumber')
|
|
475
|
+
lineStr = stringNew(lineNumber)
|
|
476
|
+
if !objectHas(covered, lineStr):
|
|
477
|
+
missingCount = missingCount + 1
|
|
478
|
+
totalMissing = totalMissing + 1
|
|
479
|
+
endif
|
|
480
|
+
totalStatements = totalStatements + 1
|
|
481
|
+
endfor
|
|
482
|
+
|
|
483
|
+
# Add the script coverage data row
|
|
484
|
+
coveragePercent = if(statementCount, 100 * (statementCount - missingCount) / statementCount, 100)
|
|
485
|
+
arrayPush(data, { \
|
|
486
|
+
'Script': scriptName, \
|
|
487
|
+
'Statements': statementCount, \
|
|
488
|
+
'Missing': missingCount, \
|
|
489
|
+
'Coverage': coveragePercent, \
|
|
490
|
+
'CoverageStr': numberToFixed(coveragePercent, 1) + '%' \
|
|
491
|
+
})
|
|
492
|
+
endfor
|
|
493
|
+
|
|
494
|
+
# Add the coverage totals data row
|
|
495
|
+
if scriptNames:
|
|
496
|
+
coveragePercent = if(totalStatements, 100 * (totalStatements - totalMissing) / totalStatements, 100)
|
|
497
|
+
arrayPush(data, { \
|
|
498
|
+
'Script': '**Total**', \
|
|
499
|
+
'Statements': totalStatements, \
|
|
500
|
+
'Missing': totalMissing, \
|
|
501
|
+
'Coverage': coveragePercent, \
|
|
502
|
+
'CoverageStr': numberToFixed(coveragePercent, 1) + '%' \
|
|
503
|
+
})
|
|
504
|
+
endif
|
|
505
|
+
endif
|
|
506
|
+
|
|
507
|
+
return data
|
|
508
|
+
endfunction
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
# Get a script's array of statements
|
|
512
|
+
function unittestScriptStatements(script):
|
|
513
|
+
statements = []
|
|
514
|
+
|
|
515
|
+
# Add the top-level script statements
|
|
516
|
+
for statement in objectGet(script, 'statements'):
|
|
517
|
+
arrayPush(statements, statement)
|
|
518
|
+
|
|
519
|
+
# Add function statements
|
|
520
|
+
statementKey = arrayGet(objectKeys(statement), 0)
|
|
521
|
+
if statementKey == 'function':
|
|
522
|
+
for funcStatement in objectGet(objectGet(statement, statementKey), 'statements'):
|
|
523
|
+
arrayPush(statements, funcStatement)
|
|
524
|
+
endfor
|
|
525
|
+
endif
|
|
526
|
+
endfor
|
|
527
|
+
|
|
528
|
+
return statements
|
|
529
|
+
endfunction
|