logic_check_test.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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. }
  88. // To mark which parts of the check did run
  89. Log log_;
  90. // The loader
  91. Loader<Log> loader_;
  92. // Some convenience shortcut names
  93. typedef LogicOperator<AnyOfSpec, Log> AnyOf;
  94. typedef LogicOperator<AllOfSpec, Log> AllOf;
  95. typedef shared_ptr<AnyOf> AnyOfPtr;
  96. typedef shared_ptr<AllOf> AllOfPtr;
  97. // Loads the JSON as a check and tries to convert it to the given check
  98. // subclass
  99. template<typename Result> shared_ptr<Result> load(const string& JSON) {
  100. shared_ptr<Check<Log> > result;
  101. EXPECT_NO_THROW(result = loader_.loadCheck(Element::fromJSON(JSON)));
  102. /*
  103. * Optimally, we would use a dynamic_pointer_cast here to both
  104. * convert the pointer and to check the type is correct. However,
  105. * clang++ seems to be confused by templates and creates two typeids
  106. * for the same templated type (even with the same parameters),
  107. * therfore considering the types different, even if they are the same.
  108. * This leads to false alarm in the test. Luckily, it generates the
  109. * same name for both typeids, so we use them instead (which is enough
  110. * to test the correct type of Check is returned). Then we can safely
  111. * cast statically, as we don't use any kind of nasty things like
  112. * multiple inheritance.
  113. */
  114. EXPECT_STREQ(typeid(Result).name(), typeid(*result.get()).name());
  115. shared_ptr<Result>
  116. resultConverted(static_pointer_cast<Result>(result));
  117. EXPECT_NE(shared_ptr<Result>(), resultConverted);
  118. return (resultConverted);
  119. }
  120. };
  121. // Test it can load empty ones
  122. TEST_F(LogicCreatorTest, empty) {
  123. AnyOfPtr emptyAny(load<AnyOf>("{\"ANY\": []}"));
  124. EXPECT_EQ(0, emptyAny->getSubexpressions().size());
  125. AllOfPtr emptyAll(load<AllOf>("{\"ALL\": []}"));
  126. EXPECT_EQ(0, emptyAll->getSubexpressions().size());
  127. }
  128. // Test it rejects invalid inputs (not a list as a parameter)
  129. TEST_F(LogicCreatorTest, invalid) {
  130. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": null}")),
  131. LoaderError);
  132. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": {}}")),
  133. LoaderError);
  134. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": true}")),
  135. LoaderError);
  136. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": 42}")),
  137. LoaderError);
  138. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ANY\": \"hello\"}")),
  139. LoaderError);
  140. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": null}")),
  141. LoaderError);
  142. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": {}}")),
  143. LoaderError);
  144. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": true}")),
  145. LoaderError);
  146. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": 42}")),
  147. LoaderError);
  148. EXPECT_THROW(loader_.loadCheck(Element::fromJSON("{\"ALL\": \"hello\"}")),
  149. LoaderError);
  150. }
  151. // Exceptions from subexpression creation isn't caught
  152. TEST_F(LogicCreatorTest, propagate) {
  153. EXPECT_THROW(loader_.loadCheck(
  154. Element::fromJSON("{\"ANY\": [{\"throw\": null}]}")),
  155. TestCreatorError);
  156. EXPECT_THROW(loader_.loadCheck(
  157. Element::fromJSON("{\"ALL\": [{\"throw\": null}]}")),
  158. TestCreatorError);
  159. }
  160. // We can create more complex ANY check and run it correctly
  161. TEST_F(LogicCreatorTest, anyRun) {
  162. AnyOfPtr any(load<AnyOf>("{\"ANY\": ["
  163. " {\"logcheck\": [0, false]},"
  164. " {\"logcheck\": [1, true]},"
  165. " {\"logcheck\": [2, true]}"
  166. "]}"));
  167. EXPECT_EQ(3, any->getSubexpressions().size());
  168. EXPECT_TRUE(any->matches(log_));
  169. log_.checkFirst(2);
  170. }
  171. // We can create more complex ALL check and run it correctly
  172. TEST_F(LogicCreatorTest, allRun) {
  173. AllOfPtr any(load<AllOf>("{\"ALL\": ["
  174. " {\"logcheck\": [0, true]},"
  175. " {\"logcheck\": [1, false]},"
  176. " {\"logcheck\": [2, false]}"
  177. "]}"));
  178. EXPECT_EQ(3, any->getSubexpressions().size());
  179. EXPECT_FALSE(any->matches(log_));
  180. log_.checkFirst(2);
  181. }
  182. // Or is able to return false
  183. TEST_F(LogicCreatorTest, anyFalse) {
  184. AnyOfPtr any(load<AnyOf>("{\"ANY\": ["
  185. " {\"logcheck\": [0, false]},"
  186. " {\"logcheck\": [1, false]},"
  187. " {\"logcheck\": [2, false]}"
  188. "]}"));
  189. EXPECT_EQ(3, any->getSubexpressions().size());
  190. EXPECT_FALSE(any->matches(log_));
  191. log_.checkFirst(3);
  192. }
  193. // And is able to return true
  194. TEST_F(LogicCreatorTest, andTrue) {
  195. AllOfPtr all(load<AllOf>("{\"ALL\": ["
  196. " {\"logcheck\": [0, true]},"
  197. " {\"logcheck\": [1, true]},"
  198. " {\"logcheck\": [2, true]}"
  199. "]}"));
  200. EXPECT_EQ(3, all->getSubexpressions().size());
  201. EXPECT_TRUE(all->matches(log_));
  202. log_.checkFirst(3);
  203. }
  204. // We can nest them together
  205. TEST_F(LogicCreatorTest, nested) {
  206. AllOfPtr all(load<AllOf>("{\"ALL\": ["
  207. " {\"ANY\": ["
  208. " {\"logcheck\": [0, true]},"
  209. " {\"logcheck\": [2, true]},"
  210. " ]},"
  211. " {\"logcheck\": [1, false]}"
  212. "]}"));
  213. EXPECT_EQ(2, all->getSubexpressions().size());
  214. /*
  215. * This has the same problem as load function above, and we use the
  216. * same solution here.
  217. */
  218. ASSERT_STREQ(typeid(LogicOperator<AnyOfSpec, Log>).name(),
  219. typeid(*all->getSubexpressions()[0]).name());
  220. const LogicOperator<AnyOfSpec, Log>*
  221. any(static_cast<const LogicOperator<AnyOfSpec, Log>*>
  222. (all->getSubexpressions()[0]));
  223. EXPECT_EQ(2, any->getSubexpressions().size());
  224. EXPECT_FALSE(all->matches(log_));
  225. log_.checkFirst(2);
  226. }
  227. }