FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
plugdata/Tests/PatchTextFuzzTest.h at develop · plugdata-team/plugdata · GitHub
Uh oh!
There was an error while loading.
Please reload this page
.
plugdata-team
/
plugdata
Public
Uh oh!
There was an error while loading.
Please reload this page
.
Notifications
You must be signed in to change notification settings
Fork
103
Star
2.3k
Code
Issues
237
Pull requests
2
Discussions
Actions
Projects
Wiki
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Discussions
Actions
Projects
Wiki
Security and quality
Insights
Expand file tree
Breadcrumbs
plugdata
/
Tests
/
PatchTextFuzzTest.h
Copy path
More file actions
More file actions
Latest commit
History
History
History
166 lines (148 loc) · 6.66 KB
Breadcrumbs
plugdata
/
Tests
/
PatchTextFuzzTest.h
Copy path
File metadata and controls
166 lines (148 loc) · 6.66 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
//
Fuzzes the patch loader with structurally damaged patch files.
//
//
Users routinely paste patch text from forums/chats and open patches written
//
by other (sometimes buggy) software, so the loader regularly sees text that
//
no saver would produce. This test generates randomly malformed patch text
//
and runs it through the same path as TabComponent::openPatch: a random mix
//
of valid object/message/atom/array lines with classic loader hazards:
//
//
- "#X connect" with out-of-range or negative object indices
//
- "#X restore" without a matching "#N canvas" (canvas stack underflow)
//
- "#N canvas" that is never restored (truncated file)
//
- "#A" array-data lines with no array in sight
//
- "#X coords" on canvases with and without graph-on-parent
//
- absurd coordinates/sizes, multi-kilobyte single atoms, unterminated
//
final lines, raw garbage lines, and "\$0"-style dollar args at the
//
top level
//
//
Whatever the loader produces is then synchronised into a Canvas (so
//
plugdata's object/connection sync sees the damaged glist too) and closed
//
again. Every generated patch is deterministic for a fixed UnitTestRunner
//
seed; the patch text of the current iteration is logged so a crash can be
//
reproduced directly.
class
PatchTextFuzzTest
:
public
PlugDataUnitTest
{
public:
PatchTextFuzzTest
(PluginEditor* editor) : PlugDataUnitTest(editor,
"
Patch Text Fuzz Test
"
)
{
}
private:
static
constexpr
int
numPatches =
80
;
void
perform
()
override
{
editor->
pd
->
volume
->
store
(
0
.
0f
);
performStep
(numPatches);
}
void
performStep
(
int
stepsLeft)
{
auto
& tabbar = editor->
getTabComponent
();
if
(stepsLeft ==
0
) {
while
(
auto
* cnv = tabbar.
getCurrentCanvas
())
tabbar.
closeTab
(cnv);
signalDone
(
true
);
return
;
}
beginTest
(
String
(stepsLeft) +
"
-> random malformed patch
"
);
auto
const
patchText =
generatePatchText
();
//
Log the patch so a crash in this iteration can be reproduced
logMessage
(patchText);
tabbar.
openPatch
(patchText);
if
(
auto
* cnv = tabbar.
getCurrentCanvas
())
cnv->
performSynchronise
();
while
(
auto
* cnv = tabbar.
getCurrentCanvas
())
tabbar.
closeTab
(cnv);
Timer::callAfterDelay
(
1
, [
this
, stepsLeft] {
performStep
(stepsLeft -
1
);
});
}
String
generatePatchText
()
{
static
constexpr
char
const
* objectNames[] = {
"
osc~
"
,
"
dac~
"
,
"
metro
"
,
"
f
"
,
"
t b b
"
,
"
print
"
,
"
tgl
"
,
"
bng
"
,
"
list store
"
,
"
until
"
,
"
select 1
"
,
"
route a b
"
,
"
text define
"
,
"
not_an_object_xyz
"
,
"
$1
"
,
"
\\
$0-foo
"
};
String text =
"
#N canvas 100 100 600 400 12;
\n
"
;
int
openCanvases =
0
;
int
const
numLines = rng.
nextInt
(
30
) +
1
;
for
(
int
i =
0
; i < numLines; i++) {
switch
(rng.
nextInt
(
12
)) {
case
0
:
case
1
:
//
A (mostly) valid object line
text +=
"
#X obj
"
+
randomCoord
() +
"
"
+
randomCoord
() +
"
"
+ objectNames[rng.
nextInt
(
static_cast
<
int
>(
std::size
(objectNames)))] +
"
;
\n
"
;
break
;
case
2
:
//
A message box, sometimes with dollar args and escapes
text +=
"
#X msg
"
+
randomCoord
() +
"
"
+
randomCoord
() +
"
set
\\
$1
"
+
randomToken
(rng.
nextInt
(
20
) +
1
) +
"
;
\n
"
;
break
;
case
3
:
//
Atom boxes
text += rng.
nextBool
()
?
"
#X floatatom
"
+
randomCoord
() +
"
"
+
randomCoord
() +
"
5 0 0 0 - - -;
\n
"
:
"
#X symbolatom
"
+
randomCoord
() +
"
"
+
randomCoord
() +
"
10 0 0 0 - - -;
\n
"
;
break
;
case
4
:
//
Connection with random, frequently out-of-range indices
text +=
"
#X connect
"
+
String
(rng.
nextInt
(
20
) -
4
) +
"
"
+
String
(rng.
nextInt
(
8
) -
2
) +
"
"
+
String
(rng.
nextInt
(
20
) -
4
) +
"
"
+
String
(rng.
nextInt
(
8
) -
2
) +
"
;
\n
"
;
break
;
case
5
:
//
Open a subcanvas (may never be restored)
text +=
"
#N canvas 0 0 300 200 sub
"
+
String
(i) +
"
0;
\n
"
;
openCanvases++;
break
;
case
6
:
//
Restore - sometimes without a canvas to restore
text +=
"
#X restore
"
+
randomCoord
() +
"
"
+
randomCoord
() +
"
pd sub;
\n
"
;
openCanvases--;
break
;
case
7
:
//
Array definition, sometimes followed by mismatched data
text +=
"
#X array fuzzarray
"
+
String
(i) +
"
"
+
String
(rng.
nextInt
(
1000
) -
100
) +
"
float
"
+
String
(rng.
nextInt
(
4
)) +
"
;
\n
"
;
if
(rng.
nextBool
())
text +=
"
#A
"
+
String
(rng.
nextInt
(
2000
)) +
"
0.1 0.2 0.3 0.4;
\n
"
;
break
;
case
8
:
//
Stray array data with no array in sight
text +=
"
#A 0
"
+
randomToken
(rng.
nextInt
(
40
) +
1
) +
"
;
\n
"
;
break
;
case
9
:
//
Graph-on-parent coords, valid or not
text +=
"
#X coords 0 1 100 -1
"
+
String
(rng.
nextInt
(
400
) -
100
) +
"
"
+
String
(rng.
nextInt
(
400
) -
100
) +
"
"
+
String
(rng.
nextInt
(
3
)) +
"
0 0;
\n
"
;
break
;
case
10
:
//
A single absurdly long atom
text +=
"
#X obj 10 10
"
+
randomToken
(rng.
nextInt
(
4000
) +
1000
) +
"
;
\n
"
;
break
;
case
11
:
//
Raw garbage line
text +=
randomToken
(rng.
nextInt
(
60
) +
1
) +
"
\n
"
;
break
;
}
}
//
Sometimes close the canvases that are still open, sometimes leave
//
the file truncated; sometimes pop one canvas too many
int
toClose = openCanvases + (rng.
nextInt
(
4
) ==
0
?
1
:
0
);
if
(rng.
nextInt
(
4
) ==
0
)
toClose =
0
;
for
(
int
i =
0
; i < toClose; i++)
text +=
"
#X restore 10 10 pd sub;
\n
"
;
//
Sometimes chop the end off mid-line
if
(rng.
nextInt
(
4
) ==
0
)
text = text.
dropLastCharacters
(rng.
nextInt
(
jmin
(
20
, text.
length
())));
return
text;
}
String
randomCoord
()
{
switch
(rng.
nextInt
(
4
)) {
case
0
:
return
String
(rng.
nextInt
(
600
));
case
1
:
return
String
(-rng.
nextInt
(
100000
));
case
2
:
return
String
(rng.
nextInt
(std::numeric_limits<
int
>::
max
()));
default
:
return
String
(rng.
nextFloat
() * 1e9f);
}
}
String
randomToken
(
int
length)
{
static
constexpr
char
charset[] =
"
abcdefghijklmnopqrstuvwxyz0123456789$
\\
,;{}()[]<>~#-.
"
;
String result;
result.
preallocateBytes
(length);
for
(
int
i =
0
; i < length; i++)
result += charset[rng.
nextInt
(
sizeof
(charset) -
1
)];
return
result;
}
};
Back
|
FazBrowse Home
|
New Git URL