OpenVDB  8.1.0
util.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
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...
Logging system to collect errors and warnings throughout the different stages of parsing and compilat...
Parsing methods for creating abstract syntax trees out of AX code.
Various function and operator tokens used throughout the AST and code generation.
Definition: util.h:52
void replace(std::string &str, const std::string &oldStr, const std::string &newStr)
Definition: util.h:61
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
std::vector< std::pair< std::string, openvdb::ax::ast::Node::Ptr > > CodeTests
Definition: util.h:56