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