utest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /* Author: Brian Gerkey */
31 
32 #include <stdexcept> // for std::runtime_error
33 #include <string>
34 #include <vector>
35 #include <stdlib.h>
36 #ifndef _WIN32
37 #include <unistd.h>
38 #endif
39 #include <stdio.h>
40 #include <time.h>
41 #include <gtest/gtest.h>
42 #include <boost/algorithm/string.hpp>
43 #include <boost/filesystem.hpp>
44 #include "rospack/rospack.h"
45 #include "utils.h"
46 
47 #ifdef _WIN32
48 int setenv(const char *name, const char *value, int overwrite)
49 {
50  if(!overwrite)
51  {
52  size_t envsize = 0;
53  errno_t errcode = getenv_s(&envsize, NULL, 0, name);
54  if(errcode || envsize)
55  return errcode;
56  }
57  return _putenv_s(name, value);
58 }
59 #endif
60 
61 TEST(rospack, reentrant)
62 {
64  std::string output;
65  int ret = rp.run(std::string("plugins --attrib=foo --top=precedence1 roslang"));
66  ASSERT_EQ(ret, 0);
67  ret = rp.run(std::string("find roslang"));
68  ASSERT_EQ(ret, 0);
69  ret = rp.run(std::string("list-names"));
70  ASSERT_EQ(ret, 0);
71  std::vector<std::string> output_list;
72  output = rp.getOutput();
73  boost::trim(output);
74  boost::split(output_list, output, boost::is_any_of("\n"));
75  ASSERT_EQ((int)output_list.size(), 4);
76  ret = rp.run(std::string("list"));
77  ASSERT_EQ(ret, 0);
78  output = rp.getOutput();
79  boost::trim(output);
80  boost::split(output_list, output, boost::is_any_of("\n"));
81  ASSERT_EQ((int)output_list.size(), 4);
82  std::vector<std::string> path_name;
83  boost::split(path_name, output_list[0], boost::is_any_of(" "));
84  ASSERT_EQ((int)path_name.size(), 2);
85 }
86 
87 TEST(rospack, multiple_rospack_objects)
88 {
90  std::string output;
91  int ret = rp.run(std::string("plugins --attrib=foo --top=precedence1 roslang"));
92  ASSERT_EQ(ret, 0);
93  ret = rp.run(std::string("find roslang"));
94  ASSERT_EQ(ret, 0);
95  ret = rp.run(std::string("list-names"));
96  ASSERT_EQ(ret, 0);
97  std::vector<std::string> output_list;
98  output = rp.getOutput();
99  boost::trim(output);
100  boost::split(output_list, output, boost::is_any_of("\n"));
101  ASSERT_EQ((int)output_list.size(), 4);
102  ret = rp.run(std::string("list"));
103  ASSERT_EQ(ret, 0);
104  output = rp.getOutput();
105  boost::trim(output);
106  boost::split(output_list, output, boost::is_any_of("\n"));
107  ASSERT_EQ((int)output_list.size(), 4);
108  std::vector<std::string> path_name;
109  boost::split(path_name, output_list[0], boost::is_any_of(" "));
110  ASSERT_EQ((int)path_name.size(), 2);
111 
112  rospack::ROSPack rp2;
113  ret = rp2.run(std::string("plugins --attrib=foo --top=precedence1 roslang"));
114  ASSERT_EQ(ret, 0);
115  ret = rp2.run(std::string("find roslang"));
116  ASSERT_EQ(ret, 0);
117  ret = rp2.run(std::string("list-names"));
118  ASSERT_EQ(ret, 0);
119  output_list.clear();
120  output = rp2.getOutput();
121  boost::trim(output);
122  boost::split(output_list, output, boost::is_any_of("\n"));
123  ASSERT_EQ((int)output_list.size(), 4);
124  ret = rp2.run(std::string("list"));
125  ASSERT_EQ(ret, 0);
126  output = rp2.getOutput();
127  boost::trim(output);
128  boost::split(output_list, output, boost::is_any_of("\n"));
129  ASSERT_EQ((int)output_list.size(), 4);
130  path_name.clear();
131  boost::split(path_name, output_list[0], boost::is_any_of(" "));
132  ASSERT_EQ((int)path_name.size(), 2);
133 }
134 
136 {
137  std::string input = "foo foo bar bat bar foobar batbar";
138  std::string truth = "foo bar bat foobar batbar";
139  std::string output;
140  rospack::deduplicate_tokens(input, false, output);
141  ASSERT_EQ(truth, output);
142 }
143 
144 // Test that env var changes between runs still produce the right results.
145 TEST(rospack, env_change)
146 {
147  // Get old path for resetting later, to avoid cross-talk with other tests
148  char* oldrpp = getenv("ROS_PACKAGE_PATH");
149  rospack::ROSPack rp;
150 
151  // Case 1: RPP=/test2
152  char buf[1024];
153  std::string rr = std::string(getcwd(buf, sizeof(buf))) + "/test2";
154  setenv("ROS_PACKAGE_PATH", rr.c_str(), 1);
155  std::vector<std::string> test_pkgs;
156  test_pkgs.push_back("precedence1");
157  test_pkgs.push_back("precedence2");
158  test_pkgs.push_back("precedence3");
159  test_pkgs.push_back("roslang");
160  std::string output;
161  int ret = rp.run(std::string("list-names"));
162  EXPECT_EQ(ret, 0);
163  std::vector<std::string> output_list;
164  output = rp.getOutput();
165  boost::trim(output);
166  boost::split(output_list, output, boost::is_any_of("\n"));
167  // Check that we get back the right list of packages (which could be in any
168  // order).
169  EXPECT_EQ(output_list.size(), test_pkgs.size());
170  for(std::vector<std::string>::const_iterator it = output_list.begin();
171  it != output_list.end();
172  ++it)
173  {
174  bool found = false;
175  for(std::vector<std::string>::const_iterator it2 = test_pkgs.begin();
176  it2 != test_pkgs.end();
177  ++it2)
178  {
179  if(*it == *it2)
180  {
181  EXPECT_FALSE(found);
182  found = true;
183  }
184  }
185  EXPECT_TRUE(found);
186  }
187 
188  // Case 2: RPP=/test3
189  rr = std::string(getcwd(buf, sizeof(buf))) + "/test3";
190  setenv("ROS_PACKAGE_PATH", rr.c_str(), 1);
191  test_pkgs.clear();
192  test_pkgs.push_back("precedence1");
193  test_pkgs.push_back("precedence2");
194  test_pkgs.push_back("precedence3");
195  ret = rp.run(std::string("list-names"));
196  EXPECT_EQ(ret, 0);
197  output_list.clear();
198  output = rp.getOutput();
199  boost::trim(output);
200  boost::split(output_list, output, boost::is_any_of("\n"));
201  // Check that we get back the right list of packages (which could be in any
202  // order).
203  EXPECT_EQ(output_list.size(), test_pkgs.size());
204  for(std::vector<std::string>::const_iterator it = output_list.begin();
205  it != output_list.end();
206  ++it)
207  {
208  bool found = false;
209  for(std::vector<std::string>::const_iterator it2 = test_pkgs.begin();
210  it2 != test_pkgs.end();
211  ++it2)
212  {
213  if(*it == *it2)
214  {
215  EXPECT_FALSE(found);
216  found = true;
217  }
218  }
219  EXPECT_TRUE(found);
220  }
221 
222  // Case 3: RPP=/test_empty
223  rr = std::string(getcwd(buf, sizeof(buf))) + "/test_empty";
224  setenv("ROS_PACKAGE_PATH", rr.c_str(), 1);
225  ret = rp.run(std::string("list-names"));
226  EXPECT_EQ(ret, 0);
227  output = rp.getOutput();
228  boost::trim(output);
229  EXPECT_EQ(output, std::string());
230 
231  // Reset old path, for other tests
232  setenv("ROS_PACKAGE_PATH", oldrpp, 1);
233 }
234 
235 
236 namespace
237 {
238 void trimAll(std::vector<std::string> &inout)
239 {
240  for (ssize_t i = inout.size() - 1; i >= 0; --i)
241  {
242  boost::trim(inout[i]);
243  // Remove empty ones
244  if (inout[i].empty()) inout.erase(inout.begin() + i);
245  }
246 }
247 
248 ::testing::AssertionResult outputEqual(std::string output, const std::string &expected, bool trim = true)
249 {
250  if (trim) boost::trim(output);
251  if (output == expected) return ::testing::AssertionSuccess();
252  return ::testing::AssertionFailure() << "Output did not match: " << output;
253 }
254 
255 ::testing::AssertionResult outputEqual(std::string output, const std::vector<std::string> &expected, bool trim = true)
256 {
257  boost::trim(output);
258  std::vector<std::string> output_lines;
259  boost::split( output_lines, output, []( char c) { return c == '\n'; });
260  if (trim) trimAll( output_lines);
261  if ( output_lines.size() != expected.size())
262  return ::testing::AssertionFailure() << "output line count did not match expected: " << output_lines.size() << std::endl << boost::join( output_lines, "\n");
263  for ( size_t i = 0; i < output_lines.size(); ++i)
264  {
265  for ( size_t j = i + 1; j < output_lines.size(); ++j)
266  {
267  if ( output_lines[i] == output_lines[j])
268  return ::testing::AssertionFailure() << "output contained a duplicate: " << output_lines[i];
269  }
270  }
271  for (auto &dep : output_lines)
272  {
273  bool found = false;
274  for (auto &line : expected)
275  {
276  if (line != dep) continue;
277  found = true;
278  break;
279  }
280  if (!found)
281  return ::testing::AssertionFailure() << "output contained '" << dep << "' which was not expected!";
282  }
283  return ::testing::AssertionSuccess();
284 }
285 
286 ::testing::AssertionResult outputEndsWith(std::string output, const std::vector<std::string> &expected, bool trim = true)
287 {
288  boost::trim(output);
289  std::vector<std::string> output_lines;
290  boost::split( output_lines, output, []( char c) { return c == '\n' || c == ' '; });
291  if (trim) trimAll( output_lines);
292  if (output_lines.size() != expected.size())
293  return ::testing::AssertionFailure() << "output line count did not match expected: " << output_lines.size() << std::endl << boost::join( output_lines, "\n");
294  for (size_t i = 0; i < output_lines.size(); ++i)
295  {
296  for (size_t j = i + 1; j < output_lines.size(); ++j)
297  {
298  if (output_lines[i] == output_lines[j])
299  return ::testing::AssertionFailure() << "output contained a duplicate: " << output_lines[i];
300  }
301  }
302  for (auto &dep : output_lines)
303  {
304  bool found = false;
305  for (auto &line : expected)
306  {
307  if (dep.length() < line.length()) continue;
308  if (line != dep.substr(dep.length() - line.length())) continue;
309  found = true;
310  break;
311  }
312  if (!found)
313  return ::testing::AssertionFailure() << "output contained '" << dep << "' which was not expected!";
314  }
315  return ::testing::AssertionSuccess();
316 }
317 }
318 
319 TEST(rospack, multiple_errors)
320 {
321  // Get old path for resetting later, to avoid cross-talk with other tests
322  char* oldrpp = getenv("ROS_PACKAGE_PATH");
323  // Switch to RPP=/test_errors
324  char buf[1024];
325  std::string rr = std::string(getcwd(buf, sizeof(buf))) + "/test_errors";
326  setenv("ROS_PACKAGE_PATH", rr.c_str(), 1);
327  rospack::ROSPack rp;
328  std::string output;
329  int ret = rp.run("deps valid_package");
330  EXPECT_EQ(ret, 0);
331  EXPECT_TRUE(outputEqual(rp.getOutput(), std::vector<std::string> {"base", "base2"}));
332 
333  // one error
334  ret = rp.run("deps invalid_package_one");
335  EXPECT_NE(ret, 0);
336  EXPECT_TRUE(outputEqual(rp.getOutput(), std::vector<std::string> {"valid_package", "base", "base2"} ));
337 
338  // two errors
339  ret = rp.run("deps invalid_package_two");
340  EXPECT_NE(ret, 0);
341  EXPECT_TRUE(outputEqual(rp.getOutput(), {"invalid_package_one", "valid_package", "base", "base2", "another_valid_package"}));
342 
343  // depends1
344  ret = rp.run("depends1 direct_deps_valid");
345  EXPECT_NE(ret, 0);
346  EXPECT_TRUE(outputEqual(rp.getOutput(), std::vector<std::string> {"valid_package", "invalid_package_one"}));
347 
348  // depends-manifests
349  ret = rp.run("depends-manifests invalid_package_one");
350  EXPECT_NE(ret, 0);
351  EXPECT_TRUE(outputEndsWith(rp.getOutput(), std::vector<std::string> {"valid_package/manifest.xml", "base/manifest.xml", "base2/manifest.xml"}));
352 
353  // depends-indent
354  ret = rp.run("depends-indent invalid_package_one");
355  EXPECT_NE(ret, 0);
356  EXPECT_TRUE(outputEqual(rp.getOutput(), std::vector<std::string> {"valid_package", " base", " base2"}, false));
357 
358  // depends-why
359  ret = rp.run("depends-why --target=base invalid_package_two");
360  EXPECT_NE(ret, 0);
361  EXPECT_TRUE(outputEqual(rp.getOutput(), std::vector<std::string> {"Dependency chains from invalid_package_two to base:",
362  "* invalid_package_two -> invalid_package_one -> valid_package -> base"}));
363 
364  // depends-on
365  ret = rp.run("depends-on base");
366  EXPECT_EQ(ret, 0);
367  EXPECT_TRUE(outputEqual(rp.getOutput(), {"direct_deps_valid", "valid_package", "invalid_package_one", "invalid_package_two", "invalid_roslang_package"}));
368 
369  // depends-on1
370  ret = rp.run("depends-on1 base");
371  EXPECT_EQ(ret, 0);
372  EXPECT_TRUE(outputEqual(rp.getOutput(), "valid_package"));
373 
374  ret = rp.run("depends-on1 valid_package");
375  EXPECT_EQ(ret, 0);
376  EXPECT_TRUE(outputEqual(rp.getOutput(), std::vector<std::string> {"direct_deps_valid", "invalid_package_one"}));
377 
378  // Reset old path, for other tests
379  setenv("ROS_PACKAGE_PATH", oldrpp, 1);
380 }
381 
382 int main(int argc, char **argv)
383 {
384  // Quiet some warnings
385  (void)rospack::ROSPACK_NAME;
387 
388  char buf[1024];
389  std::string rr = std::string(getcwd(buf, sizeof(buf))) + "/test2";
390  setenv("ROS_PACKAGE_PATH", rr.c_str(), 1);
391  char *path = getcwd(NULL, 0);
392  if(path)
393  {
394  boost::filesystem::path p(path);
395  p = p.parent_path();
396  std::string newpath = p.string();
397  char* oldpath = getenv("PATH");
398  if(oldpath)
399  newpath += std::string(":") + oldpath;
400  setenv("PATH", newpath.c_str(), 1);
401  }
402 
403  free(path);
404  testing::InitGoogleTest(&argc, argv);
405  return RUN_ALL_TESTS();
406 }
main
int main(int argc, char **argv)
Definition: utest.cpp:382
rospack::deduplicate_tokens
void deduplicate_tokens(const std::string &instring, bool last, std::string &outstring)
Definition: utils.cpp:39
rospack.h
rospack::ROSPack
Backward compatibility API for librospack (DEPRECATED).
Definition: rospack_backcompat.h:42
TEST
TEST(rospack, reentrant)
Definition: utest.cpp:61
utils.h
rospack
Definition: rospack.h:123
rospack::ROSPACK_NAME
static const char * ROSPACK_NAME
Definition: utils.h:42
rospack::ROSPack::run
int run(int argc, char **argv)
Run rospack with the given arguments. Call getOutput() to get the result.
Definition: rospack_backcompat.cpp:41
rospack::ROSPack::getOutput
std::string getOutput()
Get the output from the last successful run() call.
Definition: rospack_backcompat.h:74
rospack::ROSSTACK_NAME
static const char * ROSSTACK_NAME
Definition: utils.h:43


rospack
Author(s): Brian Gerkey, Morgan Quigley, Dirk Thomas
autogenerated on Wed Mar 2 2022 00:54:50