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