76 lines
2.1 KiB
C++
76 lines
2.1 KiB
C++
#include "catch.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
#include "Formula.h"
|
|
|
|
TEST_CASE("Formula compiles a constant expression", "[formula]")
|
|
{
|
|
const Formula f = Formula::compile("42");
|
|
|
|
REQUIRE(f.isValid());
|
|
REQUIRE(f.evaluate(0.0) == Approx(42.0));
|
|
REQUIRE(f.evaluate(100.0) == Approx(42.0));
|
|
}
|
|
|
|
TEST_CASE("Formula evaluates a linear expression in x", "[formula]")
|
|
{
|
|
// Matches world.toml [waves].threat_rate_formula default.
|
|
const Formula f = Formula::compile("1*x - 30");
|
|
|
|
REQUIRE(f.evaluate(0.0) == Approx(-30.0));
|
|
REQUIRE(f.evaluate(30.0) == Approx(0.0));
|
|
REQUIRE(f.evaluate(60.0) == Approx(30.0));
|
|
}
|
|
|
|
TEST_CASE("Formula evaluates a polynomial in x", "[formula]")
|
|
{
|
|
const Formula f = Formula::compile("2 + 3*x*x");
|
|
|
|
REQUIRE(f.evaluate(0.0) == Approx(2.0));
|
|
REQUIRE(f.evaluate(2.0) == Approx(14.0));
|
|
REQUIRE(f.evaluate(4.0) == Approx(50.0));
|
|
}
|
|
|
|
TEST_CASE("Formula retains its source string", "[formula]")
|
|
{
|
|
const std::string source = "10 + x / 5";
|
|
const Formula f = Formula::compile(source);
|
|
|
|
REQUIRE(f.source() == source);
|
|
}
|
|
|
|
TEST_CASE("Formula throws on malformed source", "[formula]")
|
|
{
|
|
REQUIRE_THROWS_AS(Formula::compile("1 +"), std::runtime_error);
|
|
REQUIRE_THROWS_AS(Formula::compile(""), std::runtime_error);
|
|
REQUIRE_THROWS_AS(Formula::compile("unknown_var"), std::runtime_error);
|
|
}
|
|
|
|
TEST_CASE("Formula survives move construction", "[formula]")
|
|
{
|
|
// tinyexpr bakes the bound variable's address into the compiled tree.
|
|
// Formula keeps x on the heap so that address stays valid across moves.
|
|
Formula original = Formula::compile("x * 2");
|
|
Formula moved(std::move(original));
|
|
|
|
REQUIRE(moved.evaluate(21.0) == Approx(42.0));
|
|
}
|
|
|
|
TEST_CASE("Formula survives move assignment", "[formula]")
|
|
{
|
|
Formula a = Formula::compile("x + 1");
|
|
Formula b = Formula::compile("x + 100");
|
|
|
|
b = std::move(a);
|
|
|
|
REQUIRE(b.evaluate(5.0) == Approx(6.0));
|
|
}
|
|
|
|
TEST_CASE("Default-constructed Formula is invalid and throws on evaluate", "[formula]")
|
|
{
|
|
const Formula f;
|
|
REQUIRE_FALSE(f.isValid());
|
|
REQUIRE_THROWS_AS(f.evaluate(0.0), std::runtime_error);
|
|
}
|