OpenVDB  9.0.1
util.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file test/util.h
5 ///
6 /// @author Nick Avramoussis
7 ///
8 /// @brief Test utilities
9 
10 #ifndef OPENVDB_AX_UNITTEST_UTIL_HAS_BEEN_INCLUDED
11 #define OPENVDB_AX_UNITTEST_UTIL_HAS_BEEN_INCLUDED
12 
13 #include <openvdb_ax/ast/AST.h>
14 #include <openvdb_ax/ast/Parse.h>
15 #include <openvdb_ax/ast/Tokens.h>
17 
18 #include <openvdb/Types.h>
19 
20 #include <memory>
21 #include <vector>
22 #include <utility>
23 #include <string>
24 #include <type_traits>
25 
26 #define ERROR_MSG(Msg, Code) Msg + std::string(": \"") + Code + std::string("\"")
27 
28 #define TEST_SYNTAX_PASSES(Tests) \
29 { \
30  openvdb::ax::Logger logger;\
31  for (const auto& test : Tests) { \
32  logger.clear();\
33  const std::string& code = test.first; \
34  openvdb::ax::ast::Tree::ConstPtr tree = openvdb::ax::ast::parse(code.c_str(), logger);\
35  std::stringstream str; \
36  CPPUNIT_ASSERT_MESSAGE(ERROR_MSG("Unexpected parsing error(s)\n", str.str()), tree); \
37  } \
38 } \
39 
40 #define TEST_SYNTAX_FAILS(Tests) \
41 { \
42  openvdb::ax::Logger logger([](const std::string&) {});\
43  for (const auto& test : Tests) { \
44  logger.clear();\
45  const std::string& code = test.first; \
46  openvdb::ax::ast::Tree::ConstPtr tree = openvdb::ax::ast::parse(code.c_str(), logger);\
47  CPPUNIT_ASSERT_MESSAGE(ERROR_MSG("Expected parsing error", code), logger.hasError()); \
48  } \
49 } \
50 
51 namespace unittest_util
52 {
53 // Use shared pointers rather than unique pointers so initializer lists can easily
54 // be used. Could easily introduce some move semantics to work around this if
55 // necessary.
56 using CodeTests = std::vector<std::pair<std::string, openvdb::ax::ast::Node::Ptr>>;
57 
58 //
59 
60 // Find + Replace all string helper
61 inline void replace(std::string& str, const std::string& oldStr, const std::string& newStr)
62 {
63  std::string::size_type pos = 0u;
64  while ((pos = str.find(oldStr, pos)) != std::string::npos) {
65  str.replace(pos, oldStr.length(), newStr);
66  pos += newStr.length();
67  }
68 }
69 
70 //
71 
72 inline bool compareLinearTrees(const std::vector<const openvdb::ax::ast::Node*>& a,
73  const std::vector<const openvdb::ax::ast::Node*>& b, const bool allowEmpty = false)
74 {
75  if (!allowEmpty && (a.empty() || b.empty())) return false;
76  if (a.size() != b.size()) return false;
77  const size_t size = a.size();
78  for (size_t i = 0; i < size; ++i) {
79  if ((a[i] == nullptr) ^ (b[i] == nullptr)) return false;
80  if (a[i] == nullptr) continue;
81  if (a[i]->nodetype() != b[i]->nodetype()) return false;
82 
83  // Specific handling of various node types to compare child data
84  // @todo generalize this
85  // @note Value methods does not compare child text data
86 
87  if (a[i]->nodetype() == openvdb::ax::ast::Node::AssignExpressionNode) {
88  if (static_cast<const openvdb::ax::ast::AssignExpression*>(a[i])->operation() !=
89  static_cast<const openvdb::ax::ast::AssignExpression*>(b[i])->operation()) {
90  return false;
91  }
92  }
93  else if (a[i]->nodetype() == openvdb::ax::ast::Node::BinaryOperatorNode) {
94  if (static_cast<const openvdb::ax::ast::BinaryOperator*>(a[i])->operation() !=
95  static_cast<const openvdb::ax::ast::BinaryOperator*>(b[i])->operation()) {
96  return false;
97  }
98  }
99  else if (a[i]->nodetype() == openvdb::ax::ast::Node::CrementNode) {
100  if (static_cast<const openvdb::ax::ast::Crement*>(a[i])->operation() !=
101  static_cast<const openvdb::ax::ast::Crement*>(b[i])->operation()) {
102  return false;
103  }
104  if (static_cast<const openvdb::ax::ast::Crement*>(a[i])->post() !=
105  static_cast<const openvdb::ax::ast::Crement*>(b[i])->post()) {
106  return false;
107  }
108  }
109  else if (a[i]->nodetype() == openvdb::ax::ast::Node::CastNode) {
110  if (static_cast<const openvdb::ax::ast::Cast*>(a[i])->type() !=
111  static_cast<const openvdb::ax::ast::Cast*>(b[i])->type()) {
112  return false;
113  }
114  }
115  else if (a[i]->nodetype() == openvdb::ax::ast::Node::FunctionCallNode) {
116  if (static_cast<const openvdb::ax::ast::FunctionCall*>(a[i])->name() !=
117  static_cast<const openvdb::ax::ast::FunctionCall*>(b[i])->name()) {
118  return false;
119  }
120  }
121  else if (a[i]->nodetype() == openvdb::ax::ast::Node::LoopNode) {
122  if (static_cast<const openvdb::ax::ast::Loop*>(a[i])->loopType() !=
123  static_cast<const openvdb::ax::ast::Loop*>(b[i])->loopType()) {
124  return false;
125  }
126  }
127  else if (a[i]->nodetype() == openvdb::ax::ast::Node::KeywordNode) {
128  if (static_cast<const openvdb::ax::ast::Keyword*>(a[i])->keyword() !=
129  static_cast<const openvdb::ax::ast::Keyword*>(b[i])->keyword()) {
130  return false;
131  }
132  }
133  else if (a[i]->nodetype() == openvdb::ax::ast::Node::AttributeNode) {
134  if (static_cast<const openvdb::ax::ast::Attribute*>(a[i])->type() !=
135  static_cast<const openvdb::ax::ast::Attribute*>(b[i])->type()) {
136  return false;
137  }
138  if (static_cast<const openvdb::ax::ast::Attribute*>(a[i])->name() !=
139  static_cast<const openvdb::ax::ast::Attribute*>(b[i])->name()) {
140  return false;
141  }
142  if (static_cast<const openvdb::ax::ast::Attribute*>(a[i])->inferred() !=
143  static_cast<const openvdb::ax::ast::Attribute*>(b[i])->inferred()) {
144  return false;
145  }
146  }
147  else if (a[i]->nodetype() == openvdb::ax::ast::Node::ExternalVariableNode) {
148  if (static_cast<const openvdb::ax::ast::ExternalVariable*>(a[i])->type() !=
149  static_cast<const openvdb::ax::ast::ExternalVariable*>(b[i])->type()) {
150  return false;
151  }
152  if (static_cast<const openvdb::ax::ast::ExternalVariable*>(a[i])->name() !=
153  static_cast<const openvdb::ax::ast::ExternalVariable*>(b[i])->name()) {
154  return false;
155  }
156  }
157  else if (a[i]->nodetype() == openvdb::ax::ast::Node::DeclareLocalNode) {
158  if (static_cast<const openvdb::ax::ast::DeclareLocal*>(a[i])->type() !=
159  static_cast<const openvdb::ax::ast::DeclareLocal*>(b[i])->type()) {
160  return false;
161  }
162  }
163  else if (a[i]->nodetype() == openvdb::ax::ast::Node::LocalNode) {
164  if (static_cast<const openvdb::ax::ast::Local*>(a[i])->name() !=
165  static_cast<const openvdb::ax::ast::Local*>(b[i])->name()) {
166  return false;
167  }
168  }
169  // @note Value methods does not compare child text data
170  else if (a[i]->nodetype() == openvdb::ax::ast::Node::ValueBoolNode) {
171  if (static_cast<const openvdb::ax::ast::Value<bool>*>(a[i])->value() !=
172  static_cast<const openvdb::ax::ast::Value<bool>*>(b[i])->value()) {
173  return false;
174  }
175  }
176  else if (a[i]->nodetype() == openvdb::ax::ast::Node::ValueInt16Node) {
177  if (static_cast<const openvdb::ax::ast::Value<int16_t>*>(a[i])->value() !=
178  static_cast<const openvdb::ax::ast::Value<int16_t>*>(b[i])->value()) {
179  return false;
180  }
181  }
182  else if (a[i]->nodetype() == openvdb::ax::ast::Node::ValueInt32Node) {
183  if (static_cast<const openvdb::ax::ast::Value<int32_t>*>(a[i])->value() !=
184  static_cast<const openvdb::ax::ast::Value<int32_t>*>(b[i])->value()) {
185  return false;
186  }
187  }
188  else if (a[i]->nodetype() == openvdb::ax::ast::Node::ValueInt64Node) {
189  if (static_cast<const openvdb::ax::ast::Value<int64_t>*>(a[i])->value() !=
190  static_cast<const openvdb::ax::ast::Value<int64_t>*>(b[i])->value()) {
191  return false;
192  }
193  }
194  else if (a[i]->nodetype() == openvdb::ax::ast::Node::ValueFloatNode) {
195  if (static_cast<const openvdb::ax::ast::Value<float>*>(a[i])->value() !=
196  static_cast<const openvdb::ax::ast::Value<float>*>(b[i])->value()) {
197  return false;
198  }
199  }
200  else if (a[i]->nodetype() == openvdb::ax::ast::Node::ValueDoubleNode) {
201  if (static_cast<const openvdb::ax::ast::Value<double>*>(a[i])->value() !=
202  static_cast<const openvdb::ax::ast::Value<double>*>(b[i])->value()) {
203  return false;
204  }
205  }
206  else if (a[i]->nodetype() == openvdb::ax::ast::Node::ValueStrNode) {
207  if (static_cast<const openvdb::ax::ast::Value<std::string>*>(a[i])->value() !=
208  static_cast<const openvdb::ax::ast::Value<std::string>*>(b[i])->value()) {
209  return false;
210  }
211  }
212  }
213  return true;
214 }
215 
216 inline std::vector<std::string>
217 nameSequence(const std::string& base, const size_t number)
218 {
219  std::vector<std::string> names;
220  if (number <= 0) return names;
221  names.reserve(number);
222 
223  for (size_t i = 1; i <= number; i++) {
224  names.emplace_back(base + std::to_string(i));
225  }
226 
227  return names;
228 }
229 }
230 
231 #endif // OPENVDB_AX_UNITTEST_UTIL_HAS_BEEN_INCLUDED
232 
Provides the definition for every abstract and concrete derived class which represent a particular ab...
Parsing methods for creating abstract syntax trees out of AX code.
std::vector< std::pair< std::string, openvdb::ax::ast::Node::Ptr >> CodeTests
Definition: util.h:56
void replace(std::string &str, const std::string &oldStr, const std::string &newStr)
Definition: util.h:61
ValueT value
Definition: GridBuilder.h:1287
Definition: util.h:51
Logging system to collect errors and warnings throughout the different stages of parsing and compilat...
Various function and operator tokens used throughout the AST and code generation. ...
std::vector< std::string > nameSequence(const std::string &base, const size_t number)
Definition: util.h:217
bool compareLinearTrees(const std::vector< const openvdb::ax::ast::Node * > &a, const std::vector< const openvdb::ax::ast::Node * > &b, const bool allowEmpty=false)
Definition: util.h:72