Synthia
Generic and flexible data structure generator
Monkey.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 ca.uqac.lif.synthia.test;
20 
21 import java.io.PrintStream;
22 import java.util.ArrayList;
23 import java.util.List;
24 
25 import ca.uqac.lif.synthia.Picker;
29 import ca.uqac.lif.synthia.util.Delay;
30 
31 /**
32  * Performs <a href="https://en.wikipedia.org/wiki/Monkey_testing">monkey
33  * testing</a> by interacting with a component. The monkey works as
34  * follows:
35  * <ol>
36  * <li>The monkey starts with a <em>discovery phase</em>. It uses a
37  * <tt>Picker&lt;Action&gt;</tt> as a source of actions to be
38  * performed on the component. Actions provided by this picker are
39  * executed one by one.</li>
40  * <li>Exceptions that may be thrown resulting from each action are trapped.
41  * As soon as an exception is caught, the sequence of actions performed so
42  * far is stored.</li>
43  * <li>The monkey then enters in a <em>shrinking phase</em>, where shorter
44  * sub-traces of the original are repeatedly generated and tested. Whenever
45  * a shorter sequence still throws an exception, this sequence replaces the
46  * original, and the shrinking process restarts from this new reference.</li>
47  * </ol>
48  * What the "component" can be is totally abstract. All the monkey expects
49  * is that it implements the {@link Resettable} interface. A typical component
50  * is a graphical user interface (such as a {@link JFrame}),
51  *
52  * @author Sylvain Hallé
53  */
54 public class Monkey
55 {
56  /**
57  * The maximum number of shrinking phases the monkey will attempt.
58  */
59  protected static final int s_maxShrinkingPhases = 5;
60 
61  /**
62  * The maximum number of attempts at producing a sequence in each
63  * shrinking phase.
64  */
65  protected static final int s_maxTries = 5;
66 
67  /**
68  * The picker producing the actions to be applied.
69  */
71 
72  /**
73  * The object on which the actions are applied.
74  */
75  protected Resettable m_object;
76 
77  /**
78  * The "best" sequence of actions found by the monkey so far.
79  */
80  protected List<Action> m_bestSequence;
81 
82  /**
83  * The exception thrown at the end of the "best" sequence of actions found
84  * by the monkey so far.
85  */
86  protected Exception m_lastException;
87 
88  /**
89  * A picker passed to the action picker for the shrinking process.
90  */
92 
93  /**
94  * A print stream where the monkey outputs status messages during its
95  * execution.
96  */
97  protected PrintStream m_out;
98 
99  /**
100  * The length of the sequence under which the monkey is allowed to stop
101  * searching.
102  */
103  protected int m_bestThreshold;
104 
105  /**
106  * Creates a new instance of the monkey.
107  * @param object The object on which the actions are applied
108  * @param actions The picker producing the actions to be applied
109  * @param decision A picker passed to the action picker for the
110  * shrinking process
111  * @param ps A print stream where the monkey outputs status messages during
112  * its execution. Set it to <tt>null</tt> to disable messages.
113  */
114  public Monkey(Resettable object, Picker<Action> actions, Picker<Float> decision, PrintStream ps)
115  {
116  super();
117  m_object = object;
118  m_actionPicker = actions;
119  m_decision = decision;
120  m_bestSequence = new ArrayList<Action>();
121  m_out = ps;
122  m_bestThreshold = 4;
123  m_lastException = null;
124  }
125 
126  /**
127  * Creates a new instance of the monkey.
128  * @param object The object on which the actions are applied
129  * @param actions The picker producing the actions to be applied
130  * @param decision A picker passed to the action picker for the
131  * shrinking process
132  */
133  public Monkey(Resettable object, Picker<Action> actions, Picker<Float> decision)
134  {
135  this(object, actions, decision, null);
136  }
137 
138  public boolean check()
139  {
140  boolean error_found = false;
142  for (int try_counter = 0; try_counter < s_maxTries; try_counter++)
143  {
144  println("Attempt " + try_counter);
145  try
146  {
147  for (int i = 0; i < 100; i++)
148  {
149  Action a = rec.pick();
150  a.doAction();
151  print(a);
152  //Delay.wait(0.005f); // Give time for the object to reset itself
153  }
154  println("");
155  }
156  catch (Exception e)
157  {
158  // Exception thrown
159  print("\n" + e);
160  error_found = true;
161  m_bestSequence = rec.getSequence();
162  println("\nSequence: " + m_bestSequence);
163  break;
164  }
165  rec.clear();
166  }
167  SequenceShrinkable<Action> reference = rec;
168  for (int shrinking_steps = 0; m_bestSequence.size() > m_bestThreshold && shrinking_steps < s_maxShrinkingPhases; shrinking_steps++)
169  {
170  boolean shrink_again = false;
171  for (float magnitude = 0.25f; m_bestSequence.size() > m_bestThreshold && !shrink_again && magnitude <= 1; magnitude += 0.25)
172  {
173  Exception last_ex = null;
174  for (int i = 0; i < s_maxTries; i++)
175  {
176  SequenceShrinkable<Action> to_try = reference.shrink(m_decision, magnitude);
177  boolean success = false;
178  m_object.reset();
179  Delay.wait(0.25f); // Give time for the object to reset itself
180  while (!to_try.isDone())
181  {
182  try
183  {
184  Action a = to_try.pick();
185  a.doAction();
186  print(a);
187  //Delay.wait(0.005f); // Give time for the object to reset itself
188  }
189  catch (Exception e)
190  {
191  success = true;
192  last_ex = e;
193  break;
194  }
195  }
196  if (success)
197  {
198  reference = to_try;
199  if (m_bestSequence == null || to_try.getSequence().size() < m_bestSequence.size())
200  {
201  m_bestSequence = to_try.getSequence();
202  println("\nSequence: " + m_bestSequence);
203  m_lastException = last_ex;
204  }
205  shrink_again = true;
206  break;
207  }
208  println("");
209  }
210  }
211  }
212  println("");
213  return !error_found;
214  }
215 
216  public Exception getException()
217  {
218  return m_lastException;
219  }
220 
221  public List<Action> getShrunk()
222  {
223  return m_bestSequence;
224  }
225 
226  /**
227  * Prints a message to the print stream.
228  * @param message The message
229  */
230  protected void print(Object message)
231  {
232  if (m_out != null)
233  {
234  m_out.print(message);
235  }
236  }
237 
238  /**
239  * Prints a message to the print stream.
240  * @param message The message
241  */
242  protected void println(Object message)
243  {
244  if (m_out != null)
245  {
246  m_out.println(message);
247  }
248  }
249 }
ca.uqac.lif.synthia.Picker
Picks an object.
Definition: Picker.java:36
ca.uqac.lif.synthia.sequence.Record
Picker that records and returns the values produced by another picker.
Definition: Record.java:49
ca.uqac.lif.synthia.test.Monkey.m_decision
Picker< Float > m_decision
A picker passed to the action picker for the shrinking process.
Definition: Monkey.java:91
ca.uqac.lif.synthia.test.Monkey.Monkey
Monkey(Resettable object, Picker< Action > actions, Picker< Float > decision)
Creates a new instance of the monkey.
Definition: Monkey.java:133
ca.uqac.lif.synthia.test.Monkey.m_bestThreshold
int m_bestThreshold
The length of the sequence under which the monkey is allowed to stop searching.
Definition: Monkey.java:103
ca.uqac.lif.synthia.util
Miscellaneous pickers performing various functions.
Definition: ArrayPicker.java:19
ca.uqac.lif.synthia.Resettable
Signals that an object can be put back into its initial state.
Definition: Resettable.java:27
ca.uqac.lif.synthia.test.Monkey
Performs monkey testing by interacting with a component.
Definition: Monkey.java:54
ca.uqac.lif.synthia.Bounded.isDone
boolean isDone()
Signals if the picker enumerates all values from a set.
ca.uqac.lif.synthia.Resettable.reset
void reset()
Puts the object back into its initial state.
ca.uqac.lif.synthia.test.Monkey.check
boolean check()
Definition: Monkey.java:138
ca.uqac.lif.synthia.SequenceShrinkable
Signals that a picker can shrink the sequence of values it has produced since its last reset.
Definition: SequenceShrinkable.java:47
ca.uqac
ca.uqac.lif.synthia.test.Monkey.m_object
Resettable m_object
The object on which the actions are applied.
Definition: Monkey.java:75
ca.uqac.lif.synthia
Definition: Bounded.java:19
ca.uqac.lif.synthia.test.Monkey.Monkey
Monkey(Resettable object, Picker< Action > actions, Picker< Float > decision, PrintStream ps)
Creates a new instance of the monkey.
Definition: Monkey.java:114
ca.uqac.lif.synthia.test.Monkey.m_actionPicker
Picker< Action > m_actionPicker
The picker producing the actions to be applied.
Definition: Monkey.java:70
ca.uqac.lif.synthia.util.Delay.wait
static void wait(float duration)
Waits for some time.
Definition: Delay.java:68
ca.uqac.lif.synthia.test.Monkey.m_out
PrintStream m_out
A print stream where the monkey outputs status messages during its execution.
Definition: Monkey.java:97
ca.uqac.lif.synthia.util.Delay
Picker that does not produce any value, but causes the thread to wait for a moment on every call to p...
Definition: Delay.java:28
ca.uqac.lif.synthia.test.Monkey.m_lastException
Exception m_lastException
The exception thrown at the end of the "best" sequence of actions found by the monkey so far.
Definition: Monkey.java:86
ca.uqac.lif
ca.uqac.lif.synthia.test.Action.doAction
void doAction()
Performs an action on a component.
ca.uqac.lif.synthia.sequence.Record.pick
T pick()
Picks a value, records it and returns the value.
Definition: Record.java:108
ca.uqac.lif.synthia.sequence.Record.clear
void clear()
Clears the values recorded so far.
Definition: Record.java:81
ca.uqac.lif.synthia.test.Monkey.m_bestSequence
List< Action > m_bestSequence
The "best" sequence of actions found by the monkey so far.
Definition: Monkey.java:80
ca
ca.uqac.lif.synthia.Picker.pick
T pick()
Picks an object.
ca.uqac.lif.synthia.test.Action
Interface signaling that an object can perform an "action".
Definition: Action.java:27
ca.uqac.lif.synthia.SequenceShrinkable.shrink
SequenceShrinkable< T > shrink(Picker< Float > d, float magnitude)
Shrinks a picker.
ca.uqac.lif.synthia.test.Monkey.getShrunk
List< Action > getShrunk()
Definition: Monkey.java:221
ca.uqac.lif.synthia.test.Monkey.println
void println(Object message)
Prints a message to the print stream.
Definition: Monkey.java:242
ca.uqac.lif.synthia.sequence.Record.getSequence
List< T > getSequence()
Gets the sequence of values that the picker has produced so far.
Definition: Record.java:203
ca.uqac.lif.synthia.test.Monkey.getException
Exception getException()
Definition: Monkey.java:216
ca.uqac.lif.synthia.test.Monkey.s_maxShrinkingPhases
static final int s_maxShrinkingPhases
The maximum number of shrinking phases the monkey will attempt.
Definition: Monkey.java:59
ca.uqac.lif.synthia.test.Monkey.print
void print(Object message)
Prints a message to the print stream.
Definition: Monkey.java:230
ca.uqac.lif.synthia.SequenceShrinkable.getSequence
List< T > getSequence()
Gets the sequence of values that the picker has produced so far.
ca.uqac.lif.synthia.sequence
Pickers related to the generation of a sequence of values.
Definition: BehaviorTree.java:19
ca.uqac.lif.synthia.test.Monkey.s_maxTries
static final int s_maxTries
The maximum number of attempts at producing a sequence in each shrinking phase.
Definition: Monkey.java:65