|
1 // Copyright 2004-5 Trustees of Indiana University |
|
2 |
|
3 // Use, modification and distribution is subject to the Boost Software |
|
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
|
5 // http://www.boost.org/LICENSE_1_0.txt) |
|
6 |
|
7 // |
|
8 // graphviz_test.cpp - Test cases for the Boost.Spirit implementation of a |
|
9 // Graphviz DOT Language reader. |
|
10 // |
|
11 |
|
12 // Author: Ronald Garcia |
|
13 /* |
|
14 * © Portions copyright (c) 2006-2007 Nokia Corporation. All rights reserved. |
|
15 */ |
|
16 |
|
17 //#define BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS |
|
18 #define BOOST_GRAPHVIZ_USE_ISTREAM |
|
19 #include <boost/graph/graphviz.hpp> |
|
20 #include <boost/assign/std/map.hpp> |
|
21 #include <boost/graph/adjacency_list.hpp> |
|
22 #include <boost/graph/graph_traits.hpp> |
|
23 #include <boost/tuple/tuple.hpp> |
|
24 #include <boost/dynamic_property_map.hpp> |
|
25 #include <boost/test/test_tools.hpp> |
|
26 #include <boost/test/floating_point_comparison.hpp> |
|
27 #include <algorithm> |
|
28 #include <string> |
|
29 #include <iostream> |
|
30 #include <iterator> |
|
31 #include <map> |
|
32 #include <utility> |
|
33 |
|
34 #ifdef __SYMBIAN32__ |
|
35 #include "std_log_result.h" |
|
36 #define LOG_FILENAME_LINE __FILE__, __LINE__ |
|
37 #endif |
|
38 using namespace std; |
|
39 using namespace boost; |
|
40 |
|
41 #ifndef BOOST_GRAPHVIZ_USE_ISTREAM |
|
42 using namespace boost::spirit; |
|
43 #endif |
|
44 using namespace boost::assign; |
|
45 |
|
46 typedef std::string node_t; |
|
47 typedef std::pair<node_t,node_t> edge_t; |
|
48 |
|
49 typedef std::map<node_t,float> mass_map_t; |
|
50 typedef std::map<edge_t,double> weight_map_t; |
|
51 |
|
52 template <typename Directedness, typename OutEdgeList> |
|
53 bool test_graph(std::istream& dotfile, mass_map_t const& masses, |
|
54 weight_map_t const& weights, |
|
55 std::string const& node_id = "node_id") { |
|
56 |
|
57 typedef adjacency_list < OutEdgeList, vecS, Directedness, |
|
58 property < vertex_name_t, std::string, |
|
59 property < vertex_color_t, float > >, |
|
60 property < edge_weight_t, double > > graph_t; |
|
61 typedef typename graph_traits < graph_t >::edge_descriptor edge_t; |
|
62 typedef typename graph_traits < graph_t >::vertex_descriptor vertex_t; |
|
63 |
|
64 // Construct a graph and set up the dynamic_property_maps. |
|
65 graph_t graph(0); |
|
66 dynamic_properties dp; |
|
67 typename property_map<graph_t, vertex_name_t>::type name = |
|
68 get(vertex_name, graph); |
|
69 dp.property(node_id,name); |
|
70 typename property_map<graph_t, vertex_color_t>::type mass = |
|
71 get(vertex_color, graph); |
|
72 dp.property("mass",mass); |
|
73 typename property_map<graph_t, edge_weight_t>::type weight = |
|
74 get(edge_weight, graph); |
|
75 dp.property("weight",weight); |
|
76 |
|
77 // Read in space characters too! |
|
78 dotfile >> noskipws; |
|
79 |
|
80 bool result = true; |
|
81 #ifdef BOOST_GRAPHVIZ_USE_ISTREAM |
|
82 if(read_graphviz(dotfile,graph,dp,node_id)) { |
|
83 #else |
|
84 std::string data; |
|
85 std::copy(std::istream_iterator<char>(dotfile), |
|
86 std::istream_iterator<char>(), |
|
87 std::back_inserter(data)); |
|
88 if(read_graphviz(data.begin(),data.end(),graph,dp,node_id)) { |
|
89 #endif |
|
90 // check masses |
|
91 if(!masses.empty()) { |
|
92 // assume that all the masses have been set |
|
93 // for each vertex: |
|
94 typename graph_traits<graph_t>::vertex_iterator i,j; |
|
95 for(boost::tie(i,j) = vertices(graph); i != j; ++i) { |
|
96 // - get its name |
|
97 std::string node_name = get(name,*i); |
|
98 // - get its mass |
|
99 float node_mass = get(mass,*i); |
|
100 float ref_mass = masses.find(node_name)->second; |
|
101 // - compare the mass to the result in the table |
|
102 |
|
103 BOOST_CHECK_CLOSE(node_mass, ref_mass, 0.01f); |
|
104 } |
|
105 } |
|
106 // check weights |
|
107 if(!weights.empty()) { |
|
108 // assume that all weights have been set |
|
109 /// for each edge: |
|
110 typename graph_traits<graph_t>::edge_iterator i,j; |
|
111 for(boost::tie(i,j) = edges(graph); i != j; ++i) { |
|
112 // - get its name |
|
113 std::pair<std::string,std::string> |
|
114 edge_name = make_pair(get(name, source(*i,graph)), |
|
115 get(name, target(*i,graph))); |
|
116 // - get its weight |
|
117 double edge_weight = get(weight,*i); |
|
118 double ref_weight = weights.find(edge_name)->second; |
|
119 // - compare the weight to teh result in the table |
|
120 BOOST_CHECK_CLOSE(edge_weight, ref_weight, 0.01); |
|
121 } |
|
122 } |
|
123 |
|
124 |
|
125 } else { |
|
126 std::cerr << "Parsing Failed!\n"; |
|
127 result = false; |
|
128 } |
|
129 |
|
130 return result; |
|
131 } |
|
132 |
|
133 int test_main(int, char*[]) { |
|
134 |
|
135 typedef istringstream gs_t; |
|
136 |
|
137 // Basic directed graph tests |
|
138 { |
|
139 mass_map_t masses; |
|
140 insert ( masses ) ("a",0.0f) ("c",7.7f) ("e", 6.66f); |
|
141 gs_t gs("digraph { a node [mass = 7.7] c e [mass = 6.66] }"); |
|
142 BOOST_CHECK((test_graph<directedS,vecS>(gs,masses,weight_map_t()))); |
|
143 } |
|
144 |
|
145 { |
|
146 weight_map_t weights; |
|
147 insert( weights )(make_pair("a","b"),0.0) |
|
148 (make_pair("c","d"),7.7)(make_pair("e","f"),6.66); |
|
149 gs_t gs("digraph { a -> b edge [weight = 7.7] " |
|
150 "c -> d e-> f [weight = 6.66] }"); |
|
151 BOOST_CHECK((test_graph<directedS,vecS>(gs,mass_map_t(),weights))); |
|
152 } |
|
153 |
|
154 // undirected graph with alternate node_id property name |
|
155 { |
|
156 mass_map_t masses; |
|
157 insert ( masses ) ("a",0.0f) ("c",7.7f) ("e", 6.66f); |
|
158 gs_t gs("graph { a node [mass = 7.7] c e [mass = 6.66] }"); |
|
159 BOOST_CHECK((test_graph<undirectedS,vecS>(gs,masses,weight_map_t(), |
|
160 "nodenames"))); |
|
161 } |
|
162 |
|
163 // Basic undirected graph tests |
|
164 { |
|
165 mass_map_t masses; |
|
166 insert ( masses ) ("a",0.0f) ("c",7.7f) ("e", 6.66f); |
|
167 gs_t gs("graph { a node [mass = 7.7] c e [mass = 6.66] }"); |
|
168 BOOST_CHECK((test_graph<undirectedS,vecS>(gs,masses,weight_map_t()))); |
|
169 } |
|
170 |
|
171 { |
|
172 weight_map_t weights; |
|
173 insert( weights )(make_pair("a","b"),0.0) |
|
174 (make_pair("c","d"),7.7)(make_pair("e","f"),6.66); |
|
175 gs_t gs("graph { a -- b eDge [weight = 7.7] " |
|
176 "c -- d e -- f [weight = 6.66] }"); |
|
177 BOOST_CHECK((test_graph<undirectedS,vecS>(gs,mass_map_t(),weights))); |
|
178 } |
|
179 |
|
180 // Mismatch directed graph test |
|
181 { |
|
182 mass_map_t masses; |
|
183 insert ( masses ) ("a",0.0f) ("c",7.7f) ("e", 6.66f); |
|
184 gs_t gs("graph { a nodE [mass = 7.7] c e [mass = 6.66] }"); |
|
185 try { |
|
186 test_graph<directedS,vecS>(gs,masses,weight_map_t()); |
|
187 } catch (boost::undirected_graph_error&) {} |
|
188 } |
|
189 |
|
190 // Mismatch undirected graph test |
|
191 { |
|
192 mass_map_t masses; |
|
193 insert ( masses ) ("a",0.0f) ("c",7.7f) ("e", 6.66f); |
|
194 gs_t gs("digraph { a node [mass = 7.7] c e [mass = 6.66] }"); |
|
195 try { |
|
196 test_graph<undirectedS,vecS>(gs,masses,weight_map_t()); |
|
197 BOOST_ERROR("Failed to throw boost::directed_graph_error."); |
|
198 } catch (boost::directed_graph_error&) {} |
|
199 } |
|
200 |
|
201 // Complain about parallel edges |
|
202 { |
|
203 weight_map_t weights; |
|
204 insert( weights )(make_pair("a","b"),7.7); |
|
205 gs_t gs("diGraph { a -> b [weight = 7.7] a -> b [weight = 7.7] }"); |
|
206 try { |
|
207 test_graph<directedS,setS>(gs,mass_map_t(),weights); |
|
208 BOOST_ERROR("Failed to throw boost::bad_parallel_edge."); |
|
209 } catch (boost::bad_parallel_edge&) {} |
|
210 } |
|
211 |
|
212 // Handle parallel edges gracefully |
|
213 { |
|
214 weight_map_t weights; |
|
215 insert( weights )(make_pair("a","b"),7.7); |
|
216 gs_t gs("digraph { a -> b [weight = 7.7] a -> b [weight = 7.7] }"); |
|
217 BOOST_CHECK((test_graph<directedS,vecS>(gs,mass_map_t(),weights))); |
|
218 } |
|
219 |
|
220 #ifdef __SYMBIAN32__ |
|
221 |
|
222 std_log(LOG_FILENAME_LINE,"[End Test Case ]"); |
|
223 |
|
224 testResultXml("graphiz_test"); |
|
225 close_log_file(); |
|
226 #endif |
|
227 return 0; |
|
228 } |