bare-script 3.2.2 → 3.3.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/lib/include/args.bare +344 -0
- package/lib/include/args.mds +2 -334
- package/lib/include/diff.bare +155 -0
- package/lib/include/forms.bare +79 -0
- package/lib/include/forms.mds +2 -69
- package/lib/include/pager.bare +236 -0
- package/lib/include/pager.mds +2 -225
- package/lib/include/unittest.bare +229 -0
- package/lib/include/unittest.mds +2 -181
- package/lib/include/unittestMock.bare +462 -0
- package/lib/include/unittestMock.mds +2 -452
- package/lib/value.js +1 -3
- package/package.json +1 -1
package/lib/include/pager.mds
CHANGED
|
@@ -1,235 +1,12 @@
|
|
|
1
1
|
# Licensed under the MIT License
|
|
2
2
|
# https://github.com/craigahobbs/markdown-up/blob/main/LICENSE
|
|
3
3
|
|
|
4
|
-
include <args.mds>
|
|
5
|
-
|
|
6
4
|
|
|
7
5
|
# Include sentinel
|
|
8
6
|
if systemGlobalGet('pagerSentinel'):
|
|
9
7
|
return
|
|
10
8
|
endif
|
|
11
|
-
pagerSentinel = true
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# The pager model
|
|
15
|
-
pagerTypes = schemaParse( \
|
|
16
|
-
'group "Pager"', \
|
|
17
|
-
'', \
|
|
18
|
-
'', \
|
|
19
|
-
'# A pager application model', \
|
|
20
|
-
'struct Pager', \
|
|
21
|
-
'', \
|
|
22
|
-
" # The application's pages", \
|
|
23
|
-
' PagerPage[len > 0] pages', \
|
|
24
|
-
'', \
|
|
25
|
-
'', \
|
|
26
|
-
'# A page model', \
|
|
27
|
-
'struct PagerPage', \
|
|
28
|
-
'', \
|
|
29
|
-
' # The page name', \
|
|
30
|
-
' string name', \
|
|
31
|
-
'', \
|
|
32
|
-
' # If true, the page is hidden', \
|
|
33
|
-
' optional bool hidden', \
|
|
34
|
-
'', \
|
|
35
|
-
' # The page type', \
|
|
36
|
-
' PagerPageType type', \
|
|
37
|
-
'', \
|
|
38
|
-
'', \
|
|
39
|
-
'# The page type', \
|
|
40
|
-
'union PagerPageType', \
|
|
41
|
-
'', \
|
|
42
|
-
' # A function page', \
|
|
43
|
-
' PagerPageFunction function', \
|
|
44
|
-
'', \
|
|
45
|
-
' # A markdown resource page', \
|
|
46
|
-
' PagerPageMarkdown markdown', \
|
|
47
|
-
'', \
|
|
48
|
-
' # A navigation link', \
|
|
49
|
-
' PagerPageLink link', \
|
|
50
|
-
'', \
|
|
51
|
-
'', \
|
|
52
|
-
'# A page function', \
|
|
53
|
-
'struct PagerPageFunction', \
|
|
54
|
-
'', \
|
|
55
|
-
' # The page function', \
|
|
56
|
-
' object function', \
|
|
57
|
-
'', \
|
|
58
|
-
' # The page title', \
|
|
59
|
-
' optional string title', \
|
|
60
|
-
'', \
|
|
61
|
-
'', \
|
|
62
|
-
'# A Markdown resource page', \
|
|
63
|
-
'struct PagerPageMarkdown', \
|
|
64
|
-
'', \
|
|
65
|
-
' # The Markdown resource URL', \
|
|
66
|
-
' string url', \
|
|
67
|
-
'', \
|
|
68
|
-
'', \
|
|
69
|
-
'# A page link', \
|
|
70
|
-
'struct PagerPageLink', \
|
|
71
|
-
'', \
|
|
72
|
-
' # The link URL', \
|
|
73
|
-
' string url' \
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# $function: pagerValidate
|
|
78
|
-
# $group: pager.mds
|
|
79
|
-
# $doc: Validate a pager model
|
|
80
|
-
# $arg pagerModel: The [pager model](includeModel.html#var.vName='Pager')
|
|
81
|
-
# $return: The validated [pager model](includeModel.html#var.vName='Pager') or null if validation fails
|
|
82
|
-
function pagerValidate(pagerModel):
|
|
83
|
-
return schemaValidate(pagerTypes, 'Pager', pagerModel)
|
|
84
|
-
endfunction
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# $function: pagerMain
|
|
88
|
-
# $group: pager.mds
|
|
89
|
-
# $doc: The pager application main entry point
|
|
90
|
-
# $arg pagerModel: The [pager model](includeModel.html#var.vName='Pager')
|
|
91
|
-
# $arg options: The pager application options. The following options are available:
|
|
92
|
-
# $arg options: - **arguments** - The [arguments model](includeModel.html#var.vName='ArgsArguments').
|
|
93
|
-
# $arg options: Must contain a string argument named "page".
|
|
94
|
-
# $arg options: - **hideMenu** - Hide the menu links
|
|
95
|
-
# $arg options: - **hideNav** - Hide the navigation links
|
|
96
|
-
# $arg options: - **start** - The start page name
|
|
97
|
-
async function pagerMain(pagerModel, options):
|
|
98
|
-
if options == null:
|
|
99
|
-
options = objectNew()
|
|
100
|
-
endif
|
|
101
|
-
|
|
102
|
-
# Validate the pager model
|
|
103
|
-
pagerModel = pagerValidate(pagerModel)
|
|
104
|
-
if pagerModel == null:
|
|
105
|
-
return
|
|
106
|
-
endif
|
|
107
|
-
|
|
108
|
-
# Compute the visible and navigable pages
|
|
109
|
-
pages = objectGet(pagerModel, 'pages')
|
|
110
|
-
visiblePages = arrayNew()
|
|
111
|
-
navPages = arrayNew()
|
|
112
|
-
for page in pages:
|
|
113
|
-
# Visible page?
|
|
114
|
-
if !objectGet(page, 'hidden'):
|
|
115
|
-
arrayPush(visiblePages, page)
|
|
116
|
-
|
|
117
|
-
# Navigable page?
|
|
118
|
-
pageTypeKey = arrayGet(objectKeys(objectGet(page, 'type')), 0)
|
|
119
|
-
if pageTypeKey != 'link':
|
|
120
|
-
arrayPush(navPages, page)
|
|
121
|
-
endif
|
|
122
|
-
endif
|
|
123
|
-
endfor
|
|
124
|
-
|
|
125
|
-
# Parse arguments
|
|
126
|
-
startPageName = objectGet(options, 'start', if(arrayLength(navPages), objectGet(arrayGet(navPages, 0), 'name'), null))
|
|
127
|
-
if objectHas(options, 'arguments'):
|
|
128
|
-
arguments = argsValidate(objectGet(options, 'arguments'))
|
|
129
|
-
if arguments == null:
|
|
130
|
-
return
|
|
131
|
-
endif
|
|
132
|
-
else:
|
|
133
|
-
arguments = arrayNew(objectNew('name', 'page', 'default', startPageName))
|
|
134
|
-
endif
|
|
135
|
-
args = argsParse(arguments)
|
|
136
|
-
|
|
137
|
-
# Determine the current page
|
|
138
|
-
curPage = null
|
|
139
|
-
startPage = null
|
|
140
|
-
for page in pages:
|
|
141
|
-
if objectGet(page, 'name') == objectGet(args, 'page'):
|
|
142
|
-
curPage = page
|
|
143
|
-
endif
|
|
144
|
-
if objectGet(page, 'name') == startPageName:
|
|
145
|
-
startPage = page
|
|
146
|
-
endif
|
|
147
|
-
endfor
|
|
148
|
-
if startPage == null:
|
|
149
|
-
systemLogDebug('MarkdownUp - pager.mds: Unknown start page' + if(startPageName != null, '"' + startPageName + '"', ''))
|
|
150
|
-
return
|
|
151
|
-
endif
|
|
152
|
-
if curPage == null:
|
|
153
|
-
curPage = startPage
|
|
154
|
-
endif
|
|
155
|
-
|
|
156
|
-
# Determine the current page's navigable index, if any
|
|
157
|
-
ixCurPage = -1
|
|
158
|
-
for navPage, ixNavPage in navPages:
|
|
159
|
-
if objectGet(navPage, 'name') == objectGet(curPage, 'name'):
|
|
160
|
-
ixCurPage = ixNavPage
|
|
161
|
-
break
|
|
162
|
-
endif
|
|
163
|
-
endfor
|
|
164
|
-
|
|
165
|
-
# Render the menu
|
|
166
|
-
if !objectGet(options, 'hideMenu'):
|
|
167
|
-
for page, ixPage in visiblePages:
|
|
168
|
-
pageName = objectGet(page, 'name')
|
|
169
|
-
pageType = objectGet(page, 'type')
|
|
170
|
-
pageTypeKey = arrayGet(objectKeys(pageType), 0)
|
|
171
|
-
|
|
172
|
-
# Render the menu link
|
|
173
|
-
pageNameNbsp = stringReplace(pageName, ' ', ' ')
|
|
174
|
-
separator = if(ixPage != arrayLength(visiblePages) - 1, ' |', '')
|
|
175
|
-
if pageTypeKey == 'link':
|
|
176
|
-
pageLinkURL = objectGet(objectGet(pageType, 'link'), 'url')
|
|
177
|
-
markdownPrint('[' + markdownEscape(pageNameNbsp) + '](' + urlEncode(pageLinkURL) + ')' + separator)
|
|
178
|
-
elif pageName == objectGet(curPage, 'name'):
|
|
179
|
-
markdownPrint(markdownEscape(pageNameNbsp) + separator)
|
|
180
|
-
else:
|
|
181
|
-
markdownPrint(argsLink(arguments, pageNameNbsp, objectNew('page', pageName)) + separator)
|
|
182
|
-
endif
|
|
183
|
-
endfor
|
|
184
|
-
markdownPrint('')
|
|
185
|
-
endif
|
|
186
|
-
|
|
187
|
-
# Render the start/next/prev buttons
|
|
188
|
-
if !objectGet(options, 'hideNav') && arrayLength(navPages) > 1 && ixCurPage != -1:
|
|
189
|
-
if startPageName == objectGet(curPage, 'name'):
|
|
190
|
-
startPageName = null
|
|
191
|
-
endif
|
|
192
|
-
prevPageName = if(ixCurPage != -1 && ixCurPage - 1 >= 0, objectGet(arrayGet(navPages, ixCurPage - 1), 'name'), null)
|
|
193
|
-
nextPageName = if(ixCurPage != -1 && ixCurPage + 1 < arrayLength(navPages), objectGet(arrayGet(navPages, ixCurPage + 1), 'name'), null)
|
|
194
|
-
markdownPrint( \
|
|
195
|
-
'( ' + if(startPageName != null, argsLink(arguments, 'Start', objectNew('page', startPageName)), 'Start') + ' |', \
|
|
196
|
-
if(prevPageName != null, argsLink(arguments, 'Previous', objectNew('page', prevPageName)), 'Previous') + ' |', \
|
|
197
|
-
if(nextPageName != null, argsLink(arguments, 'Next', objectNew('page', nextPageName)), 'Next') + ' )', \
|
|
198
|
-
'' \
|
|
199
|
-
)
|
|
200
|
-
endif
|
|
201
|
-
|
|
202
|
-
# Function page?
|
|
203
|
-
curPageType = objectGet(curPage, 'type')
|
|
204
|
-
curPageTypeKey = arrayGet(objectKeys(curPageType), 0)
|
|
205
|
-
if curPageTypeKey == 'function':
|
|
206
|
-
# Set the title
|
|
207
|
-
title = objectGet(objectGet(curPageType, 'function'), 'title')
|
|
208
|
-
if title != null:
|
|
209
|
-
documentSetTitle(title)
|
|
210
|
-
markdownPrint('# ' + markdownEscape(title), '')
|
|
211
|
-
endif
|
|
212
9
|
|
|
213
|
-
# Call the page function
|
|
214
|
-
pageFn = objectGet(objectGet(curPageType, 'function'), 'function')
|
|
215
|
-
pageFn(args)
|
|
216
|
-
elif curPageTypeKey == 'markdown':
|
|
217
|
-
# Fetch the Markdown text
|
|
218
|
-
url = objectGet(objectGet(curPageType, 'markdown'), 'url')
|
|
219
|
-
markdownText = systemFetch(url)
|
|
220
|
-
if markdownText == null:
|
|
221
|
-
markdownPrint('**Error:** Failed to load "' + url + '"')
|
|
222
|
-
else:
|
|
223
|
-
# Compute and set the page title
|
|
224
|
-
markdownModel = markdownParse(markdownText)
|
|
225
|
-
title = markdownTitle(markdownModel)
|
|
226
|
-
if title == null:
|
|
227
|
-
title = 'No Title'
|
|
228
|
-
endif
|
|
229
|
-
documentSetTitle(title)
|
|
230
10
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
endif
|
|
234
|
-
endif
|
|
235
|
-
endfunction
|
|
11
|
+
systemLog('MarkdownUp - pager.mds: pager.mds is now pager.bare - please update before 2025-06-01')
|
|
12
|
+
include 'pager.bare'
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Licensed under the MIT License
|
|
2
|
+
# https://github.com/craigahobbs/markdown-up/blob/main/LICENSE
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# Include sentinel
|
|
6
|
+
if systemGlobalGet('unittestSentinel'):
|
|
7
|
+
return
|
|
8
|
+
endif
|
|
9
|
+
unittestSentinel = true
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
include 'diff.bare'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Test statistics
|
|
16
|
+
unittestTests = objectNew()
|
|
17
|
+
unittestWarnings = arrayNew()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# $function: unittestRunTest
|
|
21
|
+
# $group: unittest.bare
|
|
22
|
+
# $doc: Run a unit test
|
|
23
|
+
# $arg testName: The test function name
|
|
24
|
+
function unittestRunTest(testName):
|
|
25
|
+
testFn = unittestRunTestHelper(testName)
|
|
26
|
+
if testFn:
|
|
27
|
+
testFn()
|
|
28
|
+
systemGlobalSet('unittestTestName', null)
|
|
29
|
+
endif
|
|
30
|
+
endfunction
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# $function: unittestRunTestAsync
|
|
34
|
+
# $group: unittest.bare
|
|
35
|
+
# $doc: Run an asyncronous unit test
|
|
36
|
+
# $arg testName: The test function name
|
|
37
|
+
async function unittestRunTestAsync(testName):
|
|
38
|
+
testFn = unittestRunTestHelper(testName)
|
|
39
|
+
if testFn:
|
|
40
|
+
testFn()
|
|
41
|
+
systemGlobalSet('unittestTestName', null)
|
|
42
|
+
endif
|
|
43
|
+
endfunction
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# unittestRunTest helper function
|
|
47
|
+
function unittestRunTestHelper(testName):
|
|
48
|
+
# Single test argument?
|
|
49
|
+
if vTest != null && vTest != testName:
|
|
50
|
+
return null
|
|
51
|
+
endif
|
|
52
|
+
|
|
53
|
+
# Test run multiple times?
|
|
54
|
+
if objectHas(unittestTests, testName):
|
|
55
|
+
arrayPush(unittestWarnings, 'Test "' + testName + '" run multiple times')
|
|
56
|
+
return null
|
|
57
|
+
endif
|
|
58
|
+
|
|
59
|
+
# Get the test func
|
|
60
|
+
testFn = systemGlobalGet(testName)
|
|
61
|
+
if testFn == null:
|
|
62
|
+
arrayPush(unittestWarnings, 'Test "' + testName + '" not found')
|
|
63
|
+
return null
|
|
64
|
+
endif
|
|
65
|
+
|
|
66
|
+
# Add the unit test result array
|
|
67
|
+
testFailures = arrayNew()
|
|
68
|
+
objectSet(unittestTests, testName, testFailures)
|
|
69
|
+
systemGlobalSet('unittestTestName', testName)
|
|
70
|
+
|
|
71
|
+
return testFn
|
|
72
|
+
endfunction
|
|
73
|
+
|
|
74
|
+
|
|
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
|
+
# $function: unittestEqual
|
|
148
|
+
# $group: unittest.bare
|
|
149
|
+
# $doc: Assert an actual value is equal to the expected value
|
|
150
|
+
# $arg actual: The actual value
|
|
151
|
+
# $arg expected: The expected value
|
|
152
|
+
# $arg description: The description of the assertion
|
|
153
|
+
function unittestEqual(actual, expected, description):
|
|
154
|
+
if actual == expected:
|
|
155
|
+
return
|
|
156
|
+
endif
|
|
157
|
+
|
|
158
|
+
# Add the test failure error lines
|
|
159
|
+
testFailures = objectGet(unittestTests, unittestTestName)
|
|
160
|
+
errorLines = arrayNew( \
|
|
161
|
+
'Equal:', \
|
|
162
|
+
'', \
|
|
163
|
+
'```', \
|
|
164
|
+
jsonStringify(actual), \
|
|
165
|
+
'```', \
|
|
166
|
+
'', \
|
|
167
|
+
'```', \
|
|
168
|
+
jsonStringify(expected), \
|
|
169
|
+
'```' \
|
|
170
|
+
)
|
|
171
|
+
if description != null:
|
|
172
|
+
arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), errorLines)))
|
|
173
|
+
else:
|
|
174
|
+
arrayPush(testFailures, errorLines)
|
|
175
|
+
endif
|
|
176
|
+
endfunction
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# $function: unittestDeepEqual
|
|
180
|
+
# $group: unittest.bare
|
|
181
|
+
# $doc: Assert an actual value is *deeply* equal to the expected value
|
|
182
|
+
# $arg actual: The actual value
|
|
183
|
+
# $arg expected: The expected value
|
|
184
|
+
# $arg description: The description of the assertion
|
|
185
|
+
function unittestDeepEqual(actual, expected, description):
|
|
186
|
+
# Serialize as JSON
|
|
187
|
+
actualJSON = if(systemType(actual) == 'string', actual, jsonStringify(actual, 4))
|
|
188
|
+
expectedJSON = if(systemType(expected) == 'string', expected, jsonStringify(expected, 4))
|
|
189
|
+
if actualJSON == expectedJSON:
|
|
190
|
+
return
|
|
191
|
+
endif
|
|
192
|
+
|
|
193
|
+
# Compute the difference lines
|
|
194
|
+
errorLines = arrayNew()
|
|
195
|
+
diffErrorLines = arrayNew()
|
|
196
|
+
for diff in diffLines(actualJSON, expectedJSON):
|
|
197
|
+
diffType = objectGet(diff, 'type')
|
|
198
|
+
if diffType == 'Remove':
|
|
199
|
+
for diffLine in objectGet(diff, 'lines'):
|
|
200
|
+
arrayPush(diffErrorLines, '--- ' + diffLine)
|
|
201
|
+
endfor
|
|
202
|
+
elif diffType == 'Add':
|
|
203
|
+
for diffLine in objectGet(diff, 'lines'):
|
|
204
|
+
arrayPush(diffErrorLines, '+++ ' + diffLine)
|
|
205
|
+
endfor
|
|
206
|
+
else:
|
|
207
|
+
# diffType == 'Identical'
|
|
208
|
+
if diffErrorLines:
|
|
209
|
+
arrayExtend(errorLines, arrayNew('Deep-equal:', '', '```'))
|
|
210
|
+
arrayExtend(errorLines, diffErrorLines)
|
|
211
|
+
arrayPush(errorLines, '```')
|
|
212
|
+
diffErrorLines = arrayNew()
|
|
213
|
+
endif
|
|
214
|
+
endif
|
|
215
|
+
endfor
|
|
216
|
+
if diffErrorLines:
|
|
217
|
+
arrayExtend(errorLines, arrayNew('Deep-equal:', '', '```'))
|
|
218
|
+
arrayExtend(errorLines, diffErrorLines)
|
|
219
|
+
arrayPush(errorLines, '```')
|
|
220
|
+
endif
|
|
221
|
+
|
|
222
|
+
# Add the test failure error lines
|
|
223
|
+
testFailures = objectGet(unittestTests, unittestTestName)
|
|
224
|
+
if description != null:
|
|
225
|
+
arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), errorLines)))
|
|
226
|
+
else:
|
|
227
|
+
arrayPush(testFailures, errorLines)
|
|
228
|
+
endif
|
|
229
|
+
endfunction
|
package/lib/include/unittest.mds
CHANGED
|
@@ -6,186 +6,7 @@
|
|
|
6
6
|
if systemGlobalGet('unittestSentinel'):
|
|
7
7
|
return
|
|
8
8
|
endif
|
|
9
|
-
unittestSentinel = true
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
unittestWarnings = arrayNew()
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# $function: unittestRunTest
|
|
18
|
-
# $group: unittest.mds
|
|
19
|
-
# $doc: Run a unit test
|
|
20
|
-
# $arg testName: The test function name
|
|
21
|
-
function unittestRunTest(testName):
|
|
22
|
-
testFn = unittestRunTestHelper(testName)
|
|
23
|
-
if testFn:
|
|
24
|
-
testFn()
|
|
25
|
-
systemGlobalSet('unittestTestName', null)
|
|
26
|
-
endif
|
|
27
|
-
endfunction
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# $function: unittestRunTestAsync
|
|
31
|
-
# $group: unittest.mds
|
|
32
|
-
# $doc: Run an asyncronous unit test
|
|
33
|
-
# $arg testName: The test function name
|
|
34
|
-
async function unittestRunTestAsync(testName):
|
|
35
|
-
testFn = unittestRunTestHelper(testName)
|
|
36
|
-
if testFn:
|
|
37
|
-
testFn()
|
|
38
|
-
systemGlobalSet('unittestTestName', null)
|
|
39
|
-
endif
|
|
40
|
-
endfunction
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
# unittestRunTest helper function
|
|
44
|
-
function unittestRunTestHelper(testName):
|
|
45
|
-
# Single test argument?
|
|
46
|
-
if vTest != null && vTest != testName:
|
|
47
|
-
return null
|
|
48
|
-
endif
|
|
49
|
-
|
|
50
|
-
# Test run multiple times?
|
|
51
|
-
if objectHas(unittestTests, testName):
|
|
52
|
-
arrayPush(unittestWarnings, 'Test "' + testName + '" run multiple times')
|
|
53
|
-
return null
|
|
54
|
-
endif
|
|
55
|
-
|
|
56
|
-
# Get the test func
|
|
57
|
-
testFn = systemGlobalGet(testName)
|
|
58
|
-
if testFn == null:
|
|
59
|
-
arrayPush(unittestWarnings, 'Test "' + testName + '" not found')
|
|
60
|
-
return null
|
|
61
|
-
endif
|
|
62
|
-
|
|
63
|
-
# Add the unit test result array
|
|
64
|
-
testFailures = arrayNew()
|
|
65
|
-
objectSet(unittestTests, testName, testFailures)
|
|
66
|
-
systemGlobalSet('unittestTestName', testName)
|
|
67
|
-
|
|
68
|
-
return testFn
|
|
69
|
-
endfunction
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
# $function: unittestReport
|
|
73
|
-
# $group: unittest.mds
|
|
74
|
-
# $doc: Render the unit test report
|
|
75
|
-
# $return: The number of unit test failures
|
|
76
|
-
function unittestReport():
|
|
77
|
-
# Compute test statistics
|
|
78
|
-
testNames = arraySort(objectKeys(unittestTests))
|
|
79
|
-
testCount = arrayLength(testNames)
|
|
80
|
-
testFailCount = 0
|
|
81
|
-
for testName in testNames:
|
|
82
|
-
testFailures = objectGet(unittestTests, testName)
|
|
83
|
-
if arrayLength(testFailures):
|
|
84
|
-
testFailCount = testFailCount + 1
|
|
85
|
-
endif
|
|
86
|
-
endfor
|
|
87
|
-
testPassCount = testCount - testFailCount
|
|
88
|
-
|
|
89
|
-
# Report statistics
|
|
90
|
-
markdownPrint('', 'Ran ' + testCount + ' tests - ' + testPassCount + ' passed, ' + testFailCount + ' failed')
|
|
91
|
-
if vTest != null:
|
|
92
|
-
testURL = if(vTestArgs != null, '#' + vTestArgs, '#var=')
|
|
93
|
-
markdownPrint('([all tests](' + testURL + '))')
|
|
94
|
-
endif
|
|
95
|
-
|
|
96
|
-
# Report any warnings
|
|
97
|
-
testWarningCount = arrayLength(unittestWarnings)
|
|
98
|
-
if testWarningCount:
|
|
99
|
-
markdownPrint('', '## Warnings')
|
|
100
|
-
for warning in unittestWarnings:
|
|
101
|
-
markdownPrint('', '- ' + markdownEscape(warning))
|
|
102
|
-
endfor
|
|
103
|
-
endif
|
|
104
|
-
|
|
105
|
-
# Report the failing tests
|
|
106
|
-
if testFailCount:
|
|
107
|
-
markdownPrint('', '## Failing Tests')
|
|
108
|
-
for testName in testNames:
|
|
109
|
-
testFailures = objectGet(unittestTests, testName)
|
|
110
|
-
if arrayLength(testFailures):
|
|
111
|
-
testURL = '#' + if(vTestArgs != null, vTestArgs + '&', '') + "var.vTest='" + urlEncodeComponent(testName) + "'"
|
|
112
|
-
failureLines = arrayNew('', '[' + markdownEscape(testName) + '](' + testURL + ") - FAIL")
|
|
113
|
-
for errorLines in testFailures:
|
|
114
|
-
for errorLine, ixErrorLine in errorLines:
|
|
115
|
-
if ixErrorLine == 0:
|
|
116
|
-
arrayPush(failureLines, '')
|
|
117
|
-
arrayPush(failureLines, '- ' + errorLine)
|
|
118
|
-
else:
|
|
119
|
-
arrayPush(failureLines, ' ' + errorLine)
|
|
120
|
-
endif
|
|
121
|
-
endfor
|
|
122
|
-
endfor
|
|
123
|
-
markdownPrint(failureLines)
|
|
124
|
-
endif
|
|
125
|
-
endfor
|
|
126
|
-
endif
|
|
127
|
-
|
|
128
|
-
# Report the passing tests
|
|
129
|
-
if testPassCount:
|
|
130
|
-
markdownPrint('', '## Passing Tests')
|
|
131
|
-
for testName in testNames:
|
|
132
|
-
testFailures = objectGet(unittestTests, testName)
|
|
133
|
-
if !arrayLength(testFailures):
|
|
134
|
-
testURL = '#' + if(vTestArgs != null, vTestArgs + '&', '') + "var.vTest='" + urlEncodeComponent(testName) + "'"
|
|
135
|
-
markdownPrint('', '[' + markdownEscape(testName) + '](' + testURL + ") - OK")
|
|
136
|
-
endif
|
|
137
|
-
endfor
|
|
138
|
-
endif
|
|
139
|
-
|
|
140
|
-
return testWarningCount + testFailCount
|
|
141
|
-
endfunction
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
# $function: unittestEqual
|
|
145
|
-
# $group: unittest.mds
|
|
146
|
-
# $doc: Assert an actual value is equal to the expected value
|
|
147
|
-
# $arg actual: The actual value
|
|
148
|
-
# $arg expected: The expected value
|
|
149
|
-
# $arg description: The description of the assertion
|
|
150
|
-
function unittestEqual(actual, expected, description):
|
|
151
|
-
if actual != expected:
|
|
152
|
-
unittestRecordError(jsonStringify(actual), jsonStringify(expected), description)
|
|
153
|
-
endif
|
|
154
|
-
endfunction
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
# $function: unittestDeepEqual
|
|
158
|
-
# $group: unittest.mds
|
|
159
|
-
# $doc: Assert an actual value is *deeply* equal to the expected value
|
|
160
|
-
# $arg actual: The actual value
|
|
161
|
-
# $arg expected: The expected value
|
|
162
|
-
# $arg description: The description of the assertion
|
|
163
|
-
function unittestDeepEqual(actual, expected, description):
|
|
164
|
-
actualJSON = jsonStringify(actual)
|
|
165
|
-
expectedJSON = jsonStringify(expected)
|
|
166
|
-
if actualJSON != expectedJSON:
|
|
167
|
-
unittestRecordError(actualJSON, expectedJSON, description)
|
|
168
|
-
endif
|
|
169
|
-
endfunction
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
# Helper function to record a unit test error
|
|
173
|
-
function unittestRecordError(actualStr, expectedStr, description):
|
|
174
|
-
testFailures = objectGet(unittestTests, unittestTestName)
|
|
175
|
-
errorLines = arrayNew( \
|
|
176
|
-
'~~~', \
|
|
177
|
-
actualStr, \
|
|
178
|
-
'~~~', \
|
|
179
|
-
'', \
|
|
180
|
-
'!=', \
|
|
181
|
-
'', \
|
|
182
|
-
'~~~', \
|
|
183
|
-
expectedStr, \
|
|
184
|
-
'~~~' \
|
|
185
|
-
)
|
|
186
|
-
if description != null:
|
|
187
|
-
arrayPush(testFailures, arrayExtend(arrayNew(markdownEscape(description), errorLines)))
|
|
188
|
-
else:
|
|
189
|
-
arrayPush(testFailures, errorLines)
|
|
190
|
-
endif
|
|
191
|
-
endfunction
|
|
11
|
+
systemLog('MarkdownUp - unittest.mds: unittest.mds is now unittest.bare - please update before 2025-06-01')
|
|
12
|
+
include 'unittest.bare'
|