QuickCheck++  0.0.3
Automated testing library
Property.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009-2012 Cyril Soldani
3  *
4  * This file is part of QuickCheck++.
5  *
6  * QuickCheck++ is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * QuickCheck++ is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * QuickCheck++. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
26 #ifndef QUICKCHECK_PROPERTY_H
27 #define QUICKCHECK_PROPERTY_H
28 
29 #include <algorithm>
30 #include <iomanip>
31 #include <iostream>
32 #include <map>
33 #include <string>
34 #include <utility>
35 #include <vector>
36 
37 #include "generate.hh"
38 
39 namespace quickcheck {
40 
46 enum Unit { UNIT };
47 
59 template<class A>
60 void printArgument(std::ostream& out, size_t n, const A& a)
61 {
62  out << " " << n << ": " << a << std::endl;
63 }
64 
68 template<>
69 void printArgument(std::ostream&, size_t, const Unit&) { }
70 
84 template<class A, class B, class C, class D, class E>
85 class PropertyBase {
86 
87  public:
88 
90  explicit PropertyBase();
91 
93  virtual ~PropertyBase();
94 
110  bool check(size_t n = 100, size_t max = 0, bool isVerbose = false,
111  std::ostream& out = std::cout);
112 
113  protected:
114 
126  void _addFixed(const A& a, const B& b, const C& c, const D& d,
127  const E& e);
128 
129  private:
130 
135  struct Input {
136  A a;
137  B b;
138  C c;
139  D d;
140  E e;
141  };
142 
153  void printInput(std::ostream& out, const A& a, const B& b, const C& c,
154  const D& d, const E& e);
155 
163  virtual size_t sizeHint(size_t testNo);
164 
176  virtual bool _accepts(const A& a, const B& b, const C& c, const D& d,
177  const E& e) = 0;
178 
190  virtual const std::string _classify(const A& a, const B& b, const C& c,
191  const D& d, const E& e) = 0;
192 
203  virtual void _generateInput(size_t n, A& a, B& b, C& c, D& d, E& e) = 0;
204 
216  virtual bool _holdsFor(const A& a, const B& b, const C& c, const D& d,
217  const E& e) = 0;
218 
231  virtual bool _isTrivialFor(const A& a, const B& b, const C& c,
232  const D& d, const E& e) = 0;
233 
238  std::vector<Input> _fixedInputs;
239 
240 };
241 
242 template<class A, class B, class C, class D, class E>
244  _fixedInputs(std::vector<Input>())
245 {
246  // Nothing more to do than what was done in initialisation list
247 }
248 
249 template<class A, class B, class C, class D, class E>
251 {
252  // Nothing to do, only defined for derivation purpose
253 }
254 
255 template<class A, class B, class C, class D, class E>
256 bool PropertyBase<A, B, C, D, E>::check(size_t n, size_t max, bool isVerbose,
257  std::ostream& out)
258 {
259  if (max < n)
260  max = 5 * n;
261  size_t nTrivial = 0;
262  // ClassMap maps input classes to the number of their occurrence in the
263  // tests
264  typedef std::map<const std::string, size_t> ClassMap;
265  ClassMap classes;
266  // First verifies fixed inputs
267  size_t len = _fixedInputs.size();
268  size_t testNo;
269  for (testNo = 0; testNo < len; ++testNo) {
270  const Input& input = _fixedInputs[testNo];
271  if (_isTrivialFor(input.a, input.b, input.c, input.d, input.e))
272  ++nTrivial;
273  ++classes[_classify(input.a, input.b, input.c, input.d, input.e)];
274  if (isVerbose) {
275  out << "Test " << testNo << ":" << std::endl;
276  printInput(out, input.a, input.b, input.c, input.d, input.e);
277  }
278  if (!_holdsFor(input.a, input.b, input.c, input.d, input.e)) {
279  out << "Falsifiable after " << testNo + 1 << " tests for input:" <<
280  std::endl;
281  printInput(out, input.a, input.b, input.c, input.d, input.e);
282  return false;
283  }
284  }
285  // And now the random tests
286  n += len;
287  size_t attemptNo;
288  for (attemptNo = 0; attemptNo < max && testNo < n; ++attemptNo) {
289  // Generates random arguments (that may or may not form valid input).
290  // Size hint is random test number, so that we begin with small values
291  // before going on with larger values.
292  A a;
293  B b;
294  C c;
295  D d;
296  E e;
297  _generateInput(sizeHint(testNo - len), a, b, c, d, e);
298  // Only do the test if generated input is valid
299  if (_accepts(a, b, c, d, e)) {
300  if (_isTrivialFor(a, b, c, d, e))
301  ++nTrivial;
302  ++classes[_classify(a, b, c, d, e)];
303  if (isVerbose) {
304  out << "Test " << testNo << ":" << std::endl;
305  printInput(out, a, b, c, d, e);
306  }
307  if (!_holdsFor(a, b, c, d, e)) {
308  out << "Falsifiable after " << testNo + 1 << " tests for input:"
309  << std::endl;
310  printInput(out, a, b, c, d, e);
311  return false;
312  }
313  ++testNo;
314  }
315  }
316  // Prints summary results
317  if (testNo < n)
318  out << "Arguments exhausted after ";
319  else
320  out << "OK, passed ";
321  out << testNo << " tests";
322  if (nTrivial > 0)
323  out << " (" << nTrivial * 100 / testNo << "% trivial)";
324  out << "." << std::endl;
325  // Prints input distribution if necessary
326  classes.erase("");
327  if (!classes.empty()) {
328  // We sort input classes by number of occurrences by building a sorted
329  // vector of (occurrences, class) from the class map
330  typedef std::vector< std::pair<size_t, std::string> > ClassVec;
331  ClassVec sorted;
332  for (ClassMap::const_iterator i = classes.begin(); i != classes.end();
333  ++i) {
334  std::pair<size_t, std::string> elem = make_pair(i->second, i->first);
335  ClassVec::iterator pos = lower_bound(sorted.begin(), sorted.end(),
336  elem);
337  sorted.insert(pos, elem);
338  }
339  std::reverse(sorted.begin(), sorted.end());
340  for (ClassVec::const_iterator i = sorted.begin(); i != sorted.end(); ++i)
341  out << std::setw(4) << i->first * 100 / testNo << "% " << i->second
342  << std::endl;
343  }
344  return (testNo == n);
345 }
346 
347 template<class A, class B, class C, class D, class E>
348 void PropertyBase<A, B, C, D, E>::_addFixed(const A& a, const B& b, const C& c,
349  const D& d, const E& e)
350 {
351  Input i = { a, b, c, d, e };
352  _fixedInputs.push_back(i);
353 }
354 
355 template<class A, class B, class C, class D, class E>
356 void PropertyBase<A, B, C, D, E>::printInput(std::ostream& out, const A& a,
357  const B& b, const C& c,
358  const D& d, const E& e)
359 {
360  // We call printArgument for all arguments as it should print nothing when
361  // given UNIT
362  printArgument(out, 0, a);
363  printArgument(out, 1, b);
364  printArgument(out, 2, c);
365  printArgument(out, 3, d);
366  printArgument(out, 4, e);
367 }
368 
369 template<class A, class B, class C, class D, class E>
371 {
372  return testNo / 2 + 3;
373 }
374 
402 template<class A, class B = Unit, class C = Unit, class D = Unit,
403  class E = Unit>
404 class Property : public PropertyBase<A, B, C, D, E> {
405 
406  public:
407 
417  virtual void addFixed(const A& a, const B& b, const C& c, const D& d,
418  const E& e);
419 
420  private:
421 
448  virtual bool accepts(const A& a, const B& b, const C& c, const D& d,
449  const E& e);
450 
466  virtual const std::string classify(const A& a, const B& b, const C& c,
467  const D& d, const E& e);
468 
493  virtual void generateInput(size_t n, A& a, B& b, C& c, D& d, E& e);
494 
511  virtual bool holdsFor(const A& a, const B& b, const C& c, const D& d,
512  const E& e) = 0;
513 
531  virtual bool isTrivialFor(const A& a, const B& b, const C& c, const D& d,
532  const E& e);
533 
534  bool _accepts(const A& a, const B& b, const C& c, const D& d,
535  const E& e);
536 
537  const std::string _classify(const A& a, const B& b, const C& c,
538  const D& d, const E& e);
539 
540  void _generateInput(size_t n, A& a, B& b, C& c, D& d, E& e);
541 
542  bool _holdsFor(const A& a, const B& b, const C& c, const D& d,
543  const E& e);
544 
545  bool _isTrivialFor(const A& a, const B& b, const C& c, const D& d,
546  const E& e);
547 
548 };
549 
550 template<class A, class B, class C, class D, class E>
551 void Property<A, B, C, D, E>::addFixed(const A& a, const B& b, const C& c,
552  const D& d, const E& e)
553 {
554  this->_addFixed(a, b, c, d, e);
555 }
556 
557 template<class A, class B, class C, class D, class E>
558 bool Property<A, B, C, D, E>::accepts(const A&, const B&, const C&, const D&,
559  const E&)
560 {
561  return true;
562 }
563 
564 template<class A, class B, class C, class D, class E>
566  const A&, const B&, const C&, const D&, const E&)
567 {
568  return "";
569 }
570 
571 template<class A, class B, class C, class D, class E>
573  A& a, B& b, C& c, D& d, E& e)
574 {
575  generate(n, a);
576  generate(n, b);
577  generate(n, c);
578  generate(n, d);
579  generate(n, e);
580 }
581 
582 template<class A, class B, class C, class D, class E>
583 bool Property<A, B, C, D, E>::isTrivialFor(const A&, const B&, const C&,
584  const D&, const E&)
585 {
586  return false;
587 }
588 
589 template<class A, class B, class C, class D, class E>
590 bool Property<A, B, C, D, E>::_accepts(const A& a, const B& b, const C& c,
591  const D& d, const E& e)
592 {
593  return accepts(a, b, c, d, e);
594 }
595 
596 template<class A, class B, class C, class D, class E>
598  const A& a, const B& b, const C& c, const D& d, const E& e)
599 {
600  return classify(a, b, c, d, e);
601 }
602 
603 template<class A, class B, class C, class D, class E>
605  A& a, B& b, C& c, D& d, E& e)
606 {
607  generateInput(n, a, b, c, d, e);
608 }
609 
610 template<class A, class B, class C, class D, class E>
611 bool Property<A, B, C, D, E>::_holdsFor(const A& a, const B& b, const C& c,
612  const D& d, const E& e)
613 {
614  return holdsFor(a, b, c, d, e);
615 }
616 
617 template<class A, class B, class C, class D, class E>
618 bool Property<A, B, C, D, E>::_isTrivialFor(const A& a, const B& b, const C& c,
619  const D& d, const E& e)
620 {
621  return isTrivialFor(a, b, c, d, e);
622 }
623 
633 template<class A, class B, class C, class D>
634 class Property<A, B, C, D> : public PropertyBase<A, B, C, D, Unit> {
635 
636  public:
637 
648  virtual void addFixed(const A& a, const B& b, const C& c, const D& d);
649 
650  private:
651 
662  virtual bool accepts(const A& a, const B& b, const C& c, const D& d);
663 
674  virtual const std::string classify(const A& a, const B& b, const C& c,
675  const D& d);
676 
688  virtual void generateInput(size_t n, A& a, B& b, C& c, D& d);
689 
700  virtual bool holdsFor(const A& a, const B& b, const C& c, const D& d)
701  = 0;
702 
713  virtual bool isTrivialFor(const A& a, const B& b, const C& c,
714  const D& d);
715 
716  bool _accepts(const A& a, const B& b, const C& c, const D& d,
717  const Unit& e);
718 
719  const std::string _classify(const A& a, const B& b, const C& c,
720  const D& d, const Unit& e);
721 
722  void _generateInput(size_t n, A& a, B& b, C& c, D& d, Unit& e);
723 
724  bool _holdsFor(const A& a, const B& b, const C& c, const D& d,
725  const Unit& e);
726 
727  bool _isTrivialFor(const A& a, const B& b, const C& c, const D& d,
728  const Unit& e);
729 
730 };
731 
732 template<class A, class B, class C, class D>
733 void Property<A, B, C, D>::addFixed(const A& a, const B& b, const C& c,
734  const D& d)
735 {
736  this->_addFixed(a, b, c, d, UNIT);
737 }
738 
739 template<class A, class B, class C, class D>
740 bool Property<A, B, C, D>::accepts(const A&, const B&, const C&, const D&)
741 {
742  return true;
743 }
744 
745 template<class A, class B, class C, class D>
746 const std::string Property<A, B, C, D>::classify(const A&, const B&, const C&,
747  const D&)
748 {
749  return "";
750 }
751 
752 template<class A, class B, class C, class D>
753 void Property<A, B, C, D>::generateInput(size_t n, A& a, B& b, C& c, D& d)
754 {
755  generate(n, a);
756  generate(n, b);
757  generate(n, c);
758  generate(n, d);
759 }
760 
761 template<class A, class B, class C, class D>
762 bool Property<A, B, C, D>::isTrivialFor(const A&, const B&, const C&,
763  const D&)
764 {
765  return false;
766 }
767 
768 template<class A, class B, class C, class D>
769 bool Property<A, B, C, D>::_accepts(const A& a, const B& b, const C& c,
770  const D& d, const Unit&)
771 {
772  return accepts(a, b, c, d);
773 }
774 
775 template<class A, class B, class C, class D>
777  const A& a, const B& b, const C& c, const D& d, const Unit&)
778 {
779  return classify(a, b, c, d);
780 }
781 
782 template<class A, class B, class C, class D>
783 void Property<A, B, C, D>::_generateInput(size_t n, A& a, B& b, C& c, D& d,
784  Unit&)
785 {
786  generateInput(n, a, b, c, d);
787 }
788 
789 template<class A, class B, class C, class D>
790 bool Property<A, B, C, D>::_holdsFor(const A& a, const B& b, const C& c,
791  const D& d, const Unit&)
792 {
793  return holdsFor(a, b, c, d);
794 }
795 
796 template<class A, class B, class C, class D>
797 bool Property<A, B, C, D>::_isTrivialFor(const A& a, const B& b, const C& c,
798  const D& d, const Unit&)
799 {
800  return isTrivialFor(a, b, c, d);
801 }
802 
811 template<class A, class B, class C>
812 class Property<A, B, C> : public PropertyBase<A, B, C, Unit, Unit> {
813 
814  public:
815 
825  virtual void addFixed(const A& a, const B& b, const C& c);
826 
827  private:
828 
838  virtual bool accepts(const A& a, const B& b, const C& c);
839 
849  virtual const std::string classify(const A& a, const B& b, const C& c);
850 
861  virtual void generateInput(size_t n, A& a, B& b, C& c);
862 
872  virtual bool holdsFor(const A& a, const B& b, const C& c) = 0;
873 
883  virtual bool isTrivialFor(const A& a, const B& b, const C& c);
884 
885  bool _accepts(const A& a, const B& b, const C& c, const Unit& d,
886  const Unit& e);
887 
888  const std::string _classify(const A& a, const B& b, const C& c,
889  const Unit& d, const Unit& e);
890 
891  void _generateInput(size_t n, A& a, B& b, C& c, Unit& d, Unit& e);
892 
893  bool _holdsFor(const A& a, const B& b, const C& c, const Unit& d,
894  const Unit& e);
895 
896  bool _isTrivialFor(const A& a, const B& b, const C& c, const Unit& d,
897  const Unit& e);
898 
899 };
900 
901 template<class A, class B, class C>
902 void Property<A, B, C>::addFixed(const A& a, const B& b, const C& c)
903 {
904  this->_addFixed(a, b, c, UNIT, UNIT);
905 }
906 
907 template<class A, class B, class C>
908 bool Property<A, B, C>::accepts(const A&, const B&, const C&)
909 {
910  return true;
911 }
912 
913 template<class A, class B, class C>
914 const std::string Property<A, B, C>::classify(const A&, const B&, const C&)
915 {
916  return "";
917 }
918 
919 template<class A, class B, class C>
920 void Property<A, B, C>::generateInput(size_t n, A& a, B& b, C& c)
921 {
922  generate(n, a);
923  generate(n, b);
924  generate(n, c);
925 }
926 
927 template<class A, class B, class C>
928 bool Property<A, B, C>::isTrivialFor(const A&, const B&, const C&)
929 {
930  return false;
931 }
932 
933 template<class A, class B, class C>
934 bool Property<A, B, C>::_accepts(const A& a, const B& b, const C& c,
935  const Unit&, const Unit&)
936 {
937  return accepts(a, b, c);
938 }
939 
940 template<class A, class B, class C>
942  const A& a, const B& b, const C& c, const Unit&, const Unit&)
943 {
944  return classify(a, b, c);
945 }
946 
947 template<class A, class B, class C>
948 void Property<A, B, C>::_generateInput(size_t n, A& a, B& b, C& c, Unit&,
949  Unit&)
950 {
951  generateInput(n, a, b, c);
952 }
953 
954 template<class A, class B, class C>
955 bool Property<A, B, C>::_holdsFor(const A& a, const B& b, const C& c,
956  const Unit&, const Unit&)
957 {
958  return holdsFor(a, b, c);
959 }
960 
961 template<class A, class B, class C>
962 bool Property<A, B, C>::_isTrivialFor(const A& a, const B& b, const C& c,
963  const Unit&, const Unit&)
964 {
965  return isTrivialFor(a, b, c);
966 }
967 
975 template<class A, class B>
976 class Property<A, B> : public PropertyBase<A, B, Unit, Unit, Unit> {
977 
978  public:
979 
988  virtual void addFixed(const A& a, const B& b);
989 
990  private:
991 
1000  virtual bool accepts(const A& a, const B& b);
1001 
1010  virtual const std::string classify(const A& a, const B& b);
1011 
1021  virtual void generateInput(size_t n, A& a, B& b);
1022 
1031  virtual bool holdsFor(const A& a, const B& b) = 0;
1032 
1041  virtual bool isTrivialFor(const A& a, const B& b);
1042 
1043  bool _accepts(const A& a, const B& b, const Unit& c, const Unit& d,
1044  const Unit& e);
1045 
1046  const std::string _classify(const A& a, const B& b, const Unit& c,
1047  const Unit& d, const Unit& e);
1048 
1049  void _generateInput(size_t n, A& a, B& b, Unit& c, Unit& d, Unit& e);
1050 
1051  bool _holdsFor(const A& a, const B& b, const Unit& c, const Unit& d,
1052  const Unit& e);
1053 
1054  bool _isTrivialFor(const A& a, const B& b, const Unit& c, const Unit& d,
1055  const Unit& e);
1056 
1057 };
1058 
1059 template<class A, class B>
1060 void Property<A, B>::addFixed(const A& a, const B& b)
1061 {
1062  this->_addFixed(a, b, UNIT, UNIT, UNIT);
1063 }
1064 
1065 template<class A, class B>
1066 bool Property<A, B>::accepts(const A&, const B&)
1067 {
1068  return true;
1069 }
1070 
1071 template<class A, class B>
1072 const std::string Property<A, B>::classify(const A&, const B&)
1073 {
1074  return "";
1075 }
1076 
1077 template<class A, class B>
1078 void Property<A, B>::generateInput(size_t n, A& a, B& b)
1079 {
1080  generate(n, a);
1081  generate(n, b);
1082 }
1083 
1084 template<class A, class B>
1085 bool Property<A, B>::isTrivialFor(const A&, const B&)
1086 {
1087  return false;
1088 }
1089 
1090 template<class A, class B>
1091 bool Property<A, B>::_accepts(const A& a, const B& b, const Unit&,
1092  const Unit&, const Unit&)
1093 {
1094  return accepts(a, b);
1095 }
1096 
1097 template<class A, class B>
1098 const std::string Property<A, B>::_classify(
1099  const A& a, const B& b, const Unit&, const Unit&, const Unit&)
1100 {
1101  return classify(a, b);
1102 }
1103 
1104 template<class A, class B>
1105 void Property<A, B>::_generateInput(size_t n, A& a, B& b, Unit&, Unit&, Unit&)
1106 {
1107  generateInput(n, a, b);
1108 }
1109 
1110 template<class A, class B>
1111 bool Property<A, B>::_holdsFor(const A& a, const B& b, const Unit&,
1112  const Unit&, const Unit&)
1113 {
1114  return holdsFor(a, b);
1115 }
1116 
1117 template<class A, class B>
1118 bool Property<A, B>::_isTrivialFor(const A& a, const B& b, const Unit&,
1119  const Unit&, const Unit&)
1120 {
1121  return isTrivialFor(a, b);
1122 }
1123 
1130 template<class A>
1131 class Property<A> : public PropertyBase<A, Unit, Unit, Unit, Unit> {
1132 
1133  public:
1134 
1142  virtual void addFixed(const A& a);
1143 
1144  private:
1145 
1153  virtual bool accepts(const A& a);
1154 
1162  virtual const std::string classify(const A& a);
1163 
1172  virtual void generateInput(size_t n, A& a);
1173 
1181  virtual bool holdsFor(const A& a) = 0;
1182 
1190  virtual bool isTrivialFor(const A& a);
1191 
1192  bool _accepts(const A& a, const Unit& b, const Unit& c, const Unit& d,
1193  const Unit& e);
1194 
1195  const std::string _classify(const A& a, const Unit& b, const Unit& c,
1196  const Unit& d, const Unit& e);
1197 
1198  void _generateInput(size_t n, A& a, Unit& b, Unit& c, Unit& d, Unit& e);
1199 
1200  bool _holdsFor(const A& a, const Unit& b, const Unit& c, const Unit& d,
1201  const Unit& e);
1202 
1203  bool _isTrivialFor(const A& a, const Unit& b, const Unit& c,
1204  const Unit& d, const Unit& e);
1205 
1206 };
1207 
1208 template<class A>
1209 void Property<A>::addFixed(const A& a)
1210 {
1211  this->_addFixed(a, UNIT, UNIT, UNIT, UNIT);
1212 }
1213 
1214 template<class A>
1215 bool Property<A>::accepts(const A&)
1216 {
1217  return true;
1218 }
1219 
1220 template<class A>
1221 const std::string Property<A>::classify(const A&)
1222 {
1223  return "";
1224 }
1225 
1226 template<class A>
1227 void Property<A>::generateInput(size_t n, A& a)
1228 {
1229  generate(n, a);
1230 }
1231 
1232 template<class A>
1234 {
1235  return false;
1236 }
1237 
1238 template<class A>
1239 bool Property<A>::_accepts(const A& a, const Unit&, const Unit&, const Unit&,
1240  const Unit&)
1241 {
1242  return accepts(a);
1243 }
1244 
1245 template<class A>
1246 const std::string Property<A>::_classify(const A& a, const Unit&, const Unit&,
1247  const Unit&, const Unit&)
1248 {
1249  return classify(a);
1250 }
1251 
1252 template<class A>
1253 void Property<A>::_generateInput(size_t n, A& a, Unit&, Unit&, Unit&, Unit&)
1254 {
1255  generateInput(n, a);
1256 }
1257 
1258 template<class A>
1259 bool Property<A>::_holdsFor(const A& a, const Unit&, const Unit&, const Unit&,
1260  const Unit&)
1261 {
1262  return holdsFor(a);
1263 }
1264 
1265 template<class A>
1266 bool Property<A>::_isTrivialFor(const A& a, const Unit&, const Unit&,
1267  const Unit&, const Unit&)
1268 {
1269  return isTrivialFor(a);
1270 }
1271 
1272 }
1273 
1274 #endif // !QUICKCHECK_PROPERTY_H