Synthia
Generic and flexible data structure generator
Sort.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.quickcheck;
20 
21 import java.util.Collections;
22 import java.util.List;
23 
27 import ca.uqac.lif.synthia.test.Assert;
28 
29 /**
30  * Illustrates the shrinking process when testing a procedure that sorts lists
31  * of numbers. In this example, a generator produces random lists of up to
32  * 1,000 elements, each having a value between 0 and 999. Each list is passed
33  * to {@link FaultySort#sort(List)}, and an assertion checks that the resulting
34  * list is indeed sorted. The {@link FaultySort} class contains a deliberately
35  * injected fault, such that any list where the sum of elements at indices 3
36  * and 4 is greater than 500 is incorrectly sorted (the two elements are
37  * swapped in the output).
38  * <p>
39  * After finding a first randomly generated list revealing the fault, the
40  * {@link Assert} object will ask for a shrunk picker and repeat the process,
41  * eventually finding shorter lists with smaller values that also reveal the
42  * fault. You can try running the program multiple times; this will produce
43  * different inputs. One can observe that the number of shrinking steps depends
44  * on the starting seed. However, most of the time, the list that is found is
45  * of minimal length (i.e. 5).
46  * <p>
47  * A typical output of the program looks like this:
48  * <pre>
49  * Assertion is false
50  * [931, 520, 668, 369, 906, 823, 468, 145, 623, 702, 691, 52, 963, 339, 722, 434, 901, 590, 111, 734, 104, 694, 200, 871, 211, 311, 820, 856, 382, 724, 390] produces [52, 104, 111, 200, 145, 211, 311, 339, 369, 382, 390, 434, 468, 520, 590, 623, 668, 691, 694, 702, 722, 724, 734, 820, 823, 856, 871, 901, 906, 931, 963] and is not sorted
51  * 25 shrinking steps
52  * [0, 28, 35, 725, 419] produces [0, 28, 35, 725, 419] and is also not sorted
53  * </pre>
54  *
55  * @ingroup Examples
56  * @author Sylvain Hallé
57  */
58 public class Sort
59 {
60  public static void main(String[] args)
61  {
62  FaultySort<Integer> fs = new FaultySort<Integer>();
64  new ComposeList<Integer>(new RandomInteger(0, 1000), new RandomInteger(0, 2000))) {
65  protected boolean evaluate(List<Integer> x) {
66  return isSorted(fs.sort(x));
67  }
68  };
69  if (!a.check())
70  {
71  System.out.println("Assertion is false");
72  System.out.println(a.getInitial() + " produces " + fs.sort(a.getInitial()) + " and is not sorted");
73  System.out.println(a.getIterations().size() + " shrinking steps");
74  System.out.println(a.getShrunk() + " produces " + fs.sort(a.getShrunk()) + " and is also not sorted");
75  }
76  }
77 
78  /**
79  * A deliberately faulty implementation of insertion sort.
80  *
81  * @param <T>
82  */
83  protected static class FaultySort<T>
84  {
85  @SuppressWarnings("unchecked")
86  public List<T> sort(List<T> list)
87  {
88  ComparableList<T> ini_list = new ComparableList<T>();
89  ComparableList<T> new_list = new ComparableList<T>();
90  ini_list.addAll(list);
91  for (int i = 0; i < list.size(); i++)
92  {
93  int index_to_remove = -1;
94  T to_insert = null;
95  for (int j = 0; j < ini_list.size(); j++)
96  {
97  T e = ini_list.get(j);
98  if (to_insert == null)
99  {
100  to_insert = e;
101  index_to_remove = j;
102  }
103  else
104  {
105  if (to_insert instanceof Comparable)
106  {
107  int value = ((Comparable<T>) to_insert).compareTo(e);
108  if (value > 0)
109  {
110  to_insert = e;
111  index_to_remove = j;
112  }
113  }
114  }
115  }
116  new_list.add(to_insert);
117  ini_list.remove(index_to_remove);
118  }
119  // This part below is the injection of a fault in the sorting
120  if (list.size() > 4 && ((int) list.get(3)) + ((int) list.get(4)) > 1000)
121  {
122  Collections.swap(new_list, 3, 4);
123  }
124  return new_list;
125  }
126  }
127 
128  @SuppressWarnings("unchecked")
129  public static boolean isSorted(List<?> list)
130  {
131  for (int i = 0; i < list.size() - 1; i++)
132  {
133  Object o1 = list.get(i);
134  Object o2 = list.get(i + 1);
135  if (o1 instanceof Comparable)
136  {
137  if (((Comparable<Object>) o1).compareTo(o2) > 0)
138  {
139  return false;
140  }
141  }
142  else
143  {
144  return false;
145  }
146  }
147  return true;
148  }
149 }
examples.quickcheck.Sort.main
static void main(String[] args)
Definition: Sort.java:60
ca.uqac.lif.synthia.collection
Pickers generating and manipulating collections, such as lists and sets.
Definition: ComparableList.java:19
ca.uqac.lif.synthia.collection.ComparableList.compareTo
int compareTo(List< T > o)
Public method to compare a list to the reference one.
Definition: ComparableList.java:67
ca.uqac.lif.synthia.test.Assert.check
boolean check()
Definition: Assert.java:87
ca.uqac.lif.synthia.collection.ComparableList
Class that extends Java's ArrayList class to implements the Comparable interface.
Definition: ComparableList.java:31
ca.uqac
ca.uqac.lif.synthia.random
Pickers that produce pseudo-random objects such as numbers.
Definition: AffineTransform.java:19
examples.quickcheck.Sort.isSorted
static boolean isSorted(List<?> list)
Definition: Sort.java:129
ca.uqac.lif.synthia
Definition: Bounded.java:19
ca.uqac.lif.synthia.test.Assert.getIterations
List< T > getIterations()
Definition: Assert.java:63
ca.uqac.lif.synthia.test.Assert.getInitial
T getInitial()
Definition: Assert.java:68
ca.uqac.lif
ca.uqac.lif.synthia.test.Assert.getShrunk
T getShrunk()
Definition: Assert.java:77
ca.uqac.lif.synthia.test.Assert
Definition: Assert.java:36
ca.uqac.lif.synthia.random.RandomInteger
Picks an integer uniformly in an interval.
Definition: RandomInteger.java:31
ca
ca.uqac.lif.synthia.test
Classes that enable Synthia to operate as a fuzz testing tool.
Definition: Action.java:19
ca.uqac.lif.synthia.collection.ComposeList
Definition: ComposeList.java:44
examples.quickcheck.Sort
Illustrates the shrinking process when testing a procedure that sorts lists of numbers.
Definition: Sort.java:58