00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #ifndef QUICKCHECK_PROPERTY_H
00027 #define QUICKCHECK_PROPERTY_H
00028
00029 #include <algorithm>
00030 #include <iomanip>
00031 #include <iostream>
00032 #include <map>
00033 #include <string>
00034 #include <utility>
00035 #include <vector>
00036
00037 #include "generate.hh"
00038
00039 namespace quickcheck {
00040
00046 enum Unit { UNIT };
00047
00059 template<class A>
00060 void printArgument(std::ostream& out, size_t n, const A& a)
00061 {
00062 out << " " << n << ": " << a << std::endl;
00063 }
00064
00068 template<>
00069 void printArgument(std::ostream&, size_t, const Unit&) { }
00070
00084 template<class A, class B, class C, class D, class E>
00085 class PropertyBase {
00086
00087 public:
00088
00090 explicit PropertyBase();
00091
00093 virtual ~PropertyBase();
00094
00110 bool check(size_t n = 100, size_t max = 0, bool isVerbose = false,
00111 std::ostream& out = std::cout);
00112
00113 protected:
00114
00126 void _addFixed(const A& a, const B& b, const C& c, const D& d,
00127 const E& e);
00128
00129 private:
00130
00135 struct Input {
00136 A a;
00137 B b;
00138 C c;
00139 D d;
00140 E e;
00141 };
00142
00153 void printInput(std::ostream& out, const A& a, const B& b, const C& c,
00154 const D& d, const E& e);
00155
00163 virtual size_t sizeHint(size_t testNo);
00164
00176 virtual bool _accepts(const A& a, const B& b, const C& c, const D& d,
00177 const E& e) = 0;
00178
00190 virtual const std::string _classify(const A& a, const B& b, const C& c,
00191 const D& d, const E& e) = 0;
00192
00203 virtual void _generateInput(size_t n, A& a, B& b, C& c, D& d, E& e) = 0;
00204
00216 virtual bool _holdsFor(const A& a, const B& b, const C& c, const D& d,
00217 const E& e) = 0;
00218
00231 virtual bool _isTrivialFor(const A& a, const B& b, const C& c,
00232 const D& d, const E& e) = 0;
00233
00238 std::vector<Input> _fixedInputs;
00239
00240 };
00241
00242 template<class A, class B, class C, class D, class E>
00243 PropertyBase<A, B, C, D, E>::PropertyBase() :
00244 _fixedInputs(std::vector<Input>())
00245 {
00246
00247 }
00248
00249 template<class A, class B, class C, class D, class E>
00250 PropertyBase<A, B, C, D, E>::~PropertyBase()
00251 {
00252
00253 }
00254
00255 template<class A, class B, class C, class D, class E>
00256 bool PropertyBase<A, B, C, D, E>::check(size_t n, size_t max, bool isVerbose,
00257 std::ostream& out)
00258 {
00259 if (max < n)
00260 max = 5 * n;
00261 size_t nTrivial = 0;
00262
00263
00264 typedef std::map<const std::string, size_t> ClassMap;
00265 ClassMap classes;
00266
00267 size_t len = _fixedInputs.size();
00268 size_t testNo;
00269 for (testNo = 0; testNo < len; ++testNo) {
00270 const Input& input = _fixedInputs[testNo];
00271 if (_isTrivialFor(input.a, input.b, input.c, input.d, input.e))
00272 ++nTrivial;
00273 ++classes[_classify(input.a, input.b, input.c, input.d, input.e)];
00274 if (isVerbose) {
00275 out << "Test " << testNo << ":" << std::endl;
00276 printInput(out, input.a, input.b, input.c, input.d, input.e);
00277 }
00278 if (!_holdsFor(input.a, input.b, input.c, input.d, input.e)) {
00279 out << "Falsifiable after " << testNo + 1 << " tests for input:" <<
00280 std::endl;
00281 printInput(out, input.a, input.b, input.c, input.d, input.e);
00282 return false;
00283 }
00284 }
00285
00286 n += len;
00287 size_t attemptNo;
00288 for (attemptNo = 0; attemptNo < max && testNo < n; ++attemptNo) {
00289
00290
00291
00292 A a;
00293 B b;
00294 C c;
00295 D d;
00296 E e;
00297 _generateInput(sizeHint(testNo - len), a, b, c, d, e);
00298
00299 if (_accepts(a, b, c, d, e)) {
00300 if (_isTrivialFor(a, b, c, d, e))
00301 ++nTrivial;
00302 ++classes[_classify(a, b, c, d, e)];
00303 if (isVerbose) {
00304 out << "Test " << testNo << ":" << std::endl;
00305 printInput(out, a, b, c, d, e);
00306 }
00307 if (!_holdsFor(a, b, c, d, e)) {
00308 out << "Falsifiable after " << testNo + 1 << " tests for input:"
00309 << std::endl;
00310 printInput(out, a, b, c, d, e);
00311 return false;
00312 }
00313 ++testNo;
00314 }
00315 }
00316
00317 if (testNo < n)
00318 out << "Arguments exhausted after ";
00319 else
00320 out << "OK, passed ";
00321 out << testNo << " tests";
00322 if (nTrivial > 0)
00323 out << " (" << nTrivial * 100 / testNo << "% trivial)";
00324 out << "." << std::endl;
00325
00326 classes.erase("");
00327 if (!classes.empty()) {
00328
00329
00330 typedef std::vector< std::pair<size_t, std::string> > ClassVec;
00331 ClassVec sorted;
00332 for (ClassMap::const_iterator i = classes.begin(); i != classes.end();
00333 ++i) {
00334 std::pair<size_t, std::string> elem = make_pair(i->second, i->first);
00335 ClassVec::iterator pos = lower_bound(sorted.begin(), sorted.end(),
00336 elem);
00337 sorted.insert(pos, elem);
00338 }
00339 std::reverse(sorted.begin(), sorted.end());
00340 for (ClassVec::const_iterator i = sorted.begin(); i != sorted.end(); ++i)
00341 out << std::setw(4) << i->first * 100 / testNo << "% " << i->second
00342 << std::endl;
00343 }
00344 return (testNo == n);
00345 }
00346
00347 template<class A, class B, class C, class D, class E>
00348 void PropertyBase<A, B, C, D, E>::_addFixed(const A& a, const B& b, const C& c,
00349 const D& d, const E& e)
00350 {
00351 Input i = { a, b, c, d, e };
00352 _fixedInputs.push_back(i);
00353 }
00354
00355 template<class A, class B, class C, class D, class E>
00356 void PropertyBase<A, B, C, D, E>::printInput(std::ostream& out, const A& a,
00357 const B& b, const C& c,
00358 const D& d, const E& e)
00359 {
00360
00361
00362 printArgument(out, 0, a);
00363 printArgument(out, 1, b);
00364 printArgument(out, 2, c);
00365 printArgument(out, 3, d);
00366 printArgument(out, 4, e);
00367 }
00368
00369 template<class A, class B, class C, class D, class E>
00370 size_t PropertyBase<A, B, C, D, E>::sizeHint(size_t testNo)
00371 {
00372 return testNo / 2 + 3;
00373 }
00374
00402 template<class A, class B = Unit, class C = Unit, class D = Unit,
00403 class E = Unit>
00404 class Property : public PropertyBase<A, B, C, D, E> {
00405
00406 public:
00407
00417 virtual void addFixed(const A& a, const B& b, const C& c, const D& d,
00418 const E& e);
00419
00420 private:
00421
00448 virtual bool accepts(const A& a, const B& b, const C& c, const D& d,
00449 const E& e);
00450
00466 virtual const std::string classify(const A& a, const B& b, const C& c,
00467 const D& d, const E& e);
00468
00493 virtual void generateInput(size_t n, A& a, B& b, C& c, D& d, E& e);
00494
00511 virtual bool holdsFor(const A& a, const B& b, const C& c, const D& d,
00512 const E& e) = 0;
00513
00531 virtual bool isTrivialFor(const A& a, const B& b, const C& c, const D& d,
00532 const E& e);
00533
00534 bool _accepts(const A& a, const B& b, const C& c, const D& d,
00535 const E& e);
00536
00537 const std::string _classify(const A& a, const B& b, const C& c,
00538 const D& d, const E& e);
00539
00540 void _generateInput(size_t n, A& a, B& b, C& c, D& d, E& e);
00541
00542 bool _holdsFor(const A& a, const B& b, const C& c, const D& d,
00543 const E& e);
00544
00545 bool _isTrivialFor(const A& a, const B& b, const C& c, const D& d,
00546 const E& e);
00547
00548 };
00549
00550 template<class A, class B, class C, class D, class E>
00551 void Property<A, B, C, D, E>::addFixed(const A& a, const B& b, const C& c,
00552 const D& d, const E& e)
00553 {
00554 _addFixed(a, b, c, d, e);
00555 }
00556
00557 template<class A, class B, class C, class D, class E>
00558 bool Property<A, B, C, D, E>::accepts(const A&, const B&, const C&, const D&,
00559 const E&)
00560 {
00561 return true;
00562 }
00563
00564 template<class A, class B, class C, class D, class E>
00565 const std::string Property<A, B, C, D, E>::classify(
00566 const A&, const B&, const C&, const D&, const E&)
00567 {
00568 return "";
00569 }
00570
00571 template<class A, class B, class C, class D, class E>
00572 void Property<A, B, C, D, E>::generateInput(size_t n,
00573 A& a, B& b, C& c, D& d, E& e)
00574 {
00575 generate(n, a);
00576 generate(n, b);
00577 generate(n, c);
00578 generate(n, d);
00579 generate(n, e);
00580 }
00581
00582 template<class A, class B, class C, class D, class E>
00583 bool Property<A, B, C, D, E>::isTrivialFor(const A&, const B&, const C&,
00584 const D&, const E&)
00585 {
00586 return false;
00587 }
00588
00589 template<class A, class B, class C, class D, class E>
00590 bool Property<A, B, C, D, E>::_accepts(const A& a, const B& b, const C& c,
00591 const D& d, const E& e)
00592 {
00593 return accepts(a, b, c, d, e);
00594 }
00595
00596 template<class A, class B, class C, class D, class E>
00597 const std::string Property<A, B, C, D, E>::_classify(
00598 const A& a, const B& b, const C& c, const D& d, const E& e)
00599 {
00600 return classify(a, b, c, d, e);
00601 }
00602
00603 template<class A, class B, class C, class D, class E>
00604 void Property<A, B, C, D, E>::_generateInput(size_t n,
00605 A& a, B& b, C& c, D& d, E& e)
00606 {
00607 generateInput(n, a, b, c, d, e);
00608 }
00609
00610 template<class A, class B, class C, class D, class E>
00611 bool Property<A, B, C, D, E>::_holdsFor(const A& a, const B& b, const C& c,
00612 const D& d, const E& e)
00613 {
00614 return holdsFor(a, b, c, d, e);
00615 }
00616
00617 template<class A, class B, class C, class D, class E>
00618 bool Property<A, B, C, D, E>::_isTrivialFor(const A& a, const B& b, const C& c,
00619 const D& d, const E& e)
00620 {
00621 return isTrivialFor(a, b, c, d, e);
00622 }
00623
00633 template<class A, class B, class C, class D>
00634 class Property<A, B, C, D> : public PropertyBase<A, B, C, D, Unit> {
00635
00636 public:
00637
00648 virtual void addFixed(const A& a, const B& b, const C& c, const D& d);
00649
00650 private:
00651
00662 virtual bool accepts(const A& a, const B& b, const C& c, const D& d);
00663
00674 virtual const std::string classify(const A& a, const B& b, const C& c,
00675 const D& d);
00676
00688 virtual void generateInput(size_t n, A& a, B& b, C& c, D& d);
00689
00700 virtual bool holdsFor(const A& a, const B& b, const C& c, const D& d)
00701 = 0;
00702
00713 virtual bool isTrivialFor(const A& a, const B& b, const C& c,
00714 const D& d);
00715
00716 bool _accepts(const A& a, const B& b, const C& c, const D& d,
00717 const Unit& e);
00718
00719 const std::string _classify(const A& a, const B& b, const C& c,
00720 const D& d, const Unit& e);
00721
00722 void _generateInput(size_t n, A& a, B& b, C& c, D& d, Unit& e);
00723
00724 bool _holdsFor(const A& a, const B& b, const C& c, const D& d,
00725 const Unit& e);
00726
00727 bool _isTrivialFor(const A& a, const B& b, const C& c, const D& d,
00728 const Unit& e);
00729
00730 };
00731
00732 template<class A, class B, class C, class D>
00733 void Property<A, B, C, D>::addFixed(const A& a, const B& b, const C& c,
00734 const D& d)
00735 {
00736 _addFixed(a, b, c, d, UNIT);
00737 }
00738
00739 template<class A, class B, class C, class D>
00740 bool Property<A, B, C, D>::accepts(const A&, const B&, const C&, const D&)
00741 {
00742 return true;
00743 }
00744
00745 template<class A, class B, class C, class D>
00746 const std::string Property<A, B, C, D>::classify(const A&, const B&, const C&,
00747 const D&)
00748 {
00749 return "";
00750 }
00751
00752 template<class A, class B, class C, class D>
00753 void Property<A, B, C, D>::generateInput(size_t n, A& a, B& b, C& c, D& d)
00754 {
00755 generate(n, a);
00756 generate(n, b);
00757 generate(n, c);
00758 generate(n, d);
00759 }
00760
00761 template<class A, class B, class C, class D>
00762 bool Property<A, B, C, D>::isTrivialFor(const A&, const B&, const C&,
00763 const D&)
00764 {
00765 return false;
00766 }
00767
00768 template<class A, class B, class C, class D>
00769 bool Property<A, B, C, D>::_accepts(const A& a, const B& b, const C& c,
00770 const D& d, const Unit&)
00771 {
00772 return accepts(a, b, c, d);
00773 }
00774
00775 template<class A, class B, class C, class D>
00776 const std::string Property<A, B, C, D>::_classify(
00777 const A& a, const B& b, const C& c, const D& d, const Unit&)
00778 {
00779 return classify(a, b, c, d);
00780 }
00781
00782 template<class A, class B, class C, class D>
00783 void Property<A, B, C, D>::_generateInput(size_t n, A& a, B& b, C& c, D& d,
00784 Unit&)
00785 {
00786 generateInput(n, a, b, c, d);
00787 }
00788
00789 template<class A, class B, class C, class D>
00790 bool Property<A, B, C, D>::_holdsFor(const A& a, const B& b, const C& c,
00791 const D& d, const Unit&)
00792 {
00793 return holdsFor(a, b, c, d);
00794 }
00795
00796 template<class A, class B, class C, class D>
00797 bool Property<A, B, C, D>::_isTrivialFor(const A& a, const B& b, const C& c,
00798 const D& d, const Unit&)
00799 {
00800 return isTrivialFor(a, b, c, d);
00801 }
00802
00811 template<class A, class B, class C>
00812 class Property<A, B, C> : public PropertyBase<A, B, C, Unit, Unit> {
00813
00814 public:
00815
00825 virtual void addFixed(const A& a, const B& b, const C& c);
00826
00827 private:
00828
00838 virtual bool accepts(const A& a, const B& b, const C& c);
00839
00849 virtual const std::string classify(const A& a, const B& b, const C& c);
00850
00861 virtual void generateInput(size_t n, A& a, B& b, C& c);
00862
00872 virtual bool holdsFor(const A& a, const B& b, const C& c) = 0;
00873
00883 virtual bool isTrivialFor(const A& a, const B& b, const C& c);
00884
00885 bool _accepts(const A& a, const B& b, const C& c, const Unit& d,
00886 const Unit& e);
00887
00888 const std::string _classify(const A& a, const B& b, const C& c,
00889 const Unit& d, const Unit& e);
00890
00891 void _generateInput(size_t n, A& a, B& b, C& c, Unit& d, Unit& e);
00892
00893 bool _holdsFor(const A& a, const B& b, const C& c, const Unit& d,
00894 const Unit& e);
00895
00896 bool _isTrivialFor(const A& a, const B& b, const C& c, const Unit& d,
00897 const Unit& e);
00898
00899 };
00900
00901 template<class A, class B, class C>
00902 void Property<A, B, C>::addFixed(const A& a, const B& b, const C& c)
00903 {
00904 _addFixed(a, b, c, UNIT, UNIT);
00905 }
00906
00907 template<class A, class B, class C>
00908 bool Property<A, B, C>::accepts(const A&, const B&, const C&)
00909 {
00910 return true;
00911 }
00912
00913 template<class A, class B, class C>
00914 const std::string Property<A, B, C>::classify(const A&, const B&, const C&)
00915 {
00916 return "";
00917 }
00918
00919 template<class A, class B, class C>
00920 void Property<A, B, C>::generateInput(size_t n, A& a, B& b, C& c)
00921 {
00922 generate(n, a);
00923 generate(n, b);
00924 generate(n, c);
00925 }
00926
00927 template<class A, class B, class C>
00928 bool Property<A, B, C>::isTrivialFor(const A&, const B&, const C&)
00929 {
00930 return false;
00931 }
00932
00933 template<class A, class B, class C>
00934 bool Property<A, B, C>::_accepts(const A& a, const B& b, const C& c,
00935 const Unit&, const Unit&)
00936 {
00937 return accepts(a, b, c);
00938 }
00939
00940 template<class A, class B, class C>
00941 const std::string Property<A, B, C>::_classify(
00942 const A& a, const B& b, const C& c, const Unit&, const Unit&)
00943 {
00944 return classify(a, b, c);
00945 }
00946
00947 template<class A, class B, class C>
00948 void Property<A, B, C>::_generateInput(size_t n, A& a, B& b, C& c, Unit&,
00949 Unit&)
00950 {
00951 generateInput(n, a, b, c);
00952 }
00953
00954 template<class A, class B, class C>
00955 bool Property<A, B, C>::_holdsFor(const A& a, const B& b, const C& c,
00956 const Unit&, const Unit&)
00957 {
00958 return holdsFor(a, b, c);
00959 }
00960
00961 template<class A, class B, class C>
00962 bool Property<A, B, C>::_isTrivialFor(const A& a, const B& b, const C& c,
00963 const Unit&, const Unit&)
00964 {
00965 return isTrivialFor(a, b, c);
00966 }
00967
00975 template<class A, class B>
00976 class Property<A, B> : public PropertyBase<A, B, Unit, Unit, Unit> {
00977
00978 public:
00979
00988 virtual void addFixed(const A& a, const B& b);
00989
00990 private:
00991
01000 virtual bool accepts(const A& a, const B& b);
01001
01010 virtual const std::string classify(const A& a, const B& b);
01011
01021 virtual void generateInput(size_t n, A& a, B& b);
01022
01031 virtual bool holdsFor(const A& a, const B& b) = 0;
01032
01041 virtual bool isTrivialFor(const A& a, const B& b);
01042
01043 bool _accepts(const A& a, const B& b, const Unit& c, const Unit& d,
01044 const Unit& e);
01045
01046 const std::string _classify(const A& a, const B& b, const Unit& c,
01047 const Unit& d, const Unit& e);
01048
01049 void _generateInput(size_t n, A& a, B& b, Unit& c, Unit& d, Unit& e);
01050
01051 bool _holdsFor(const A& a, const B& b, const Unit& c, const Unit& d,
01052 const Unit& e);
01053
01054 bool _isTrivialFor(const A& a, const B& b, const Unit& c, const Unit& d,
01055 const Unit& e);
01056
01057 };
01058
01059 template<class A, class B>
01060 void Property<A, B>::addFixed(const A& a, const B& b)
01061 {
01062 _addFixed(a, b, UNIT, UNIT, UNIT);
01063 }
01064
01065 template<class A, class B>
01066 bool Property<A, B>::accepts(const A&, const B&)
01067 {
01068 return true;
01069 }
01070
01071 template<class A, class B>
01072 const std::string Property<A, B>::classify(const A&, const B&)
01073 {
01074 return "";
01075 }
01076
01077 template<class A, class B>
01078 void Property<A, B>::generateInput(size_t n, A& a, B& b)
01079 {
01080 generate(n, a);
01081 generate(n, b);
01082 }
01083
01084 template<class A, class B>
01085 bool Property<A, B>::isTrivialFor(const A&, const B&)
01086 {
01087 return false;
01088 }
01089
01090 template<class A, class B>
01091 bool Property<A, B>::_accepts(const A& a, const B& b, const Unit&,
01092 const Unit&, const Unit&)
01093 {
01094 return accepts(a, b);
01095 }
01096
01097 template<class A, class B>
01098 const std::string Property<A, B>::_classify(
01099 const A& a, const B& b, const Unit&, const Unit&, const Unit&)
01100 {
01101 return classify(a, b);
01102 }
01103
01104 template<class A, class B>
01105 void Property<A, B>::_generateInput(size_t n, A& a, B& b, Unit&, Unit&, Unit&)
01106 {
01107 generateInput(n, a, b);
01108 }
01109
01110 template<class A, class B>
01111 bool Property<A, B>::_holdsFor(const A& a, const B& b, const Unit&,
01112 const Unit&, const Unit&)
01113 {
01114 return holdsFor(a, b);
01115 }
01116
01117 template<class A, class B>
01118 bool Property<A, B>::_isTrivialFor(const A& a, const B& b, const Unit&,
01119 const Unit&, const Unit&)
01120 {
01121 return isTrivialFor(a, b);
01122 }
01123
01130 template<class A>
01131 class Property<A> : public PropertyBase<A, Unit, Unit, Unit, Unit> {
01132
01133 public:
01134
01142 virtual void addFixed(const A& a);
01143
01144 private:
01145
01153 virtual bool accepts(const A& a);
01154
01162 virtual const std::string classify(const A& a);
01163
01172 virtual void generateInput(size_t n, A& a);
01173
01181 virtual bool holdsFor(const A& a) = 0;
01182
01190 virtual bool isTrivialFor(const A& a);
01191
01192 bool _accepts(const A& a, const Unit& b, const Unit& c, const Unit& d,
01193 const Unit& e);
01194
01195 const std::string _classify(const A& a, const Unit& b, const Unit& c,
01196 const Unit& d, const Unit& e);
01197
01198 void _generateInput(size_t n, A& a, Unit& b, Unit& c, Unit& d, Unit& e);
01199
01200 bool _holdsFor(const A& a, const Unit& b, const Unit& c, const Unit& d,
01201 const Unit& e);
01202
01203 bool _isTrivialFor(const A& a, const Unit& b, const Unit& c,
01204 const Unit& d, const Unit& e);
01205
01206 };
01207
01208 template<class A>
01209 void Property<A>::addFixed(const A& a)
01210 {
01211 _addFixed(a, UNIT, UNIT, UNIT, UNIT);
01212 }
01213
01214 template<class A>
01215 bool Property<A>::accepts(const A&)
01216 {
01217 return true;
01218 }
01219
01220 template<class A>
01221 const std::string Property<A>::classify(const A&)
01222 {
01223 return "";
01224 }
01225
01226 template<class A>
01227 void Property<A>::generateInput(size_t n, A& a)
01228 {
01229 generate(n, a);
01230 }
01231
01232 template<class A>
01233 bool Property<A>::isTrivialFor(const A&)
01234 {
01235 return false;
01236 }
01237
01238 template<class A>
01239 bool Property<A>::_accepts(const A& a, const Unit&, const Unit&, const Unit&,
01240 const Unit&)
01241 {
01242 return accepts(a);
01243 }
01244
01245 template<class A>
01246 const std::string Property<A>::_classify(const A& a, const Unit&, const Unit&,
01247 const Unit&, const Unit&)
01248 {
01249 return classify(a);
01250 }
01251
01252 template<class A>
01253 void Property<A>::_generateInput(size_t n, A& a, Unit&, Unit&, Unit&, Unit&)
01254 {
01255 generateInput(n, a);
01256 }
01257
01258 template<class A>
01259 bool Property<A>::_holdsFor(const A& a, const Unit&, const Unit&, const Unit&,
01260 const Unit&)
01261 {
01262 return holdsFor(a);
01263 }
01264
01265 template<class A>
01266 bool Property<A>::_isTrivialFor(const A& a, const Unit&, const Unit&,
01267 const Unit&, const Unit&)
01268 {
01269 return isTrivialFor(a);
01270 }
01271
01272 }
01273
01274 #endif // !QUICKCHECK_PROPERTY_H