This repository was archived by the owner on Aug 31, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 227
Expand file tree
/
Copy pathvalidate-dictionary.livecodescript
More file actions
466 lines (366 loc) · 18.6 KB
/
validate-dictionary.livecodescript
File metadata and controls
466 lines (366 loc) · 18.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
script "DocsValidateDictionary"
/*
Copyright (C) 2016 LiveCode Ltd.
This file is part of LiveCode.
LiveCode is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License v3 as published by the Free
Software Foundation.
LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
constant kAPITypes = "command,function,property,message,constant,keyword,control structure,operator,statement,expression,handler"
constant kGlossaryTypes = "library,glossary,object,widget,module"
constant kOS = "iOS,Android,Mac,Windows,Linux,RPi,html5"
constant kPlatform = "desktop,mobile,server,filemaker"
on TestSetup
TestSkipIfNot "docs"
-- Only run these tests on desktop platforms
if the platform is not among the items of "MacOS,Windows,Linux" then
return "SKIP Tests are not runnable on" && the platform
end if
local tDocsParser
put TestGetEngineRepositoryPath() & "/ide-support/revdocsparser.livecodescript" into tDocsParser
start using stack tDocsParser
create stack "Test"
end TestSetup
on TestDocsValidateDictionary
local tDocsPath, tDocsArray
put TestGetEngineRepositoryPath() & "/docs" into tDocsPath
put revDocsParseDictionaryToLibraryArray(tDocsPath) into tDocsArray
__TestDocsLibraryArray tDocsPath, tDocsArray
end TestDocsValidateDictionary
on TestDocsValidateExtractedLibraries
local tExtractedDocsFolder
put TestGetExtractedDocsFolder() into tExtractedDocsFolder
-- There are not necessarily any docs in the extracted docs folder now.
-- Re-uncomment if and when there are.
//TestAssert "extracted docs folder exists", there is a folder tExtractedDocsFolder
if there is not a folder tExtractedDocsFolder then
exit TestDocsValidateExtractedLibraries
end if
local tFiles
put files(tExtractedDocsFolder) into tFiles
TestAssert "some files are in the extracted docs folder", tFiles is not empty
filter tFiles with "*.lcdoc"
TestAssert "some lcdoc files are in the extracted docs folder", tFiles is not empty
set the itemDelimiter to "."
local tFile
repeat for each line tFile in tFiles
local tDocsPath, tDocsArray
put tExtractedDocsFolder & slash & tFile into tDocsPath
put revDocsParseDocFileToLibraryArray(tDocsPath, item -2 of tFile, "LiveCode") into tDocsArray
TestAssert tDocsPath & ":" && "type of" && tFile && "is library", tDocsArray["type"] is "library"
TestAssert tDocsPath & ":" && "name of" && tFile && "is not empty", tDocsArray["name"] is not empty
TestAssert tDocsPath & ":" && "display name of" && tFile && "is not empty", tDocsArray["display name"] is not empty
TestAssert tDocsPath & ":" && "author name of" && tFile && "is not empty", tDocsArray["author"] is not empty
TestAssert tDocsPath & ":" && "description of" && tFile && "is not empty", tDocsArray["description"] is not empty
__TestDocsLibraryArray tDocsPath, tDocsArray["doc"]
end repeat
end TestDocsValidateExtractedLibraries
on TestDocsValidateExtensionDocs
local tExtensionsFolder
put TestGetPackagedExtensionsFolder() into tExtensionsFolder
TestAssert "packaged extensions folder exists", there is a folder tExtensionsFolder
local tExtensions
put folders(tExtensionsFolder) into tExtensions
filter tExtensions without ".*"
repeat for each line tExtension in tExtensions
local tFiles
put files(tExtensionsFolder & slash & tExtension) into tFiles
filter tFiles with "*.lcdoc"
TestAssert tExtension && "has docs file", tFiles is not empty
set the itemDelimiter to "."
local tFile
repeat for each line tFile in tFiles
local tDocsPath, tDocsArray
put tExtensionsFolder & slash & tExtension & slash & tFile into tDocsPath
if url("file:" & tDocsPath) is empty then
TestAssertBroken tDocsPath & ": non-empty docs", false
next repeat
end if
put revDocsParseDocFileToLibraryArray(tDocsPath, tExtension, "LiveCode") into tDocsArray
TestAssert tDocsPath & ":" && "type of" && tFile && "is not empty", tDocsArray["type"] is not empty
TestAssert tDocsPath & ":" && "display name of" && tFile && "is not empty", tDocsArray["display name"] is not empty
TestAssert tDocsPath & ":" && "author name of" && tFile && "is not empty", tDocsArray["author"] is not empty
-- At the moment, allow docs to have either summary or description
local tExtensionNoSummary, tExtensionNoDescription
put tDocsArray["summary"] is empty into tExtensionNoSummary
put tDocsArray["description"] is empty into tExtensionNoDescription
if tExtensionNoSummary and tExtensionNoDescription then
TestAssert tDocsPath & ":" && "summary of" && tFile && "is not empty", false
TestAssert tDocsPath & ":" && "description of" && tFile && "is not empty", false
else if tExtensionNoSummary then
TestAssertBroken tDocsPath & ":" && "summary of" && tFile && "is not empty", false
else if tExtensionNoDescription then
TestAssertBroken tDocsPath & ":" && "description of" && tFile && "is not empty", false
else
TestAssert tDocsPath & ":" && "summary of" && tFile && "is not empty", true
TestAssert tDocsPath & ":" && "description of" && tFile && "is not empty", true
end if
__TestDocsLibraryArray tDocsPath, tDocsArray["doc"], tDocsArray["type"] is not "module"
end repeat
end repeat
end TestDocsValidateExtensionDocs
command __TestDocsLibraryArray pDocsPath, pLibrary, pTestSyntax
local tElement
local tReferences
repeat for each element tElement in pLibrary
put true into tReferences[tElement["type"]][tElement["display name"]]
end repeat
repeat for each element tElement in pLibrary
local tValue
local tIndex
-- test name required
TestAssert pDocsPath & ":" && "name of" && tElement["display name"] && tElement["type"] && "not empty", tElement["display name"] is not empty
-- test type is valid
TestAssert pDocsPath & ":" && "type of" && tElement["display name"] && tElement["type"] && "is valid", tElement["type"] is among the items of (kAPITypes,kGlossaryTypes)
-- test syntaxes exist for API entries
local tSyntaxParams
if tElement["type"] is among the items of kAPITypes then
TestAssert pDocsPath & ":" && "API entry for" && tElement["display name"] && tElement["type"] && "has syntax", tElement["syntax"] is an array
-- parse out params to validate against documented params
put 1 into tIndex
repeat for each element tValue in tElement["syntax"]
-- ensure matching brackets
CheckBrackets tValue, "syntax" && tIndex && "of" && tElement["display name"] && tElement["type"]
split tValue by "<"
local tSplitIndex
repeat with tSplitIndex = 2 to the number of elements of tValue
split tValue[tSplitIndex] by ">"
split tValue[tSplitIndex][1] by "|"
put true into tSyntaxParams[tValue[tSplitIndex][1][1]]
end repeat
add 1 to tIndex
end repeat
-- test summary required
TestAssert pDocsPath & ":" && "summary of" && tElement["display name"] && tElement["type"] && "not empty", tElement["summary"] is not empty
end if
-- !TODO test associations are valid
-- test OS
repeat for each element tValue in tElement["OS"]
TestAssert pDocsPath & ":" && "OS entry" && tValue && "for" && tElement["display name"] && tElement["type"] && "is valid", tValue is among the items of kOS
end repeat
-- test platform
repeat for each element tValue in tElement["Platform"]
TestAssert pDocsPath & ":" && "Platform entry" && tValue && "for" && tElement["display name"] && tElement["type"] && "is valid", tValue is among the items of kPlatform
end repeat
-- test examples
put 1 into tIndex
if pTestSyntax is not false and \
tElement["display name"] is not among the words of "sessionName errorObject" then
repeat for each element tValue in tElement["Example"]
if word 1 of tValue is among the words of "end case catch" then
next repeat
end if
--some scrips have ... to indicate user code
replace "..." with empty in tValue
--some html entities
replace ">" with ">" in tValue
replace "<" with "<" in tValue
local tLine
local tRequiresWrap
put true into tRequiresWrap
repeat for each line tLine in tValue
if word 1 of tLine is among the words of "on private command function before after setprop getprop" then
put false into tRequiresWrap
exit repeat
end if
end repeat
local tWrapWith
put empty into tWrapWith
if tRequiresWrap then
get matchText(tValue, "exit (.+)", tWrapWith)
if tWrapWith is empty or word 1 of tWrapWith is among the words of "repeat if switch to" then
put "mouseUp" into tWrapWith
end if
end if
local tTempValue
if tRequiresWrap then
put "on" && tWrapWith & return & tValue & return & "end" && tWrapWith into tTempValue
else
put tValue into tTempValue
end if
set the script of stack "Test" to tTempValue
local tResult
put the result into tResult
--!TODO this should not be necessary if we fix all these docs but baby steps!!!
-- check for lack of vairable declaration but only auto fix for 1 variable
if tResult is not empty then
-- require variable declaration
if item 1 of line 1 of tResult is among the items of 14,78,209,423,507 and "(" is not in item 4 of line 1 of tResult then
put "local" && item 4 of line 1 of tResult & return before tTempValue
set the script of stack "Test" to tTempValue
put the result into tResult
else if the number of lines of tValue is 1 then
--!TODO this should not be necessary if we fix all these docs but baby steps!!!
-- check for half baked examples
set the itemDelimiter to "("
switch
case word 1 of tValue is not among the lines of the commandNames
case item 1 of tValue is among the lines of the functionNames and the number of items of tValue > 1
put "put " before tValue
break
case word 1 of tValue is "repeat"
put return & "end repeat" after tValue
break
case word -1 of tValue is "then"
put return & "end if" after tValue
break
end switch
set the itemDelimiter to comma
if tRequiresWrap then
put "on" && tWrapWith & return & tValue & return & "end" && tWrapWith into tTempValue
end if
set the script of stack "Test" to tTempValue
put the result into tResult
end if
end if
TestAssert pDocsPath & ":" && "example" && tIndex && "of" && tElement["display name"] && tElement["Type"] && "compiles", tResult is empty
if tResult is not empty then
TestDiagnostic "Example:" & return & tTempValue & return & "Script Parsing Error:" & return & \
line (item 1 of line 1 of tResult) of the scriptParsingErrors && "-" && item 4 of line 1 of tResult
end if
add 1 to tIndex
end repeat
end if
-- skip parameter tests for properties
if tElement["type"] is not "property" then
-- test parameters
local tDocumentedParams
repeat for each element tValue in tElement["params"]
put true into tDocumentedParams[tValue["name"]]
end repeat
local tUnion
put tDocumentedParams into tUnion
union tUnion with tSyntaxParams
local tParam, tType
repeat for each key tParam in tUnion
local tParamInGlossary
put false into tParamInGlossary
-- determine if the param specified a type
SplitParam tParam
-- params in syntax section may be documented in glossary
TestAssert pDocsPath & ":" && "param" && tParam[1] && "in param section" && tElement["display name"] && tElement["Type"], tDocumentedParams[tParam[1]] -- or tParamInGlossary
-- params in param section should be in the syntax section otherwise what are they documenting
TestAssert pDocsPath & ":" && "param" && tParam[1] && "in syntax section" && tElement["display name"] && tElement["Type"], tSyntaxParams[tParam[1]]
end repeat
end if
delete variable tDocumentedParams
delete variable tSyntaxParams
-- test description required
TestAssert pDocsPath & ":" && "description of" && tElement["display name"] && tElement["type"] && "not empty", tElement["Description"] is not empty
-- !TODO parse all summaries and descriptions etc
-- * test all links are listed in references
-- * test for ambiguous links
end repeat
end __TestDocsLibraryArray
command SplitParam @pParam
-- find type
split pParam by "("
split pParam[2] by ")"
-- trim
put word 1 to -1 of pParam[1] into pParam[1]
put word 1 to -1 of pParam[2][1] into pParam[2]
end SplitParam
command CheckBrackets pSyntax, pMessage
local tCodepoint, tBrackets
local tPrintDiagnostic = false
repeat for each codepoint tCodepoint in pSyntax
switch tCodepoint
case "{"
SetState tBrackets, "{}", "open", tPrintDiagnostic, pMessage
break
case "}"
SetState tBrackets, "{}", "closed", tPrintDiagnostic, pMessage
break
case "["
SetState tBrackets, "[]", "open", tPrintDiagnostic, pMessage
break
case "]"
SetState tBrackets, "[]", "closed", tPrintDiagnostic, pMessage
break
case "("
SetState tBrackets, "()", "open", tPrintDiagnostic, pMessage
break
case ")"
SetState tBrackets, "()", "closed", tPrintDiagnostic, pMessage
break
case "<"
SetState tBrackets, "<>", "open", tPrintDiagnostic, pMessage
break
case ">"
SetState tBrackets, "<>", "closed", tPrintDiagnostic, pMessage
break
case "|"
-- allow pipe for plural params
TestAssert pMessage && "variant in curly brackets", GetState(tBrackets, "{}") is "open" and GetState(tBrackets, "<>") is "closed"
if not (GetState(tBrackets, "{}") is "open" and GetState(tBrackets, "<>") is "closed") then
put true into tPrintDiagnostic
end if
break
end switch
end repeat
TestAssert pMessage && "matched pairs of curly brackets", tBrackets["{}"]["count"] is empty or tBrackets["{}"]["count"] is 0
if not tPrintDiagnostic then
put not (tBrackets["{}"]["count"] is empty or tBrackets["{}"]["count"] is 0) into tPrintDiagnostic
end if
TestAssert pMessage && "matched pairs of square brackets", tBrackets["[]"]["count"] is empty or tBrackets["[]"]["count"] is 0
if not tPrintDiagnostic then
put not (tBrackets["[]"]["count"] is empty or tBrackets["[]"]["count"] is 0) into tPrintDiagnostic
end if
TestAssert pMessage && "matched parentheses", tBrackets["()"]["count"] is empty or tBrackets["()"]["count"] is 0
if not tPrintDiagnostic then
put not (tBrackets["()"]["count"] is empty or tBrackets["()"]["count"] is 0) into tPrintDiagnostic
end if
TestAssert pMessage && "matched angle brackets", tBrackets["<>"]["count"] is empty or tBrackets["<>"]["count"] is 0
if not tPrintDiagnostic then
put not (tBrackets["<>"]["count"] is empty or tBrackets["<>"]["count"] is 0) into tPrintDiagnostic
end if
if tPrintDiagnostic then
TestDiagnostic pSyntax
end if
end CheckBrackets
constant kBracketTypes = "{},[],(),<>"
command SetState @xBrackets, pType, pState, @xPrintDiagnostic, pMessage
local tSize
put the number of elements of xBrackets[pType] into tSize
if pState is "open" then
add 1 to tSize
end if
put pState into xBrackets[pType][tSize]["state"]
local tType
repeat for each item tType in kBracketTypes
if tType is pType then
next repeat
end if
local tOtherSize
put the number of elements of xBrackets[tType] into tOtherSize
if tOtherSize is 0 then
next repeat
end if
if pState is "open" then
if xBrackets[tType][tOtherSize]["state"] is "open" then
put tOtherSize into xBrackets[pType][tSize][tType]
else if xBrackets[pType][tSize][tType] is an integer and \
xBrackets[tType][xBrackets[pType][tSize][tType]]["state"] is not "open" then
-- check if any brackets open when we opened these are still open
TestAssert pMessage && "brackets" && pType && tType && "nested correctly" , false
put true into xPrintDiagnostic
end if
end if
end repeat
end SetState
function GetState pBrackets, pType
local tSize
repeat with tSize = the number of elements of pBrackets[pType] down to 1
if pBrackets[pType][tSize]["state"] is "open" then return "open"
end repeat
return "closed"
end GetState
on TestTeardown
delete stack "revDocsParser"
delete stack "Test"
end TestTeardown