logic_check_test.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include "creators.h"
  15. #include <acl/logic_check.h>
  16. #include <typeinfo>
  17. #include <boost/shared_ptr.hpp> // for static_pointer_cast
  18. using namespace std;
  19. using namespace boost;
  20. using namespace isc::acl;
  21. using namespace isc::acl::tests;
  22. using isc::data::Element;
  23. namespace {
  24. // Test the defs in AnyOfSpec
  25. TEST(LogicOperators, AnyOfSpec) {
  26. EXPECT_FALSE(AnyOfSpec::start());
  27. EXPECT_FALSE(AnyOfSpec::terminate(false));
  28. EXPECT_TRUE(AnyOfSpec::terminate(true));
  29. }
  30. // Test the defs in AllOfSpec
  31. TEST(LogicOperators, AllOfSpec) {
  32. EXPECT_TRUE(AllOfSpec::start());
  33. EXPECT_TRUE(AllOfSpec::terminate(false));
  34. EXPECT_FALSE(AllOfSpec::terminate(true));
  35. }
  36. // Generic test of one check
  37. template<typename Mode>
  38. void
  39. testCheck(bool emptyResult) {
  40. // It can be created
  41. LogicOperator<Mode, Log> oper;
  42. // It is empty by default
  43. EXPECT_EQ(0, oper.getSubexpressions().size());
  44. // And returns true, as all 0 of the subexpressions return true
  45. Log log;
  46. EXPECT_EQ(emptyResult, oper.matches(log));
  47. log.checkFirst(0);
  48. // Fill it with some subexpressions
  49. typedef shared_ptr<ConstCheck> CheckPtr;
  50. oper.addSubexpression(CheckPtr(new ConstCheck(emptyResult, 0)));
  51. oper.addSubexpression(CheckPtr(new ConstCheck(emptyResult, 1)));
  52. // Check what happens when only the default-valued are there
  53. EXPECT_EQ(2, oper.getSubexpressions().size());
  54. EXPECT_EQ(emptyResult, oper.matches(log));
  55. log.checkFirst(2);
  56. oper.addSubexpression(CheckPtr(new ConstCheck(!emptyResult, 2)));
  57. oper.addSubexpression(CheckPtr(new ConstCheck(!emptyResult, 3)));
  58. // They are listed there
  59. EXPECT_EQ(4, oper.getSubexpressions().size());
  60. // Now, the last one kills it, but the first ones will run, the fourth
  61. // won't
  62. EXPECT_EQ(!emptyResult, oper.matches(log));
  63. log.checkFirst(3);
  64. }
  65. TEST(LogicOperators, AllOf) {
  66. testCheck<AllOfSpec>(true);
  67. }
  68. TEST(LogicOperators, AnyOf) {
  69. testCheck<AnyOfSpec>(false);
  70. }
  71. // Fixture for the tests of the creators
  72. class LogicCreatorTest : public ::testing::Test {
  73. private:
  74. typedef shared_ptr<Loader<Log>::CheckCreator> CreatorPtr;
  75. public:
  76. // Register some creators, both tested ones and some auxiliary ones for
  77. // help
  78. LogicCreatorTest():
  79. loader_(REJECT)
  80. {
  81. loader_.registerCreator(CreatorPtr(new
  82. LogicCreator<AnyOfSpec, Log>("ANY")));
  83. loader_.registerCreator(CreatorPtr(new
  84. LogicCreator<AllOfSpec, Log>("ALL")));
  85. loader_.registerCreator(CreatorPtr(new ThrowCreator));
  86. loader_.registerCreator(CreatorPtr(new LogCreator));
  87. loader_.registerCreator(CreatorPtr(new NotCreator<Log>("NOT")));
  88. }
  89. // To mark which parts of the check did run
  90. Log log_;
  91. // The loader
  92. Loader<Log> loader_;
  93. // Some convenience shortcut names
  94. typedef LogicOperator<AnyOfSpec, Log> AnyOf;
  95. typedef LogicOperator<AllOfSpec, Log> AllOf;
  96. typedef shared_ptr<AnyOf> AnyOfPtr;
  97. typedef shared_ptr<AllOf> AllOfPtr;
  98. // Loads the JSON as a check and tries to convert it to the given check
  99. // subclass
  100. template<typename Result> shared_ptr<Result> load(const string& JSON) {
  101. shared_ptr<Check<Log> > result;
  102. EXPECT_NO_THROW(result = loader_.loadCheck(Element::fromJSON(JSON)));
  103. /*
  104. * Optimally, we would use a dynamic_pointer_cast here to both
  105. * convert the pointer and to check the type is correct. However,
  106. * clang++ seems to be confused by templates and creates two typeids
  107. * for the same templated type (even with the same parameters),
  108. * therfore considering the types different, even if they are the same.
  109. * This leads to false alarm in the test. Luckily, it generates the
  110. * same name for both typeids, so we use them instead (which is enough
  111. * to test the correct type of Check is returned). Then we can safely
  112. * cast statically, as we don't use any kind of nasty things like
  113. * multiple inheritance.
  114. */
  115. EXPECT_STREQ(typeid(Result).name(), typeid(*result.get()).name());
  116. shared_ptr<Result>
  117. resultConverted(static_pointer_cast<Result>(result));
  118. EXPECT_NE(shared_ptr<Result>(), resultConverted);
  119. return (resultConverted);
  120. }
  121. };
  122. // Test it can load empty ones
  123. TEST_F(LogicCreatorTest, empty) {
  124. AnyOfPtr emptyAny(load<AnyOf>("{\"ANY\": []}"));
  125. EXPECT_EQ(0, emptyAny->getSubexpressions().size());
  126. AllOfPtr emptyAll(load<AllOf>("{\"ALL\": []}"));
  127. EXPECT_EQ(0, emptyAll->getSubexpressions().size());
  128. }
  129. // Test it rejects invalid inputs (not a list as a parameter)
  130. TEST_F(LogicCreatorTest, invalid) {
  131. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": null}")),
  132. LoaderError);
  133. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": {}}")),
  134. LoaderError);
  135. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": true}")),
  136. LoaderError);
  137. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": 42}")),
  138. LoaderError);
  139. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": \"hello\"}")),
  140. LoaderError);
  141. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": null}")),
  142. LoaderError);
  143. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": {}}")),
  144. LoaderError);
  145. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": true}")),
  146. LoaderError);
  147. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": 42}")),
  148. LoaderError);
  149. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": \"hello\"}")),
  150. LoaderError);
  151. }
  152. // Exceptions from subexpression creation isn't caught
  153. TEST_F(LogicCreatorTest, propagate) {
  154. EXPECT_THROW(loader_.loadCheck(
  155. Element::fromJSON("{\"ANY\": [{\"throw\": null}]}")),
  156. TestCreatorError);
  157. EXPECT_THROW(loader_.loadCheck(
  158. Element::fromJSON("{\"ALL\": [{\"throw\": null}]}")),
  159. TestCreatorError);
  160. }
  161. // We can create more complex ANY check and run it correctly
  162. TEST_F(LogicCreatorTest, anyRun) {
  163. AnyOfPtr any(load<AnyOf>("{\"ANY\": ["
  164. " {\"logcheck\": [0, false]},"
  165. " {\"logcheck\": [1, true]},"
  166. " {\"logcheck\": [2, true]}"
  167. "]}"));
  168. EXPECT_EQ(3, any->getSubexpressions().size());
  169. EXPECT_TRUE(any->matches(log_));
  170. log_.checkFirst(2);
  171. }
  172. // We can create more complex ALL check and run it correctly
  173. TEST_F(LogicCreatorTest, allRun) {
  174. AllOfPtr any(load<AllOf>("{\"ALL\": ["
  175. " {\"logcheck\": [0, true]},"
  176. " {\"logcheck\": [1, false]},"
  177. " {\"logcheck\": [2, false]}"
  178. "]}"));
  179. EXPECT_EQ(3, any->getSubexpressions().size());
  180. EXPECT_FALSE(any->matches(log_));
  181. log_.checkFirst(2);
  182. }
  183. // Or is able to return false
  184. TEST_F(LogicCreatorTest, anyFalse) {
  185. AnyOfPtr any(load<AnyOf>("{\"ANY\": ["
  186. " {\"logcheck\": [0, false]},"
  187. " {\"logcheck\": [1, false]},"
  188. " {\"logcheck\": [2, false]}"
  189. "]}"));
  190. EXPECT_EQ(3, any->getSubexpressions().size());
  191. EXPECT_FALSE(any->matches(log_));
  192. log_.checkFirst(3);
  193. }
  194. // And is able to return true
  195. TEST_F(LogicCreatorTest, andTrue) {
  196. AllOfPtr all(load<AllOf>("{\"ALL\": ["
  197. " {\"logcheck\": [0, true]},"
  198. " {\"logcheck\": [1, true]},"
  199. " {\"logcheck\": [2, true]}"
  200. "]}"));
  201. EXPECT_EQ(3, all->getSubexpressions().size());
  202. EXPECT_TRUE(all->matches(log_));
  203. log_.checkFirst(3);
  204. }
  205. // We can nest them together
  206. TEST_F(LogicCreatorTest, nested) {
  207. AllOfPtr all(load<AllOf>("{\"ALL\": ["
  208. " {\"ANY\": ["
  209. " {\"logcheck\": [0, true]},"
  210. " {\"logcheck\": [2, true]},"
  211. " ]},"
  212. " {\"logcheck\": [1, false]}"
  213. "]}"));
  214. EXPECT_EQ(2, all->getSubexpressions().size());
  215. /*
  216. * This has the same problem as load function above, and we use the
  217. * same solution here.
  218. */
  219. ASSERT_STREQ(typeid(LogicOperator<AnyOfSpec, Log>).name(),
  220. typeid(*all->getSubexpressions()[0]).name());
  221. const LogicOperator<AnyOfSpec, Log>*
  222. any(static_cast<const LogicOperator<AnyOfSpec, Log>*>
  223. (all->getSubexpressions()[0]));
  224. EXPECT_EQ(2, any->getSubexpressions().size());
  225. EXPECT_FALSE(all->matches(log_));
  226. log_.checkFirst(2);
  227. }
  228. void notTest(bool value) {
  229. NotOperator<Log> notOp(shared_ptr<Check<Log> >(new ConstCheck(value, 0)));
  230. Log log;
  231. // It returns negated value
  232. EXPECT_EQ(!value, notOp.matches(log));
  233. // And runs the only one thing there
  234. log.checkFirst(1);
  235. // Check the getSubexpressions does sane things
  236. ASSERT_EQ(1, notOp.getSubexpressions().size());
  237. EXPECT_EQ(value, notOp.getSubexpressions()[0]->matches(log));
  238. }
  239. TEST(Not, trueValue) {
  240. notTest(true);
  241. }
  242. TEST(Not, falseValue) {
  243. notTest(false);
  244. }
  245. TEST_F(LogicCreatorTest, notInvalid) {
  246. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"NOT\": null}")),
  247. LoaderError);
  248. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"NOT\": \"hello\"}")),
  249. LoaderError);
  250. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"NOT\": true}")),
  251. LoaderError);
  252. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"NOT\": 42}")),
  253. LoaderError);
  254. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"NOT\": []}")),
  255. LoaderError);
  256. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"NOT\": [{"
  257. "\"logcheck\": [0, true]"
  258. "}]}")),
  259. LoaderError);
  260. }
  261. TEST_F(LogicCreatorTest, notValid) {
  262. shared_ptr<NotOperator<Log> > notOp(load<NotOperator<Log> >("{\"NOT\":"
  263. " {\"logcheck\":"
  264. " [0, true]}}"));
  265. EXPECT_FALSE(notOp->matches(log_));
  266. log_.checkFirst(1);
  267. }
  268. }