PageRenderTime 39ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llcommon/tests/lldependencies_test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 292 lines | 176 code | 18 blank | 98 comment | 16 complexity | 55c56b36f6aaa53025a79b2044352176 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lldependencies_tut.cpp
  3. * @author Nat Goodspeed
  4. * @date 2008-09-17
  5. * @brief Test of lldependencies.h
  6. *
  7. * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. // STL headers
  29. #include <iostream>
  30. #include <string>
  31. // std headers
  32. // external library headers
  33. #include <boost/assign/list_of.hpp>
  34. // Precompiled header
  35. #include "linden_common.h"
  36. // associated header
  37. #include "../lldependencies.h"
  38. // other Linden headers
  39. #include "../test/lltut.h"
  40. using boost::assign::list_of;
  41. #if LL_WINDOWS
  42. #pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
  43. #endif
  44. typedef LLDependencies<> StringDeps;
  45. typedef StringDeps::KeyList StringList;
  46. // We use the very cool boost::assign::list_of() construct to specify vectors
  47. // of strings inline. For reasons on which I'm not entirely clear, though, it
  48. // needs a helper function. You can use list_of() to construct an implicit
  49. // StringList (std::vector<std::string>) by conversion, e.g. for a function
  50. // parameter -- but if you simply write StringList(list_of("etc.")), you get
  51. // ambiguity errors. Shrug!
  52. template<typename CONTAINER>
  53. CONTAINER make(const CONTAINER& data)
  54. {
  55. return data;
  56. }
  57. // Display an arbitary value as itself...
  58. template<typename T>
  59. std::ostream& display(std::ostream& out, const T& value)
  60. {
  61. out << value;
  62. return out;
  63. }
  64. // ...but display std::string enclosed in double quotes.
  65. template<>
  66. std::ostream& display(std::ostream& out, const std::string& value)
  67. {
  68. out << '"' << value << '"';
  69. return out;
  70. }
  71. // display any sequence compatible with Boost.Range
  72. template<typename SEQUENCE>
  73. std::ostream& display_seq(std::ostream& out,
  74. const std::string& open, const SEQUENCE& seq, const std::string& close)
  75. {
  76. out << open;
  77. typename boost::range_const_iterator<SEQUENCE>::type
  78. sli = boost::begin(seq),
  79. slend = boost::end(seq);
  80. if (sli != slend)
  81. {
  82. display(out, *sli);
  83. while (++sli != slend)
  84. {
  85. out << ", ";
  86. display(out, *sli);
  87. }
  88. }
  89. out << close;
  90. return out;
  91. }
  92. // helper to dump a StringList to std::cout if needed
  93. template<typename ENTRY>
  94. std::ostream& operator<<(std::ostream& out, const std::vector<ENTRY>& list)
  95. {
  96. display_seq(out, "(", list, ")");
  97. return out;
  98. }
  99. template<typename ENTRY>
  100. std::ostream& operator<<(std::ostream& out, const std::set<ENTRY>& set)
  101. {
  102. display_seq(out, "{", set, "}");
  103. return out;
  104. }
  105. const std::string& extract_key(const LLDependencies<>::value_type& entry)
  106. {
  107. return entry.first;
  108. }
  109. // helper to return a StringList of keys from LLDependencies::sort()
  110. StringList sorted_keys(LLDependencies<>& deps)
  111. {
  112. // 1. Call deps.sort(), returning a value_type range of (key, node) pairs.
  113. // 2. Use make_transform_range() to obtain a range of just keys.
  114. // 3. Use instance_from_range to instantiate a StringList from that range.
  115. // 4. Return by value "slices" instance_from_range<StringList> (a subclass
  116. // of StringList) to its base class StringList.
  117. return instance_from_range<StringList>(make_transform_range(deps.sort(), extract_key));
  118. }
  119. template<typename RANGE>
  120. bool is_empty(const RANGE& range)
  121. {
  122. return boost::begin(range) == boost::end(range);
  123. }
  124. /*****************************************************************************
  125. * tut test group
  126. *****************************************************************************/
  127. namespace tut
  128. {
  129. struct deps_data
  130. {
  131. };
  132. typedef test_group<deps_data> deps_group;
  133. typedef deps_group::object deps_object;
  134. tut::deps_group depsgr("LLDependencies");
  135. template<> template<>
  136. void deps_object::test<1>()
  137. {
  138. StringDeps deps;
  139. StringList empty;
  140. // The quick brown fox jumps over the lazy yellow dog.
  141. // (note, "The" and "the" are distinct, else this test wouldn't work)
  142. deps.add("lazy");
  143. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")));
  144. deps.add("jumps");
  145. ensure("found lazy", deps.get("lazy"));
  146. ensure("not found dog.", ! deps.get("dog."));
  147. // NOTE: Maybe it's overkill to test each of these intermediate
  148. // results before all the interdependencies have been specified. My
  149. // thought is simply that if the order changes, I'd like to know why.
  150. // A change to the implementation of boost::topological_sort() would
  151. // be an acceptable reason, and you can simply update the expected
  152. // test output.
  153. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("jumps")));
  154. deps.add("The", 0, empty, list_of("fox")("dog."));
  155. // Test key accessors
  156. ensure("empty before deps for missing key", is_empty(deps.get_before_range("bogus")));
  157. ensure("empty before deps for jumps", is_empty(deps.get_before_range("jumps")));
  158. ensure_equals(instance_from_range< std::set<std::string> >(deps.get_before_range("The")),
  159. make< std::set<std::string> >(list_of("dog.")("fox")));
  160. // resume building dependencies
  161. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("jumps")("The")));
  162. deps.add("the", 0, list_of("The"));
  163. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("jumps")("The")("the")));
  164. deps.add("fox", 0, list_of("The"), list_of("jumps"));
  165. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("fox")("jumps")));
  166. deps.add("the", 0, list_of("The")); // same, see if cache works
  167. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("fox")("jumps")));
  168. deps.add("jumps", 0, empty, list_of("over")); // update jumps deps
  169. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("fox")("jumps")));
  170. /*==========================================================================*|
  171. // It drives me nuts that this test doesn't work in the test
  172. // framework, because -- for reasons unknown -- running the test
  173. // framework on Mac OS X 10.5 Leopard and Windows XP Pro, the catch
  174. // clause below doesn't catch the exception. Something about the TUT
  175. // test framework?!? The identical code works fine in a standalone
  176. // test program. Commenting out the test for now, in hopes that our
  177. // real builds will be able to catch Cycle exceptions...
  178. try
  179. {
  180. // We've already specified fox -> jumps and jumps -> over. Try an
  181. // impossible constraint.
  182. deps.add("over", 0, empty, list_of("fox"));
  183. }
  184. catch (const StringDeps::Cycle& e)
  185. {
  186. std::cout << "Cycle detected: " << e.what() << '\n';
  187. // It's legal to add() an impossible constraint because we don't
  188. // detect the cycle until sort(). So sort() can't know the minimum set
  189. // of nodes to remove to make the StringDeps object valid again.
  190. // Therefore we must break the cycle by hand.
  191. deps.remove("over");
  192. }
  193. |*==========================================================================*/
  194. deps.add("dog.", 0, list_of("yellow")("lazy"));
  195. ensure_equals(instance_from_range< std::set<std::string> >(deps.get_after_range("dog.")),
  196. make< std::set<std::string> >(list_of("lazy")("yellow")));
  197. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("fox")("jumps")("dog.")));
  198. deps.add("quick", 0, list_of("The"), list_of("fox")("brown"));
  199. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("the")("quick")("fox")("jumps")("dog.")));
  200. deps.add("over", 0, list_of("jumps"), list_of("yellow")("the"));
  201. ensure_equals(sorted_keys(deps), make<StringList>(list_of("lazy")("The")("quick")("fox")("jumps")("over")("the")("dog.")));
  202. deps.add("yellow", 0, list_of("the"), list_of("lazy"));
  203. ensure_equals(sorted_keys(deps), make<StringList>(list_of("The")("quick")("fox")("jumps")("over")("the")("yellow")("lazy")("dog.")));
  204. deps.add("brown");
  205. // By now the dependencies are pretty well in place. A change to THIS
  206. // order should be viewed with suspicion.
  207. ensure_equals(sorted_keys(deps), make<StringList>(list_of("The")("quick")("brown")("fox")("jumps")("over")("the")("yellow")("lazy")("dog.")));
  208. StringList keys(make<StringList>(list_of("The")("brown")("dog.")("fox")("jumps")("lazy")("over")("quick")("the")("yellow")));
  209. ensure_equals(instance_from_range<StringList>(deps.get_key_range()), keys);
  210. #if (! defined(__GNUC__)) || (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
  211. // This is the succinct way, works on modern compilers
  212. ensure_equals(instance_from_range<StringList>(make_transform_range(deps.get_range(), extract_key)), keys);
  213. #else // gcc 3.3
  214. StringDeps::range got_range(deps.get_range());
  215. StringDeps::iterator kni = got_range.begin(), knend = got_range.end();
  216. StringList::iterator ki = keys.begin(), kend = keys.end();
  217. for ( ; kni != knend && ki != kend; ++kni, ++ki)
  218. {
  219. ensure_equals(kni->first, *ki);
  220. }
  221. ensure("get_range() returns proper length", kni == knend && ki == kend);
  222. #endif // gcc 3.3
  223. // blow off get_node_range() because they're all LLDependenciesEmpty instances
  224. }
  225. template<> template<>
  226. void deps_object::test<2>()
  227. {
  228. typedef LLDependencies<std::string, int> NameIndexDeps;
  229. NameIndexDeps nideps;
  230. const NameIndexDeps& const_nideps(nideps);
  231. nideps.add("def", 2, list_of("ghi"));
  232. nideps.add("ghi", 3);
  233. nideps.add("abc", 1, list_of("def"));
  234. NameIndexDeps::range range(nideps.get_range());
  235. ensure_equals(range.begin()->first, "abc");
  236. ensure_equals(range.begin()->second, 1);
  237. range.begin()->second = 0;
  238. range.begin()->second = 1;
  239. NameIndexDeps::const_range const_range(const_nideps.get_range());
  240. NameIndexDeps::const_iterator const_iterator(const_range.begin());
  241. ++const_iterator;
  242. ensure_equals(const_iterator->first, "def");
  243. ensure_equals(const_iterator->second, 2);
  244. // NameIndexDeps::node_range node_range(nideps.get_node_range());
  245. // ensure_equals(instance_from_range<std::vector<int> >(node_range), make< std::vector<int> >(list_of(1)(2)(3)));
  246. // *node_range.begin() = 0;
  247. // *node_range.begin() = 1;
  248. NameIndexDeps::const_node_range const_node_range(const_nideps.get_node_range());
  249. ensure_equals(instance_from_range<std::vector<int> >(const_node_range), make< std::vector<int> >(list_of(1)(2)(3)));
  250. NameIndexDeps::const_key_range const_key_range(const_nideps.get_key_range());
  251. ensure_equals(instance_from_range<StringList>(const_key_range), make<StringList>(list_of("abc")("def")("ghi")));
  252. NameIndexDeps::sorted_range sorted(const_nideps.sort());
  253. NameIndexDeps::sorted_iterator sortiter(sorted.begin());
  254. ensure_equals(sortiter->first, "ghi");
  255. ensure_equals(sortiter->second, 3);
  256. // test all iterator-flavored versions of get_after_range()
  257. StringList def(make<StringList>(list_of("def")));
  258. ensure("empty abc before list", is_empty(nideps.get_before_range(nideps.get_range().begin())));
  259. ensure_equals(instance_from_range<StringList>(nideps.get_after_range(nideps.get_range().begin())),
  260. def);
  261. ensure_equals(instance_from_range<StringList>(const_nideps.get_after_range(const_nideps.get_range().begin())),
  262. def);
  263. // ensure_equals(instance_from_range<StringList>(nideps.get_after_range(nideps.get_node_range().begin())),
  264. // def);
  265. ensure_equals(instance_from_range<StringList>(const_nideps.get_after_range(const_nideps.get_node_range().begin())),
  266. def);
  267. ensure_equals(instance_from_range<StringList>(nideps.get_after_range(nideps.get_key_range().begin())),
  268. def);
  269. // advance from "ghi" to "def", which must come after "ghi"
  270. ++sortiter;
  271. ensure_equals(instance_from_range<StringList>(const_nideps.get_after_range(sortiter)),
  272. make<StringList>(list_of("ghi")));
  273. }
  274. } // namespace tut