utility.hpp
Go to the documentation of this file.
1 #ifndef TEST_UNIT_LANG_PARSER_UTILITY_HPP
2 #define TEST_UNIT_LANG_PARSER_UTILITY_HPP
3 
4 #include <gtest/gtest.h>
6 #include <stan/lang/ast.hpp>
7 #include <stan/lang/compiler.hpp>
8 #include <stan/lang/parser.hpp>
15 #include <test/unit/util.hpp>
16 #include <boost/lexical_cast.hpp>
17 #include <iostream>
18 #include <fstream>
19 #include <istream>
20 #include <sstream>
21 #include <exception>
22 #include <stdexcept>
23 
24 /** extract model name from filepath name
25  * @param file_name Name off model file
26  */
28  std::string name_copy = name;
29  size_t last_bk = name_copy.find_last_of('\\');
30  if (last_bk != std::string::npos)
31  name_copy.erase(0,last_bk + 1);
32  size_t last_fwd = name_copy.find_last_of('/');
33  if (last_fwd != std::string::npos)
34  name_copy.erase(0,last_fwd + 1);
35 
36  size_t last_dot = name_copy.find_last_of('.');
37  if (last_dot != std::string::npos)
38  name_copy.erase(last_dot,name_copy.size());
39 
40  name_copy += "_model";
41  return name_copy;
42 }
43 
44 
45 /** test whether model with specified path name parses successfully
46  *
47  * @param file_name Filepath of model file
48  * @param msgs Expected error message (default: none)
49  * @param allow_undefined Boolean to permit undefined functions (default: false)
50  */
52  std::ostream* msgs = 0,
53  bool allow_undefined = false) {
55  std::ifstream fs(file_name.c_str());
56  if (fs.fail()) {
57  *msgs << "Cannot open model file " << file_name << std::endl;
58  return false;
59  }
60  std::string model_name = file_name_to_model_name(file_name);
61  std::vector<std::string> search_path;
62  stan::io::program_reader reader(fs, file_name, search_path);
63  std::string s = reader.program();
64  std::stringstream ss(s);
65  bool parsable
66  = stan::lang::parse(msgs, ss, model_name, reader, prog, allow_undefined);
67  return parsable;
68 }
69 
70 
71 /** test whether model with specified name in path good parses successfully
72  *
73  * @param model_name Name of model to parse
74  * @param folder Path to folder under src/test/test-models (default "good")
75  * @param msgs Warning message
76  */
77 bool is_parsable_folder(const std::string& model_name,
78  const std::string folder = "good",
79  std::ostream* msgs = 0,
80  const std::string extension = ".stan") {
81  std::string path("src/test/test-models/");
82  path += folder;
83  path += "/";
84  path += model_name;
85  path += extension;
86  return is_parsable(path, msgs, false);
87 }
88 
89 /** test that model with specified name in folder "good"
90  * parses without throwing an exception
91  *
92  * @param model_name Name of model to parse
93  */
94 void test_parsable(const std::string& model_name) {
95  bool result;
96  std::stringstream msgs;
97  SCOPED_TRACE("parsing: " + model_name);
98  result = is_parsable_folder(model_name, "good", &msgs);
99  if (!result) {
100  FAIL() << std::endl << "*********************************" << std::endl
101  << "model name=" << model_name << std::endl
102  << msgs.str() << std::endl;
103  }
104  SUCCEED();
105 }
106 
107 /** test that file with standalone functions with specified name in folder
108  * "good-standalone-functions" parses without throwing an exception
109  *
110  * @param model_name Name of model to parse
111  */
113  {
114  SCOPED_TRACE("parsing standalone functions: " + model_name);
115  EXPECT_TRUE(is_parsable_folder(model_name, "good-standalone-functions",
116  0, ".stanfuncs"));
117  }
118 }
119 
120 /** test that model with specified name in folder "bad" throws
121  * an exception containing the second arg as a substring
122  *
123  * @param model_name Name of model to parse
124  * @param msg Substring of error message expected.
125  */
126 void test_throws(const std::string& model_name, const std::string& error_msg) {
127  std::stringstream msgs;
128  try {
129  is_parsable_folder(model_name, "bad", &msgs);
130  if (msgs.str().length() > 0)
131  FAIL() << std::endl << "*********************************" << std::endl
132  << "model name=" << model_name << std::endl
133  << "*** no exception thrown by parser" << std::endl
134  << "*** parser msgs: msgs.str()=" << msgs.str() << std::endl
135  << "*** expected: error_msg=" << error_msg << std::endl
136  << "*********************************" << std::endl
137  << std::endl;
138  } catch (const std::invalid_argument& e) {
139  if (std::string(e.what()).find(error_msg) == std::string::npos
140  && msgs.str().find(error_msg) == std::string::npos) {
141  FAIL() << std::endl << "*********************************" << std::endl
142  << "model name=" << model_name << std::endl
143  << "*** EXPECTED: error_msg=" << error_msg << std::endl
144  << "*** FOUND: e.what()=" << e.what() << std::endl
145  << "*** FOUND: msgs.str()=" << msgs.str() << std::endl
146  << "*********************************" << std::endl
147  << std::endl;
148  }
149  return;
150  }
151  FAIL() << "model name=" << model_name
152  << " is parsable and were expecting msg=" << error_msg
153  << std::endl;
154 }
155 
156 /**
157  * Same as test_throws() but for two messages.
158  */
159 void test_throws(const std::string& model_name,
160  const std::string& error_msg1,
161  const std::string& error_msg2) {
162  test_throws(model_name, error_msg1);
163  test_throws(model_name, error_msg2);
164 }
165 
166 /**
167  * Same as test_throws() but for three messages.
168  */
169 void test_throws(const std::string& model_name,
170  const std::string& error_msg1,
171  const std::string& error_msg2,
172  const std::string& error_msg3) {
173  test_throws(model_name, error_msg1);
174  test_throws(model_name, error_msg2);
175  test_throws(model_name, error_msg3);
176 }
177 
178 /** test that model with specified name in good path parses
179  * and returns a warning containing the second arg as a substring
180  *
181  * @param model_name Name of model to parse
182  * @param msg Substring of warning message expected.
183  */
184 void test_warning(const std::string& model_name,
185  const std::string& warning_msg) {
186  std::stringstream msgs;
187  EXPECT_TRUE(is_parsable_folder(model_name, "good", &msgs));
188  bool found = msgs.str().find(warning_msg) != std::string::npos;
189  EXPECT_TRUE(found) << std::endl
190  << "FOUND: " << msgs.str()
191  << std::endl
192  << "EXPECTED (as substring): " << warning_msg
193  << std::endl;
194 }
195 
197  std::string model_name = "unnamed_unit_test";
198  std::stringstream ss(model_text);
199  std::stringstream msgs;
202  // fake reader history - model is parseable, no includes
203  reader.add_event(0, 0, "start", "unnamed_unit_test");
204  reader.add_event(500, 500, "end", "unnamed_unit_test");
205  bool parsable = stan::lang::parse(&msgs, ss, model_name, reader, prog);
206  EXPECT_TRUE(parsable);
207 
208  std::stringstream output;
209  stan::lang::generate_cpp(prog, model_name, reader.history(), output);
210  return output.str();
211 }
212 
213 
214 void expect_matches(int n,
215  const std::string& stan_code,
216  const std::string& target) {
217  std::string model_cpp = model_to_cpp(stan_code);
218  EXPECT_EQ(n, count_matches(target, model_cpp))
219  << "looking for: " << target;
220 }
221 
223  const std::string& model_name) {
224  std::string path("src/test/test-models/");
225  path += folder;
226  path += "/";
227  path += model_name;
228  path += ".stan";
229  return path;
230 }
231 
232 void expect_match(const std::string& model_name,
233  const std::string& target,
234  bool allow_undefined = false) {
235  std::stringstream msgs;
236  std::string file_name = get_file_name("good", model_name);
237  std::ifstream file_stream(file_name.c_str());
238  std::stringstream cpp_out_stream;
239  stan::lang::compile(&msgs, file_stream, cpp_out_stream,
240  model_name, allow_undefined);
241  std::string cpp_out = cpp_out_stream.str();
242  file_stream.close();
243  EXPECT_TRUE(count_matches(target, cpp_out) > 0)
244  << "looking for: " << target << std::endl
245  << "found: " << cpp_out << std::endl;
246 }
247 
248 /**
249  * Thest that model of specified name in test/test-models/good
250  * has exactly the specified number of matches
251  *
252  * @param[in] model_name Name of model file.
253  * @param[in] warning_msg Message to count.
254  * @param[in] n Expected number of message occurrences.
255  */
256 void test_num_warnings(const std::string& model_name,
257  const std::string& warning_msg,
258  int n) {
259  std::stringstream msgs;
260  EXPECT_TRUE(is_parsable_folder(model_name, "good", &msgs));
261  EXPECT_EQ(n, count_matches(warning_msg, msgs.str()))
262  << "looking for: " << warning_msg;
263 }
264 #endif
std::string get_file_name(const std::string &folder, const std::string &model_name)
Definition: utility.hpp:222
const XML_Char * name
Definition: expat.h:151
ofstream output
bool compile(std::ostream *msgs, std::istream &in, std::ostream &out, const std::string &name, const bool allow_undefined=false, const std::string &filename="unknown file name", const std::vector< std::string > &include_paths=std::vector< std::string >())
Definition: compiler.hpp:35
int count_matches(const std::string &target, const std::string &s)
Definition: util.hpp:19
const XML_Char * target
Definition: expat.h:268
void add_event(int concat_line_num, int line_num, const std::string &action, const std::string &path)
Float_t ss
Definition: plot.C:24
void expect_matches(int n, const std::string &stan_code, const std::string &target)
Definition: utility.hpp:214
void test_parsable_standalone_functions(const std::string &model_name)
Definition: utility.hpp:112
void test_throws(const std::string &model_name, const std::string &error_msg)
Definition: utility.hpp:126
const XML_Char * s
Definition: expat.h:262
void test_warning(const std::string &model_name, const std::string &warning_msg)
Definition: utility.hpp:184
bool parse(std::ostream *out, std::istream &in, const std::string &name, const io::program_reader &reader, program &prog, const bool allow_undefined=false)
Definition: parser.hpp:35
void generate_cpp(const program &prog, const std::string &model_name, const std::vector< io::preproc_event > &history, std::ostream &o)
void invalid_argument(const char *function, const char *name, const T &y, const char *msg1, const char *msg2)
const std::vector< preproc_event > & history() const
std::string model_to_cpp(const std::string &model_text)
Definition: utility.hpp:196
void test_parsable(const std::string &model_name)
Definition: utility.hpp:94
void expect_match(const std::string &model_name, const std::string &target, bool allow_undefined=false)
Definition: utility.hpp:232
const std::string path
Definition: plot_BEN.C:43
std::string program() const
::xsd::cxx::tree::string< char, simple_type > string
Definition: Database.h:154
bool is_parsable(const std::string &file_name, std::ostream *msgs=0, bool allow_undefined=false)
Definition: utility.hpp:51
bool is_parsable_folder(const std::string &model_name, const std::string folder="good", std::ostream *msgs=0, const std::string extension=".stan")
Definition: utility.hpp:77
void test_num_warnings(const std::string &model_name, const std::string &warning_msg, int n)
Definition: utility.hpp:256
Float_t e
Definition: plot.C:35
#define FAIL
std::string file_name_to_model_name(const std::string &name)
Definition: utility.hpp:27