diff --git a/src/context.cc b/src/context.cc index bf6a0c05..465cd6ed 100644 --- a/src/context.cc +++ b/src/context.cc @@ -69,29 +69,45 @@ Context::~Context() if (!parent) delete this->ctx_stack; } -/*! - Initialize context from a module argument list and a evaluation context - which may pass variables which will be preferred over default values. -*/ -void Context::setVariables(const AssignmentList &args, - const EvalContext *evalctx) +const Context::Expressions Context::getExpressions(const AssignmentList &args, const EvalContext *evalctx) { + Expressions expressions; + for(const auto &arg : args) { - set_variable(arg.name, arg.expr ? arg.expr->evaluate(this->parent) : ValuePtr::undefined); + expressions[arg.name] = arg.expr.get(); // NOTE: this can assign NULL pointers! } if (evalctx) { size_t posarg = 0; for (size_t i=0; inumArgs(); i++) { const std::string &name = evalctx->getArgName(i); - ValuePtr val = evalctx->getArgValue(i); + const Expression *expr = evalctx->getArgs()[i].expr.get(); if (name.empty()) { - if (posarg < args.size()) this->set_variable(args[posarg++].name, val); + if (posarg < args.size()) { + const Assignment assignment = args[posarg++]; + expressions[assignment.name] = expr; + } } else { - this->set_variable(name, val); + expressions[name] = expr; } } } + + return expressions; +} + +/*! + Initialize context from a module argument list and a evaluation context + which may pass variables which will be preferred over default values. +*/ +const Context::Expressions Context::setVariables(const AssignmentList &args, const EvalContext *evalctx) +{ + const Expressions expressions = getExpressions(args, evalctx); + for (const auto &expr : expressions) { + const ValuePtr val = expr.second ? expr.second->evaluate(evalctx) : ValuePtr::undefined; + this->set_variable(expr.first, val); + } + return expressions; } void Context::set_variable(const std::string &name, const ValuePtr &value) diff --git a/src/context.h b/src/context.h index f9783409..18cc63b7 100644 --- a/src/context.h +++ b/src/context.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -11,6 +12,8 @@ class Context { public: typedef std::vector Stack; + typedef std::map Expressions; + Context(const Context *parent = NULL); virtual ~Context(); @@ -18,15 +21,15 @@ public: virtual ValuePtr evaluate_function(const std::string &name, const class EvalContext *evalctx) const; virtual class AbstractNode *instantiate_module(const class ModuleInstantiation &inst, EvalContext *evalctx) const; - void setVariables(const AssignmentList &args, - const class EvalContext *evalctx = NULL); + const Expressions getExpressions(const AssignmentList &args, const class EvalContext *evalctx); + const Expressions setVariables(const AssignmentList &args, const class EvalContext *evalctx = NULL); void set_variable(const std::string &name, const ValuePtr &value); void set_variable(const std::string &name, const Value &value); void set_constant(const std::string &name, const ValuePtr &value); void set_constant(const std::string &name, const Value &value); - void apply_variables(const Context &other); + void apply_variables(const Context &other); ValuePtr lookup_variable(const std::string &name, bool silent = false) const; bool has_local_variable(const std::string &name) const; diff --git a/src/control.cc b/src/control.cc index 6fcb2680..f76e3a25 100644 --- a/src/control.cc +++ b/src/control.cc @@ -42,6 +42,7 @@ public: // types CHILD, CHILDREN, ECHO, + ASSERT, ASSIGN, FOR, LET, @@ -49,9 +50,9 @@ public: // types IF }; public: // methods - ControlModule(Type type) - : type(type) - { } + ControlModule(Type type) : type(type) { } + + ControlModule(Type type, const Feature& feature) : AbstractModule(feature), type(type) { } virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const; @@ -276,6 +277,16 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns } break; + case ASSERT: { + node = new GroupNode(inst); + + Context c(evalctx); + evaluate_assert(c, evalctx, inst->location()); + inst->scope.apply(c); + node->children = inst->instantiateChildren(&c); + } + break; + case LET: { node = new GroupNode(inst); Context c(evalctx); @@ -338,6 +349,7 @@ void register_builtin_control() Builtins::init("child", new ControlModule(ControlModule::CHILD)); Builtins::init("children", new ControlModule(ControlModule::CHILDREN)); Builtins::init("echo", new ControlModule(ControlModule::ECHO)); + Builtins::init("assert", new ControlModule(ControlModule::ASSERT, Feature::ExperimentalAssertExpression)); Builtins::init("assign", new ControlModule(ControlModule::ASSIGN)); Builtins::init("for", new ControlModule(ControlModule::FOR)); Builtins::init("let", new ControlModule(ControlModule::LET)); diff --git a/src/evalcontext.h b/src/evalcontext.h index 08b499df..09f89d2c 100644 --- a/src/evalcontext.h +++ b/src/evalcontext.h @@ -19,6 +19,7 @@ public: size_t numArgs() const { return this->eval_arguments.size(); } const std::string &getArgName(size_t i) const; ValuePtr getArgValue(size_t i, const Context *ctx = NULL) const; + const AssignmentList & getArgs() const { return this->eval_arguments; } size_t numChildren() const; ModuleInstantiation *getChild(size_t i) const; diff --git a/src/exceptions.h b/src/exceptions.h index 8cf58f41..c90024cd 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -9,6 +9,12 @@ public: virtual ~EvaluationException() throw() {} }; +class AssertionFailedException : public EvaluationException { +public: + AssertionFailedException(const std::string &what_arg) : EvaluationException(what_arg) {} + virtual ~AssertionFailedException() throw() {} +}; + class RecursionException: public EvaluationException { public: static RecursionException create(const char *recursiontype, const std::string &name) { diff --git a/src/expr.cc b/src/expr.cc index 45c568ea..62baf9b6 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -36,6 +36,9 @@ #include "feature.h" #include +#include +using namespace boost::assign; // bring 'operator+=()' into scope + // unnamed namespace namespace { bool isListComprehension(const shared_ptr &e) { @@ -399,6 +402,40 @@ void FunctionCall::print(std::ostream &stream) const stream << this->name << "(" << this->arguments << ")"; } +Expression * FunctionCall::create(const std::string &funcname, const AssignmentList &arglist, Expression *expr, const Location &loc) +{ + if (funcname == "assert" && Feature::ExperimentalAssertExpression.is_enabled()) { + return new Assert(arglist, expr, loc); + } else if (funcname == "let") { + return new Let(arglist, expr, loc); + } + + // TODO: Generate error/warning if expr != 0? + return new FunctionCall(funcname, arglist, loc); +} + +Assert::Assert(const AssignmentList &args, Expression *expr, const Location &loc) + : Expression(loc), arguments(args), expr(expr) +{ + +} + +ValuePtr Assert::evaluate(const Context *context) const +{ + EvalContext assert_context(context, this->arguments); + + Context c(&assert_context); + evaluate_assert(c, &assert_context, loc); + + ValuePtr result = expr ? expr->evaluate(&c) : ValuePtr::undefined; + return result; +} + +void Assert::print(std::ostream &stream) const +{ + stream << "assert(" << this->arguments << ") " << *expr; +} + Let::Let(const AssignmentList &args, Expression *expr, const Location &loc) : Expression(loc), arguments(args), expr(expr) { @@ -612,3 +649,30 @@ std::ostream &operator<<(std::ostream &stream, const Expression &expr) expr.print(stream); return stream; } + +void evaluate_assert(const Context &context, const class EvalContext *evalctx, const Location &loc) +{ + ExperimentalFeatureException::check(Feature::ExperimentalAssertExpression); + + AssignmentList args; + args += Assignment("condition"), Assignment("message"); + + Context c(&context); + const Context::Expressions expressions = c.setVariables(args, evalctx); + const ValuePtr condition = c.lookup_variable("condition"); + + if (!condition->toBool()) { + std::stringstream msg; + msg << "ERROR: Assertion"; + const Expression *expr = expressions.at("condition"); + if (expr) { + msg << " '" << *expr << "'"; + } + msg << " failed, line " << loc.firstLine(); + const ValuePtr message = c.lookup_variable("message", true); + if (message->isDefined()) { + msg << ": " << message->toEchoString(); + } + throw AssertionFailedException(msg.str()); + } +} \ No newline at end of file diff --git a/src/expression.h b/src/expression.h index 8b1e1ff4..3a41208c 100644 --- a/src/expression.h +++ b/src/expression.h @@ -154,11 +154,23 @@ public: FunctionCall(const std::string &funcname, const AssignmentList &arglist, const Location &loc); ValuePtr evaluate(const class Context *context) const; virtual void print(std::ostream &stream) const; + static Expression * create(const std::string &funcname, const AssignmentList &arglist, Expression *expr, const Location &loc); public: std::string name; AssignmentList arguments; }; +class Assert : public Expression +{ +public: + Assert(const AssignmentList &args, Expression *expr, const Location &loc); + ValuePtr evaluate(const class Context *context) const; + virtual void print(std::ostream &stream) const; +private: + AssignmentList arguments; + shared_ptr expr; +}; + class Let : public Expression { public: @@ -233,3 +245,5 @@ private: AssignmentList arguments; shared_ptr expr; }; + +void evaluate_assert(const Context &context, const class EvalContext *evalctx, const Location &loc); \ No newline at end of file diff --git a/src/feature.cc b/src/feature.cc index 1f97190b..00285b69 100644 --- a/src/feature.cc +++ b/src/feature.cc @@ -19,6 +19,7 @@ Feature::list_t Feature::feature_list; * argument to enable the option and for saving the option value in GUI * context. */ +const Feature Feature::ExperimentalAssertExpression("assert", "Enable assert."); const Feature Feature::ExperimentalEachExpression("lc-each", "Enable each expression in list comprehensions."); const Feature Feature::ExperimentalElseExpression("lc-else", "Enable else expression in list comprehensions."); const Feature Feature::ExperimentalForCExpression("lc-for-c", "Enable C-style for expression in list comprehensions."); diff --git a/src/feature.h b/src/feature.h index 0e8b5742..1261d340 100644 --- a/src/feature.h +++ b/src/feature.h @@ -14,6 +14,7 @@ public: typedef std::vector list_t; typedef list_t::iterator iterator; + static const Feature ExperimentalAssertExpression; static const Feature ExperimentalEachExpression; static const Feature ExperimentalElseExpression; static const Feature ExperimentalForCExpression; diff --git a/src/mainwin.cc b/src/mainwin.cc index 1a03c511..436de1e9 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -92,6 +92,13 @@ #include #include +#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) +#include +#define QT_HTML_ESCAPE(qstring) Qt::escape(qstring) +#else +#define QT_HTML_ESCAPE(qstring) (qstring).toHtmlEscaped() +#endif + #if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0)) // Set dummy for Qt versions that do not have QSaveFile #define QT_FILE_SAVE_CLASS QFile @@ -2671,10 +2678,10 @@ void MainWindow::consoleOutput(const QString &msg) QString qmsg; if (msg.startsWith("WARNING:") || msg.startsWith("DEPRECATED:")) { this->compileWarnings++; - qmsg = "" + msg + "\n"; + qmsg = "" + QT_HTML_ESCAPE(QString(msg)) + "\n"; } else if (msg.startsWith("ERROR:")) { this->compileErrors++; - qmsg = "" + msg + "\n"; + qmsg = "" + QT_HTML_ESCAPE(QString(msg)) + "\n"; } else { qmsg = msg; diff --git a/src/parser.y b/src/parser.y index cb440fb3..ab3e9a59 100644 --- a/src/parser.y +++ b/src/parser.y @@ -105,7 +105,7 @@ fs::path parser_sourcefile; %token LE GE EQ NE AND OR -%right LET +%left HIGH_PRIO_LEFT %right '?' ':' @@ -120,11 +120,14 @@ fs::path parser_sourcefile; %left '[' ']' %left '.' +%left LOW_PRIO_LEFT + %type expr %type vector_expr %type list_comprehension_elements %type list_comprehension_elements_p %type list_comprehension_elements_or_expr +%type expr_or_empty %type module_instantiation %type if_statement @@ -337,11 +340,6 @@ expr: { $$ = new Literal(ValuePtr($1), LOC(@$)); } - | TOK_LET '(' arguments_call ')' expr %prec LET - { - $$ = new Let(*$3, $5, LOC(@$)); - delete $3; - } | '[' expr ':' expr ']' { $$ = new Range($2, $4, LOC(@$)); @@ -434,14 +432,30 @@ expr: { $$ = new ArrayLookup($1, $3, LOC(@$)); } - | TOK_ID '(' arguments_call ')' + | TOK_ID '(' arguments_call ')' expr_or_empty { - $$ = new FunctionCall($1, *$3, LOC(@$)); - free($1); - delete $3; - } + $$ = FunctionCall::create($1, *$3, $5, LOC(@$)); + free($1); + delete $3; + } + | TOK_LET '(' arguments_call ')' expr_or_empty + { + $$ = FunctionCall::create("let", *$3, $5, LOC(@$)); + delete $3; + } ; +expr_or_empty: + %prec LOW_PRIO_LEFT + { + $$ = NULL; + } + | expr %prec HIGH_PRIO_LEFT + { + $$ = $1; + } + ; + list_comprehension_elements: /* The last set element may not be a "let" (as that would instead be parsed as an expression) */ diff --git a/src/value.cc b/src/value.cc index 4cd21f35..9491b5cd 100644 --- a/src/value.cc +++ b/src/value.cc @@ -267,6 +267,15 @@ std::string Value::toString() const return boost::apply_visitor(tostring_visitor(), this->value); } +std::string Value::toEchoString() const +{ + if (type() == Value::STRING) { + return std::string("\"") + toString() + '"'; + } else { + return toString(); + } +} + class chr_visitor : public boost::static_visitor { public: template std::string operator()(const S &) const diff --git a/src/value.h b/src/value.h index da57371c..afa7aa5f 100644 --- a/src/value.h +++ b/src/value.h @@ -169,6 +169,7 @@ public: bool getFiniteDouble(double &v) const; bool toBool() const; std::string toString() const; + std::string toEchoString() const; std::string chrString() const; const VectorType &toVector() const; bool getVec2(double &x, double &y, bool ignoreInfinite = false) const; diff --git a/testdata/scad/functions/assert-expression-fail1-test.scad b/testdata/scad/functions/assert-expression-fail1-test.scad new file mode 100644 index 00000000..81dd6d72 --- /dev/null +++ b/testdata/scad/functions/assert-expression-fail1-test.scad @@ -0,0 +1,2 @@ +v = assert(false); +echo(v); diff --git a/testdata/scad/functions/assert-expression-fail2-test.scad b/testdata/scad/functions/assert-expression-fail2-test.scad new file mode 100644 index 00000000..e363f443 --- /dev/null +++ b/testdata/scad/functions/assert-expression-fail2-test.scad @@ -0,0 +1,4 @@ +a = 10; +b = 20; +v = assert(a < 20 && b < 20, "Test! &"); +echo(v); diff --git a/testdata/scad/functions/assert-expression-fail3-test.scad b/testdata/scad/functions/assert-expression-fail3-test.scad new file mode 100644 index 00000000..fe9e0b44 --- /dev/null +++ b/testdata/scad/functions/assert-expression-fail3-test.scad @@ -0,0 +1,7 @@ +function f(x) = sin(x); + +module m(angle) { + v = assert(f(angle) > 0) 10; +} + +m(270); diff --git a/testdata/scad/functions/assert-expression-tests.scad b/testdata/scad/functions/assert-expression-tests.scad new file mode 100644 index 00000000..cdf78295 --- /dev/null +++ b/testdata/scad/functions/assert-expression-tests.scad @@ -0,0 +1,25 @@ +a = 3; +b = 6; + +t0 = assert(true); +echo(t0 = t0); + +t1 = assert("t1"); +echo(t1 = t1); + +t2 = assert(a*b); +echo(t2 = t2); + +t3 = assert(condition = a*b); +echo(t3 = t3); + +t4 = assert(true) a*b; +echo(t4 = t4); + +c = 2; +t5 = assert(condition = 2) a*b*c; +echo(t5 = t5); + +d = c + 9; +t6 = assert(condition = d + 5 > 15, message = str("value: ", d + 5)) a*b*c*d; +echo(t6 = t6); diff --git a/testdata/scad/misc/assert-fail1-test.scad b/testdata/scad/misc/assert-fail1-test.scad new file mode 100644 index 00000000..d8fc3ea0 --- /dev/null +++ b/testdata/scad/misc/assert-fail1-test.scad @@ -0,0 +1 @@ +assert(false); \ No newline at end of file diff --git a/testdata/scad/misc/assert-fail2-test.scad b/testdata/scad/misc/assert-fail2-test.scad new file mode 100644 index 00000000..0db2fcdd --- /dev/null +++ b/testdata/scad/misc/assert-fail2-test.scad @@ -0,0 +1,3 @@ +a = 10; +b = 20; +assert(a < 20 && b < 20, "Test! &"); diff --git a/testdata/scad/misc/assert-fail3-test.scad b/testdata/scad/misc/assert-fail3-test.scad new file mode 100644 index 00000000..c0fdba10 --- /dev/null +++ b/testdata/scad/misc/assert-fail3-test.scad @@ -0,0 +1,7 @@ +function f(x) = sin(x); + +module m(angle) { + assert(f(angle) > 0) cube(10); +} + +m(270); diff --git a/testdata/scad/misc/assert-tests.scad b/testdata/scad/misc/assert-tests.scad new file mode 100644 index 00000000..96703eb2 --- /dev/null +++ b/testdata/scad/misc/assert-tests.scad @@ -0,0 +1,24 @@ +a = 3; +b = 6; + +assert(true); + +assert("t1"); + +assert(a*b); + +assert(condition = a*b); + +assert(true) cube(8, center = true); + +c = 2; +translate([0, 20, 0]) +assert(condition = 2) +sphere(5); + +d = c + 9; +assert(condition = d + 5 > 15, message = str("value: ", d + 5)) +translate([15, 0, 0]) +cylinder(8, 5, center = true); + +echo("assert-tests"); \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c921e515..01cb85ef 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1032,7 +1032,7 @@ function(add_cmdline_test TESTCMD_BASENAME) if (${EXPERIMENTAL} EQUAL -1) set(EXPERIMENTAL_OPTION "") else() - set(EXPERIMENTAL_OPTION "--enable=lc-each" "--enable=lc-else" "--enable=lc-for-c") + set(EXPERIMENTAL_OPTION "--enable=assert" "--enable=lc-each" "--enable=lc-else" "--enable=lc-for-c") endif() # 2D tests should be viewed from the top, not an angle. @@ -1161,6 +1161,10 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES} ${CMAKE_SOURCE_DIR}/../testdata/scad/3D/features/for-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/expression-evaluation-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/echo-tests.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/assert-tests.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/assert-fail1-test.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/assert-fail2-test.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/assert-fail3-test.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/parser-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/builtin-tests.scad @@ -1205,6 +1209,7 @@ list(APPEND DUMPTEST_FILES ${FEATURES_2D_FILES} ${FEATURES_3D_FILES} ${DEPRECATE list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/assert-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/let-module-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad @@ -1216,6 +1221,7 @@ list(APPEND CGALPNGTEST_2D_FILES ${FEATURES_2D_FILES} ${SCAD_DXF_FILES} ${EXAMPL list(APPEND CGALPNGTEST_3D_FILES ${FEATURES_3D_FILES} ${DEPRECATED_3D_FILES} ${ISSUES_3D_FILES} ${EXAMPLE_3D_FILES}) list(APPEND CGALPNGTEST_3D_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/assert-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/let-module-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad @@ -1350,7 +1356,20 @@ disable_tests(csgpngtest_primitive-inf-tests cgalpngtest_empty-shape-tests csgpngtest_issue1258) -experimental_tests(echotest_list-comprehensions-experimental) +experimental_tests(echotest_list-comprehensions-experimental + echotest_assert-tests + cgalpngtest_assert-tests + opencsgtest_assert-tests + csgpngtest_assert-tests + throwntogethertest_assert-tests + echotest_assert-fail1-test + echotest_assert-fail2-test + echotest_assert-fail3-test + echotest_echo-expression-tests + echotest_assert-expression-tests + echotest_assert-expression-fail1-test + echotest_assert-expression-fail2-test + echotest_assert-expression-fail3-test) # Test config handling diff --git a/tests/regression/cgalpngtest/assert-tests-expected.png b/tests/regression/cgalpngtest/assert-tests-expected.png new file mode 100644 index 00000000..fc7c37f3 Binary files /dev/null and b/tests/regression/cgalpngtest/assert-tests-expected.png differ diff --git a/tests/regression/dumptest/assert-tests-expected.csg b/tests/regression/dumptest/assert-tests-expected.csg new file mode 100644 index 00000000..fb6a5306 --- /dev/null +++ b/tests/regression/dumptest/assert-tests-expected.csg @@ -0,0 +1,2 @@ +multmatrix([[1, 0, 0, 0], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]); +group(); diff --git a/tests/regression/echotest/assert-expression-fail1-test-expected.echo b/tests/regression/echotest/assert-expression-fail1-test-expected.echo new file mode 100644 index 00000000..d093613f --- /dev/null +++ b/tests/regression/echotest/assert-expression-fail1-test-expected.echo @@ -0,0 +1 @@ +ERROR: Assertion 'false' failed, line 1 diff --git a/tests/regression/echotest/assert-expression-fail2-test-expected.echo b/tests/regression/echotest/assert-expression-fail2-test-expected.echo new file mode 100644 index 00000000..9c620f23 --- /dev/null +++ b/tests/regression/echotest/assert-expression-fail2-test-expected.echo @@ -0,0 +1 @@ +ERROR: Assertion '((a < 20) && (b < 20))' failed, line 3: "Test! &" diff --git a/tests/regression/echotest/assert-expression-fail3-test-expected.echo b/tests/regression/echotest/assert-expression-fail3-test-expected.echo new file mode 100644 index 00000000..1528c368 --- /dev/null +++ b/tests/regression/echotest/assert-expression-fail3-test-expected.echo @@ -0,0 +1 @@ +ERROR: Assertion '(f(angle) > 0)' failed, line 4 diff --git a/tests/regression/echotest/assert-expression-tests-expected.echo b/tests/regression/echotest/assert-expression-tests-expected.echo new file mode 100644 index 00000000..f53c1512 --- /dev/null +++ b/tests/regression/echotest/assert-expression-tests-expected.echo @@ -0,0 +1,7 @@ +ECHO: t0 = undef +ECHO: t1 = undef +ECHO: t2 = undef +ECHO: t3 = undef +ECHO: t4 = 18 +ECHO: t5 = 36 +ECHO: t6 = 396 diff --git a/tests/regression/echotest/assert-fail1-test-expected.echo b/tests/regression/echotest/assert-fail1-test-expected.echo new file mode 100644 index 00000000..d093613f --- /dev/null +++ b/tests/regression/echotest/assert-fail1-test-expected.echo @@ -0,0 +1 @@ +ERROR: Assertion 'false' failed, line 1 diff --git a/tests/regression/echotest/assert-fail2-test-expected.echo b/tests/regression/echotest/assert-fail2-test-expected.echo new file mode 100644 index 00000000..9c620f23 --- /dev/null +++ b/tests/regression/echotest/assert-fail2-test-expected.echo @@ -0,0 +1 @@ +ERROR: Assertion '((a < 20) && (b < 20))' failed, line 3: "Test! &" diff --git a/tests/regression/echotest/assert-fail3-test-expected.echo b/tests/regression/echotest/assert-fail3-test-expected.echo new file mode 100644 index 00000000..1528c368 --- /dev/null +++ b/tests/regression/echotest/assert-fail3-test-expected.echo @@ -0,0 +1 @@ +ERROR: Assertion '(f(angle) > 0)' failed, line 4 diff --git a/tests/regression/echotest/assert-tests-expected.echo b/tests/regression/echotest/assert-tests-expected.echo new file mode 100644 index 00000000..228aabad --- /dev/null +++ b/tests/regression/echotest/assert-tests-expected.echo @@ -0,0 +1 @@ +ECHO: "assert-tests" diff --git a/tests/regression/opencsgtest/assert-tests-expected.png b/tests/regression/opencsgtest/assert-tests-expected.png new file mode 100644 index 00000000..d33ffa8e Binary files /dev/null and b/tests/regression/opencsgtest/assert-tests-expected.png differ diff --git a/tests/regression/throwntogethertest/assert-tests-expected.png b/tests/regression/throwntogethertest/assert-tests-expected.png new file mode 100644 index 00000000..c4c70d78 Binary files /dev/null and b/tests/regression/throwntogethertest/assert-tests-expected.png differ