Synthia
Generic and flexible data structure generator
CalculatorMonkey.java
Go to the documentation of this file.
1 /*
2  Synthia, a data structure generator
3  Copyright (C) 2019-2021 Laboratoire d'informatique formelle
4  Université du Québec à Chicoutimi, Canada
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 package examples.gui;
20 
23 import ca.uqac.lif.synthia.test.Action;
24 import ca.uqac.lif.synthia.test.Monkey;
25 import ca.uqac.lif.synthia.util.Choice;
26 
27 /**
28  * Performs <a href="https://en.wikipedia.org/wiki/Monkey_testing">monkey
29  * testing</a> over a simple calculator, using Synthia's {@link Monkey}.
30  * <p>
31  * The monkey is instantiated with an equal probability of clicking on any
32  * of the calculator's 16 buttons at any moment. It runs until the calculator
33  * throws an exception, after which it will attempt to <em>shrink</em> the
34  * sequence --i.e., to find a subsequence that still causes the exception to
35  * be thrown.
36  * <p>
37  * The picker for actions requires a <tt>Picker&lt;Float&gt;</tt> in order
38  * to generate a subsequence. Instead of supplying it with a uniform
39  * {@link RandomFloat} in the interval [0,1], we rather pass a
40  * {@link BiasedRandomFloat} that gives preference to values closer to 1.
41  * This has for effect that sub-sequences will contain more actions from
42  * the <em>end</em> of the reference sequence instead of the beginning.
43  * This is based on the intuition that errors are more likely to occur
44  * because of actions close to the occurrence of the exception.
45  * <p>
46  * Depending on the seed and on the faults enabled in the {@link Calculator},
47  * four outcomes are likely:
48  * <ol>
49  * <li><a href="#noerror">no error found</a></li>
50  * <li><a href="#number">number format exception</a></li>
51  * <li><a href="#overflow">overflow</a></li>
52  * <li><a href="#divzero">division by zero</a></li>
53  * </ol>
54  *
55  * <a name="noerror"></a><h4>No error found</h4>
56  * If the monkey finds no error, its printout will look like this:
57  * <pre>
58  * Attempt 0
59  * 48÷14==5−1÷36620×60603÷73=64÷6.3816=6=1÷95÷=9698821269.5845÷3439101.4270=93515÷2×7×5892×−426501=5061
60  * Attempt 1
61  * 72121=689=5÷16÷3.÷69087÷500÷.−=1617=×1=−÷5.92÷85−016=6=906840366.030−665494282×−0006464÷×240=9−22568
62  * Attempt 2
63  * ×1÷8−95÷438454.×2.4941082×678÷−80=3.÷148×.4288÷6223−629400−7=065544739.5.65×7.2×660−36.×59×22945449×
64  * Attempt 3
65  * ×498×505×−5445.1.08=040622×562749×105×6644×66÷÷−×264897−7=.84−9−60972067464.4−0003=979.×3567÷−8×55=4
66  * Attempt 4
67  * 870−6÷−111−7×.23398−452÷=21×0170.×6.=×.53÷=947=82679÷6627÷38.2÷61..2×4=809−÷2−×22×58147480×1−×9788−1
68  *
69  * No error found
70  * </pre>
71  *
72  * <a name="number"></a><h4>Number format exception</h4>
73  *
74  * If the number format fault is enabled, a possible execution of the monkey is the following:
75  * <pre>
76  * Attempt 0
77  * 48÷14==5−1÷36620×60603÷73=64÷6.3816=6=1÷95÷=9698821269.5845÷3439101.4270=93515÷2×7×5892×−426501=5061
78  * Attempt 1
79  * 72121=689=5÷16÷3.÷69087÷500÷.
80  * java.lang.NumberFormatException: For input string: "."
81  * Sequence: [7, 2, 1, 2, 1, =, 6, 8, 9, =, 5, ÷, 1, 6, ÷, 3, ., ÷, 6, 9, 0, 8, 7, ÷, 5, 0, 0, ÷, ., −]
82  * 8÷369÷−
83  * 285.67−
84  * 72693÷−
85  * 719÷65−
86  * 729.8÷−
87  * 72119516360÷5.−
88  * 7211=6÷÷9870÷.
89  * Sequence: [7, 2, 1, 1, =, 6, ÷, ÷, 9, 8, 7, 0, ÷, ., −]
90  * 77−
91  * ÷7−
92  * 28−
93  * 767
94  * 71−
95  * 2=÷987−
96  * 7÷÷980−
97  * 716÷70−
98  * 2÷970÷−
99  * 72687÷−
100  * 7216÷÷870÷−
101  * 2116÷÷987.−
102  * 721=÷÷9870−
103  * 7211=÷÷97.−
104  * 21=6÷÷98÷.
105  * Sequence: [2, 1, =, 6, ÷, ÷, 9, 8, ÷, ., −]
106  * ÷−
107  * =−
108  * ÷−
109  * 2−
110  * 6−
111  * 198÷−
112  * 2=6÷−
113  * 2=÷8−
114  * 1÷÷÷−
115  * 6÷9÷−
116  * =6÷98÷.
117  * Sequence: [=, 6, ÷, 9, 8, ÷, ., −]
118  * =−
119  * ÷−
120  * ÷.
121  * .
122  * Sequence: [., −]
123  *
124  * Found a java.lang.NumberFormatException: For input string: "."
125  * Sequence : [., −]
126  * </pre>
127  * Note how the monkey finds a first long sequence producing the exception,
128  * and then iterates over smaller sequences. Ultimately, only two clicks
129  * suffice to trigger the exception.
130  *
131  * <a name="overflow"></a><h4>Overflow</h4>
132  *
133  * If the overflow fault is enabled using {@link Calculator#hasOverflow()}, a
134  * possible execution is:
135  * <pre>
136  * Attempt 0
137  * 48÷14++6−1÷3×63.1×.×0−÷7−+6446=382×+6+2÷95÷+9698821369
138  * examples.gui.Calculator$OverflowException: Overflow
139  * Sequence: [4, 8, ÷, 1, 4, +, +, 6, −, 1, ÷, 3, ×, 6, 3, ., 1, ×, ., ×, 0, −, ÷, 7, −, +, 6, 4, 4, 6, =, 3, 8, 2, ×, +, 6, +, 2, ÷, 9, 5, ÷, +, 9, 6, 9, 8, 8, 2, 1, 3, 6, 9, =]
140  * ÷×3×64=2×69÷=
141  * 48÷133104369
142  * Sequence: [4, 8, ÷, 1, 3, 3, 1, 0, 4, 3, 6, 9, =]
143  * 80=
144  * 13=
145  * 40=
146  * 83=
147  * 84=
148  * 4÷334=
149  * 48316=
150  * 41346=
151  * ÷3049=
152  * 48÷13=
153  * 48÷33043=
154  * 48131043
155  * Sequence: [4, 8, 1, 3, 1, 0, 4, 3, =]
156  * 3=
157  * 8=
158  * 34
159  * 4=
160  * 1=
161  * 830=
162  * 343=
163  * 404=
164  * 403=
165  * 403=
166  * 13103=
167  * 41304=
168  * 43104=
169  * 81310=
170  * 48314=
171  * 481310438=
172  * 4=
173  * 4=
174  * 1=
175  * 3=
176  * 413=
177  * 430=
178  * 131=
179  * 103=
180  * 480=
181  * 13143=
182  * 48104=
183  * 41304=
184  * 41314=
185  * 83103=
186  * 481310434=
187  * 4=
188  * 40
189  * 1=
190  * 3=
191  * 1310
192  * 114=
193  * 313=
194  * 414=
195  * 133=
196  * 41104=
197  * 41314=
198  * 41343=
199  * 13104=
200  * 13143=
201  * 48131043
202  * Found a examples.gui.Calculator$OverflowException: Overflow
203  * Sequence : [4, 8, 1, 3, 1, 0, 4, 3, =]
204  * </pre>
205  *
206  * <a name="divzero"></a><h4>Division by zero</h4>
207  *
208  * The last type of error is a division by zero, which produces an execution
209  * like the following:
210  * <pre>
211  * Attempt 0
212  * 48÷14++6−1÷3×63.1×.×0−÷7−+6446=382×+6+2÷95÷+9698821369=5855÷35−91.2=437.+9−62542×7×6993×0526501=6.×2
213  * Attempt 1
214  * 73222+×9÷+542×÷−=÷×9.974500÷=0+2627+×1+0÷5=93÷850.16+6+÷.
215  * java.lang.IllegalArgumentException: Division by zero
216  * Sequence: [7, 3, 2, 2, 2, +, ×, 9, ÷, +, 5, 4, 2, ×, ÷, −, =, ÷, ×, 9, ., 9, 7, 4, 5, 0, 0, ÷, =, 0, +, 2, 6, 2, 7, +, ×, 1, +, 0, ÷, 5, =, 9, 3, ÷, 8, 5, 0, ., 1, 6, +, 6, +, ÷, ., ×]
217  * 2×÷÷.
218  * Sequence: [2, ×, ÷, ÷, ., ÷, 0, 2, +, ×, +, =, 3, ×]
219  * 2÷×
220  * 2+×
221  * 2=×
222  * 2=×
223  * ÷÷×
224  * ×.÷++3×
225  * 2×÷÷2××
226  * 2÷÷0
227  * Sequence: [2, ÷, ÷, 0, +, =, ×]
228  * ×
229  * 0
230  * ×
231  * ×
232  * ×
233  * 2÷×
234  * 2=×
235  * 2=×
236  * ÷+×
237  * ÷+×
238  * 2÷+=×
239  * 2÷0
240  * Sequence: [2, ÷, 0, +, ×]
241  * +
242  * +
243  * ×
244  * ×
245  * ×
246  * 2÷
247  * 2÷
248  * +×
249  * 2×
250  * 2×
251  * 0+×
252  * 2÷×
253  * 0+×
254  * 0+×
255  * 0+×
256  * 2÷0×
257  * 2
258  * ×
259  * 0
260  * 2
261  * 0×
262  * 0×
263  * +×
264  * +×
265  * +×
266  * ÷+×
267  * 2+×
268  * 2+×
269  * 2+×
270  * ÷0
271  * Sequence: [÷, 0, ×]
272  *
273  * Found a java.lang.IllegalArgumentException: Division by zero
274  * Sequence : [÷, 0, ×]
275  * </pre>
276  * Note how, again, the monkey zeroes in on the shortest possible sequence that
277  * triggers the error (division, zero, followed by any operator).
278  *
279  * @author Sylvain Hallé
280  */
281 public class CalculatorMonkey
282 {
283  public static void main(String[] args)
284  {
285  RandomFloat rf = new RandomFloat().setSeed(50000);
287  Choice<Action> actions = new Choice<Action>(rf);
288  for (String label : Calculator.BUTTON_LABELS)
289  {
290  actions.add(new WidgetAction.ClickAction(window.getButton(label)), 1f / 16);
291  }
292  RandomFloat b_rf = new BiasedRandomFloat(2).setSeed(0);
293  Monkey m = new Monkey(window, actions, b_rf, System.out);
294  window.setVisible(true);
295  if (m.check())
296  {
297  System.out.println("No error found");
298  }
299  else
300  {
301  System.out.println("Found a " + m.getException());
302  System.out.println("Sequence : " + m.getShrunk());
303  }
304  }
305 }
examples.gui.WidgetAction
A Action that performs a concrete action on a widget.
Definition: WidgetAction.java:39
ca.uqac.lif.synthia.util
Miscellaneous pickers performing various functions.
Definition: ArrayPicker.java:19
ca.uqac.lif.synthia.test.Monkey
Performs monkey testing by interacting with a component.
Definition: Monkey.java:54
examples.gui.Calculator.disableNumberFormatException
Calculator disableNumberFormatException()
Instructs the calculator to check the format of numbers and ignore parsing errors.
Definition: Calculator.java:129
examples.gui.Calculator
A simple calculator.
Definition: Calculator.java:62
ca.uqac.lif.synthia.test.Monkey.check
boolean check()
Definition: Monkey.java:138
ca.uqac
ca.uqac.lif.synthia.random
Pickers that produce pseudo-random objects such as numbers.
Definition: AffineTransform.java:19
ca.uqac.lif.synthia
Definition: Bounded.java:19
examples.gui.WidgetAction.ClickAction
Action that clicks on a specific button when called.
Definition: WidgetAction.java:79
ca.uqac.lif.synthia.random.BiasedRandomFloat
Generates pseudo-random floating-point numbers in the interval [0,1], but according to a probability ...
Definition: BiasedRandomFloat.java:33
ca.uqac.lif.synthia.random.RandomFloat.setSeed
RandomFloat setSeed(int seed)
Definition: RandomFloat.java:85
ca.uqac.lif
ca.uqac.lif.synthia.util.Choice.add
Choice< T > add(ProbabilityChoice< T > pc)
Adds an object-probability association.
Definition: Choice.java:72
examples.gui.CalculatorMonkey.main
static void main(String[] args)
Definition: CalculatorMonkey.java:283
ca
ca.uqac.lif.synthia.test.Action
Interface signaling that an object can perform an "action".
Definition: Action.java:27
ca.uqac.lif.synthia.test
Classes that enable Synthia to operate as a fuzz testing tool.
Definition: Action.java:19
examples.gui.CalculatorMonkey
Performs monkey testing over a simple calculator, using Synthia's Monkey.
Definition: CalculatorMonkey.java:281
examples.gui.Calculator.hasOverflow
Calculator hasOverflow()
Instructs the calculator to throw an OverflowException when producing a number over 100,...
Definition: Calculator.java:118
ca.uqac.lif.synthia.random.RandomFloat
Picks a floating point number uniformly in an interval.
Definition: RandomFloat.java:30
ca.uqac.lif.synthia.test.Monkey.getShrunk
List< Action > getShrunk()
Definition: Monkey.java:221
ca.uqac.lif.synthia.test.Monkey.getException
Exception getException()
Definition: Monkey.java:216
ca.uqac.lif.synthia.util.Choice
Picks an element from a collection, where the probability of picking each element can be user-defined...
Definition: Choice.java:44
examples.gui.Calculator.getButton
JButton getButton(String label)
Gets the button instance with given label.
Definition: Calculator.java:141
examples.gui.Calculator.BUTTON_LABELS
static final String[] BUTTON_LABELS
The array of button labels.
Definition: Calculator.java:67