-
Notifications
You must be signed in to change notification settings - Fork 16
/
testcheck.node.txt
214 lines (166 loc) · 12.2 KB
/
testcheck.node.txt
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
TESTCHECK
ALTERNATIVES ==> # - testckeck-js:
# - run a function several times, each time with different generated input (within specific constraints)
# - "shrinking": tries to guess upper and lower limit of generated input that make tests fail
# - sazerac:
# - not maintained
# - more expressive syntax for running the same test several times with different output
# - although using ARR.forEach(VAL => it(...)) is actually simpler and better
# - jest data driven testing:
# - part of Jest, i.e. Jest-specific
# - sugar syntax over ARR.forEach(VAL => it(...))
# - jest-each:
# - same as jest data driven testing (Jest copied/pasted its code)
# - i.e. not worth it since it is now integrated
VERSION ==> #1.0.0-rc.2
/=+===============================+=\
/ : : \
)==: GENERATORS CORE :==(
\ :_______________________________: /
\=+===============================+=/
GEN #Abstraction of a FUNC()->VAL for a specific type|constraints
#Actually an OBJ not a FUNC
#Is an infinite ITERABLE
#Can be any of TESTCHECK.gen.*
sampleOne(GEN[, SIZE])->VAL #Returns one generated value
#Def SIZE: 30
sample(GEN[, NUM])->ARR #Returns NUM (def: 10) generated values
/=+===============================+=\
/ : : \
)==: GENERATORS SIMPLE :==(
\ :_______________________________: /
\=+===============================+=/
gen.deepCopyOf(VAL)
VAL #Always generates VAL (by deep copy)
gen.return(VAL) #Always generates VAL (by reference)
gen.boolean #BOOL
gen.undefined #undefined
gen.null #null
gen.intWithin(NUM, NUM2) #Integer between NUM and NUM2
gen.int #Integer between -100 and 100
gen.posInt #Integer between 0 and 100
gen.sPosInt #Integer between 1 and 100
gen.negInt #Integer between -100 and -0
gen.sNegInt #Integer between -100 and -1
gen.numberWithin(NUM, NUM2) #Float between NUM and NUM2
gen.number #Float between Number.MIN_VALUE and Number.MAX_VALUE.
#Also generates NaN, Infinity, -Infinity
gen.posNumber|negNumber #Same but only positive|negative
#Also generates Infinity, -Infinity
gen.NaN #NaN
gen.char #Single STR character
#Generates backslash sequences either as sequences or as is
gen.asciiChar #[[:print:]]
gen.alphaNumChar #[[:alnum:]]
gen.string
gen.asciiString #Same but as a string
gen.alphaNumString #String length uses gen.posInt (i.e. can be empty string)
gen.substring(STR) #Random STR.substring(...)
/=+===============================+=\
/ : : \
)==: GENERATORS COMPLEX :==(
\ :_______________________________: /
\=+===============================+=/
gen.array(GEN[, NUM|OPTS]) #OPTS:
# - size NUM (def: gen.posInt (i.e. can be empty))
# - minSize|maxSize NUM2
gen.array(GEN_ARR) #Length is ARR.length and each element has different GEN
gen.uniqueArray #Same but every ARR element is unique
(GEN[, FUNC][, NUM|OPTS]) #OPTS: size|minSize|maxSize
#FUNC(VAL)->VAL is used to normalize before determine uniqueness with ===
gen.object([GEN, ]GEN2[,NUM|OPTS])#Object with:
# - key GEN (def: gen.alphaNumString)
# - value GEN2
#OPTS:
# - size NUM (def: gen.posInt (i.e. can be empty))
# - minSize|maxSize NUM2
gen.object({ KEY: GEN, ... }) #
gen.oneOf(GEN_ARR) #Random pick a GEN
gen.oneOfWeighted
([WEIGHT_NUM, GEN]_ARR) #Same but weighted
gen.nested(GEN, GEN2) #Either GEN(GEN2) or GEN(GEN(GEN2)) or ...
gen.arrayOrObject(GEN) #Like gen.oneOf(gen.array(GEN), gen.object(GEN))
gen.primitive #Either gen.null|undefined|integer|number|string|boolean
gen.JSONPrimitive #Either gen.null|integer|number|string|boolean (excluding NaN|[-]Infinity)
gen.JSONValue #Like gen.nested(gen.arrayOrObject, gen.JSONPrimitive)
gen.JSON #Like gen.nested(gen.object, gen.JSONValue)
gen.any #Like gen.nested(gen.arrayOrObject, gen.primitive)
GEN.nullable() #Like gen.oneOfWeighted([5, GEN], [1, gen.null])
GEN.suchThat(FUNC(VAL)->BOOL) #Ensures no generated value return false with FUNC()
#Throw exception after 10 failed attempts
GEN.notEmpty() #Ensures no generated value == false
GEN.then(FUNC(VAL)->VAL) #Map generated values
/=+===============================+=\
/ : : \
)==: TESTS :==(
\ :_______________________________: /
\=+===============================+=/
property #Abstraction of a FUNC that take generated VAL... as input and returns BOOL
(GEN..., FUNC(VAL...)->BOOL) #If FUNC():
->PROP # - returns non-BOOL, it will be considered true
# - throws ERROR, it will be considered false
check(PROP[, COPTS])->RESULT #Runs a PROP several times and reports RESULT
#COPTS:
# - numTests NUM (def: 100): number of tests to run
# - seed NUM: randomness seed
#RESULT:
# - result BOOL: true if no PROP's FUNC returned false
# - seed NUM
# - numTests NUM:
# - number of tests run
# - might be lower if result false
# - does not take shkring search into account
# (if result false)
# - fail ARR: generated values that triggered the failed test
# - failingSize NUM: numTests - 1
/=+===============================+=\
/ : : \
)==: SHRINKING :==(
\ :_______________________________: /
\=+===============================+=/
SHRINKING ==> #Generated values are:
# - first towards to the middle of the values domain
# - then expanded in both directions after each run
# - e.g. gen.int: 0, 5, -5, 10, -10, etc.
# - extent of this expansion is the GEN's "size"
#The first time check()'s PROP's FUNC returns false, tries to guess which is the starting limit:
# - by running the test doing a binary search
# - those extra tests are performed until limit is found
# - with several generated values, first try to guess which one is problematic
RESULT.shrunk #Only defined if RESULTS.result false
RESULT.shrunk.totalNodesVisited #NUM: number of binary search tests
RESULT.shrunk.smallest #ARR: result of the binary search
RESULT.shrunk.depth #NUM
RESULT.shrunk.result #BOOL
COPTS.maxSize #Max "size" (def: 200)
gen.sized(FUNC(NUM)->GEN) #GEN which is constructed using a NUM ("size")
#All builtin GEN are "sized"
GEN.scale(FUNC(NUM)->NUM) #Maps the size NUM
#E.g. by default is grown linearly whereas FUNC(NUM)->NUM**2 will grow cubicly
GEN.neverShrink() #Disables shrinking, e.g. if not used.
GEN.alwaysShrink() #Force shrinking after test passes
/=+===============================+=\
/ : : \
)==: RUNNERS :==(
\ :_______________________________: /
\=+===============================+=/
MOCHA-TESTCHECK #Helpers for Mocha
GLOBAL|MOCHA-TESTCHECK.check #Shortcut for check(property(...), COPTS)
([COPTS, ]...)->FUNC2() #If test fails, throw ERROR with ERROR.check RESULT and nice error message
GLOBAL.check.[x]it[.only|skip]
(STR, ...) #Same as [x]it[.only|skip](STR, MOCHA-TESTCHECK.check(...))
GLOBAL|MOCHA-TESTCHECK.gen #Reference to TESTCHECK.gen
MOCHA-TESTCHECK.install() #Must be called to install GLOBAL.*
MOCHA-JASMINE
GLOBAL.check(...)
GLOBAL.[x]it[.skip|only](...)
GLOBAL.gen
MOCHA-JASMINE.install() #Same for Jasmine and Jest
MOCHA-TAPE
MOCHA-TAPE.check(...)
MOCHA-TAPE.gen #Same for Tape
MOCHA-AVA
MOCHA-AVA.check(...)
MOCHA-AVA.gen #Same for Ava