1/*
2  This file is part of Valgrind, a dynamic binary instrumentation
3  framework.
4
5  Copyright (C) 2008-2008 Google Inc
6     opensource@google.com
7
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version.
12
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  02111-1307, USA.
22
23  The GNU General Public License is contained in the file COPYING.
24*/
25
26/* Author: Konstantin Serebryany <opensource@google.com>
27
28 This file contains a simple test suite for some of our old unit-tests.
29 These tests are likely to be moved to googletest framework over time.
30*/
31
32#include <algorithm>
33#include <gtest/gtest.h>
34#include <string>
35#include <ostream>
36
37#include "old_test_suite.h"
38
39Mutex printf_mu;
40std::map<int, Test> *TheMapOfTests = NULL;
41std::vector<int> tests_to_run;
42std::set<int> tests_to_exclude;
43
44#ifndef MAIN_INIT_ACTION
45#define MAIN_INIT_ACTION
46#endif
47
48int ParseInt(const char *str) {
49  int ret = 0;
50  const char *cur = str;
51  do {
52    if (!isdigit(*cur)) {
53      printf("\"%s\" is not a valid number\n", str);
54      exit(1);
55    }
56
57    ret = ret*10 + (*cur - '0');
58  } while (*(++cur));
59  return ret;
60}
61
62class RandomGenerator {
63 public:
64  RandomGenerator(int seed) { srand(seed); }
65  size_t operator( )(size_t n) const { return rand() % n; }
66};
67
68TEST(NonGtestTests, All) {
69  for (size_t i = 0; i < tests_to_run.size(); i++) {
70    int test_id = tests_to_run[i];
71    if (tests_to_exclude.count(test_id) > 0) {
72      printf("test%i was excluded\n", test_id);
73    } else {
74      (*TheMapOfTests)[test_id].Run();
75      ANNOTATE_FLUSH_EXPECTED_RACES();
76    }
77  }
78}
79
80#ifndef ANDROID // GTest version is too old.
81class PerformanceTestEventListener: public ::testing::EmptyTestEventListener {
82 public:
83  virtual void OnTestEnd(const ::testing::TestInfo& test_info) {
84    if (strcmp(test_info.test_case_name(), "StressTests") == 0 ||
85        strcmp(test_info.test_case_name(), "PerformanceTests") == 0) {
86      const ::testing::TestResult* result = test_info.result();
87      times_[test_info.name()].push_back(result->elapsed_time());
88    }
89  }
90
91  virtual void OnTestProgramEnd(const ::testing::UnitTest& unit_test) {
92    for (std::map<string, std::vector<long long int> >::iterator it = times_.begin();
93         it != times_.end(); ++it) {
94      printf("*RESULT %s: time= %s ms\n", it->first.c_str(), join_str(it->second).c_str());
95    }
96  }
97
98 private:
99  std::map<string, std::vector<long long int> > times_;
100
101  string join_str(std::vector<long long int> values) {
102    bool first = true;
103    bool single = (values.size() == 1);
104    std::ostringstream st;
105    if (!single) {
106      st << "[";
107    }
108    for (std::vector<long long int>::iterator it = values.begin();
109         it != values.end(); ++it) {
110      if (first) {
111        first = false;
112      } else {
113        st << " ";
114      }
115      st << *it;
116    }
117    if (!single) {
118      st << "]";
119    }
120    return st.str();
121  }
122};
123#endif
124
125int main(int argc, char** argv) {
126  MAIN_INIT_ACTION;
127  testing::InitGoogleTest(&argc, argv);
128  printf("FLAGS [phb=%i, rv=%i]\n", Tsan_PureHappensBefore(),
129      Tsan_RaceVerifier());
130
131  int shuffle_seed = 0;  // non-zero to shuffle.
132
133  int id = 1;
134  while (id < argc) {
135    char *cur_arg = argv[id];
136    if (!strcmp(cur_arg, "benchmark")) {
137      for (std::map<int,Test>::iterator it = TheMapOfTests->begin();
138        it != TheMapOfTests->end(); ++it) {
139        if(it->second.flags_ & PERFORMANCE)
140          tests_to_run.push_back(it->first);
141      }
142    } else if (!strcmp(cur_arg, "demo")) {
143      for (std::map<int,Test>::iterator it = TheMapOfTests->begin();
144        it != TheMapOfTests->end();  ++it) {
145        if(it->second.flags_ & RACE_DEMO)
146          tests_to_run.push_back(it->first);
147      }
148    } else if (!strncmp(cur_arg, "shuffle", 7)) {
149      if (strlen(cur_arg) == 7) {
150        shuffle_seed = GetTimeInMs();
151        printf("Shuffling with seed = %i\n", shuffle_seed);
152      } else {
153        CHECK(cur_arg[7] == '=');
154        shuffle_seed = ParseInt(cur_arg + 8);
155      }
156    } else {
157      if (isdigit(cur_arg[0])) {
158        // Enqueue the test specified.
159        int test_id = ParseInt(cur_arg);
160        if (!TheMapOfTests->count(test_id)) {
161          printf("Unknown test id: %d\n", test_id);
162          exit(1);
163        }
164        tests_to_run.push_back(test_id);
165      } else if (cur_arg[0] == '-') {
166        // Exclude the test specified.
167        int test_id = ParseInt(cur_arg + 1);
168        if (!TheMapOfTests->count(test_id)) {
169          printf("Unknown test id: %d\n", test_id);
170          exit(1);
171        }
172        tests_to_exclude.insert(test_id);
173      } else {
174        printf("Unknown argument: %s\n", cur_arg);
175        exit(1);
176      }
177    }
178
179    id++;
180  }
181
182  if (tests_to_run.size() == 0) {
183    printf("No tests specified.\nRunning default set of tests...\n");
184    for (std::map<int,Test>::iterator it = TheMapOfTests->begin();
185        it != TheMapOfTests->end();
186        ++it) {
187      if(it->second.flags_ & EXCLUDE_FROM_ALL) continue;
188      if(it->second.flags_ & RACE_DEMO) continue;
189      tests_to_run.push_back(it->first);
190    }
191  }
192
193  if (shuffle_seed > 0) {
194    RandomGenerator rnd(shuffle_seed);
195    random_shuffle(tests_to_run.begin(), tests_to_run.end(), rnd);
196  }
197
198#ifndef ANDROID // GTest version is too old.
199  ::testing::TestEventListeners& listeners =
200        ::testing::UnitTest::GetInstance()->listeners();
201  // Adds a listener to the end.  Google Test takes the ownership.
202  listeners.Append(new PerformanceTestEventListener());
203#endif
204
205  return RUN_ALL_TESTS();
206}
207// End {{{1
208 // vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker
209