more nodes
This commit is contained in:
@@ -167,4 +167,248 @@ TEST_SUITE("WorldGraph::Nodes") {
|
||||
PositionYNode n;
|
||||
CHECK(n.Evaluate(c, {}).AsInt() == -3);
|
||||
}
|
||||
|
||||
// ── Min / Max / Clamp ─────────────────────────────────────────────────────
|
||||
|
||||
TEST_CASE("MinNode: returns smaller value") {
|
||||
MinNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(3.0f), Value::MakeFloat(7.0f) }).AsFloat()
|
||||
== doctest::Approx(3.0f));
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(7.0f), Value::MakeFloat(3.0f) }).AsFloat()
|
||||
== doctest::Approx(3.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("MinNode: equal inputs") {
|
||||
MinNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(5.0f), Value::MakeFloat(5.0f) }).AsFloat()
|
||||
== doctest::Approx(5.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("MaxNode: returns larger value") {
|
||||
MaxNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(3.0f), Value::MakeFloat(7.0f) }).AsFloat()
|
||||
== doctest::Approx(7.0f));
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(7.0f), Value::MakeFloat(3.0f) }).AsFloat()
|
||||
== doctest::Approx(7.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("MaxNode: equal inputs") {
|
||||
MaxNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(5.0f), Value::MakeFloat(5.0f) }).AsFloat()
|
||||
== doctest::Approx(5.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("ClampNode: value within range passes through") {
|
||||
ClampNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(5.0f), Value::MakeFloat(0.0f), Value::MakeFloat(10.0f) }).AsFloat()
|
||||
== doctest::Approx(5.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("ClampNode: value below min clamped to min") {
|
||||
ClampNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(-5.0f), Value::MakeFloat(0.0f), Value::MakeFloat(10.0f) }).AsFloat()
|
||||
== doctest::Approx(0.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("ClampNode: value above max clamped to max") {
|
||||
ClampNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(15.0f), Value::MakeFloat(0.0f), Value::MakeFloat(10.0f) }).AsFloat()
|
||||
== doctest::Approx(10.0f));
|
||||
}
|
||||
|
||||
// ── Int control flow ──────────────────────────────────────────────────────
|
||||
|
||||
TEST_CASE("IntBranchNode: selects true branch") {
|
||||
IntBranchNode n;
|
||||
auto r = n.Evaluate(ctx, { Value::MakeBool(true),
|
||||
Value::MakeInt(7),
|
||||
Value::MakeInt(99) });
|
||||
CHECK(r.type == Type::Int);
|
||||
CHECK(r.AsInt() == 7);
|
||||
}
|
||||
|
||||
TEST_CASE("IntBranchNode: selects false branch") {
|
||||
IntBranchNode n;
|
||||
auto r = n.Evaluate(ctx, { Value::MakeBool(false),
|
||||
Value::MakeInt(7),
|
||||
Value::MakeInt(99) });
|
||||
CHECK(r.type == Type::Int);
|
||||
CHECK(r.AsInt() == 99);
|
||||
}
|
||||
|
||||
TEST_CASE("IntBranchNode: output type is Int") {
|
||||
IntBranchNode n;
|
||||
CHECK(n.GetOutputType() == Type::Int);
|
||||
CHECK(n.GetInputTypes() == std::vector<Type>{ Type::Bool, Type::Int, Type::Int });
|
||||
}
|
||||
|
||||
// ── Extended math ─────────────────────────────────────────────────────────
|
||||
|
||||
TEST_CASE("SqrtNode: normal value") {
|
||||
SqrtNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(9.0f) }).AsFloat() == doctest::Approx(3.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("SqrtNode: zero") {
|
||||
SqrtNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(0.0f) }).AsFloat() == doctest::Approx(0.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("SqrtNode: negative input clamped to zero") {
|
||||
SqrtNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(-4.0f) }).AsFloat() == doctest::Approx(0.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("PowNode: a^b") {
|
||||
PowNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(2.0f), Value::MakeFloat(10.0f) }).AsFloat()
|
||||
== doctest::Approx(1024.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("PowNode: anything to the power 0 is 1") {
|
||||
PowNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(99.0f), Value::MakeFloat(0.0f) }).AsFloat()
|
||||
== doctest::Approx(1.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("SquareNode: positive") {
|
||||
SquareNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(5.0f) }).AsFloat() == doctest::Approx(25.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("SquareNode: negative input gives positive result") {
|
||||
SquareNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(-3.0f) }).AsFloat() == doctest::Approx(9.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("OneMinusNode: 1 - 0.25 == 0.75") {
|
||||
OneMinusNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(0.25f) }).AsFloat() == doctest::Approx(0.75f));
|
||||
}
|
||||
|
||||
TEST_CASE("OneMinusNode: 1 - 0 == 1") {
|
||||
OneMinusNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(0.0f) }).AsFloat() == doctest::Approx(1.0f));
|
||||
}
|
||||
|
||||
TEST_CASE("OneMinusNode: 1 - 1 == 0") {
|
||||
OneMinusNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeFloat(1.0f) }).AsFloat() == doctest::Approx(0.0f));
|
||||
}
|
||||
|
||||
// ── Extended boolean logic ────────────────────────────────────────────────
|
||||
|
||||
TEST_CASE("XorNode: truth table") {
|
||||
XorNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(false), Value::MakeBool(false) }).AsBool() == false);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(true), Value::MakeBool(false) }).AsBool() == true);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(false), Value::MakeBool(true) }).AsBool() == true);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(true), Value::MakeBool(true) }).AsBool() == false);
|
||||
}
|
||||
|
||||
TEST_CASE("NandNode: truth table") {
|
||||
NandNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(false), Value::MakeBool(false) }).AsBool() == true);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(true), Value::MakeBool(false) }).AsBool() == true);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(false), Value::MakeBool(true) }).AsBool() == true);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(true), Value::MakeBool(true) }).AsBool() == false);
|
||||
}
|
||||
|
||||
TEST_CASE("NorNode: truth table") {
|
||||
NorNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(false), Value::MakeBool(false) }).AsBool() == true);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(true), Value::MakeBool(false) }).AsBool() == false);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(false), Value::MakeBool(true) }).AsBool() == false);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(true), Value::MakeBool(true) }).AsBool() == false);
|
||||
}
|
||||
|
||||
TEST_CASE("XnorNode: truth table") {
|
||||
XnorNode n;
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(false), Value::MakeBool(false) }).AsBool() == true);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(true), Value::MakeBool(false) }).AsBool() == false);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(false), Value::MakeBool(true) }).AsBool() == false);
|
||||
CHECK(n.Evaluate(ctx, { Value::MakeBool(true), Value::MakeBool(true) }).AsBool() == true);
|
||||
}
|
||||
|
||||
// ── Noise nodes ───────────────────────────────────────────────────────────
|
||||
|
||||
TEST_CASE("PerlinNoiseNode: output is float in [-1, 1]") {
|
||||
EvalContext c; c.worldX = 10; c.worldY = 20; c.seed = 42;
|
||||
PerlinNoiseNode n(0.1f);
|
||||
float v = n.Evaluate(c, {}).AsFloat();
|
||||
CHECK(v >= -1.0f);
|
||||
CHECK(v <= 1.0f);
|
||||
}
|
||||
|
||||
TEST_CASE("PerlinNoiseNode: deterministic for same context") {
|
||||
EvalContext c; c.worldX = 5; c.worldY = -3; c.seed = 123;
|
||||
PerlinNoiseNode n(0.05f);
|
||||
float v1 = n.Evaluate(c, {}).AsFloat();
|
||||
float v2 = n.Evaluate(c, {}).AsFloat();
|
||||
CHECK(v1 == doctest::Approx(v2));
|
||||
}
|
||||
|
||||
TEST_CASE("PerlinNoiseNode: different positions give different values") {
|
||||
EvalContext c1; c1.worldX = 0; c1.worldY = 0; c1.seed = 99;
|
||||
EvalContext c2; c2.worldX = 50; c2.worldY = 50; c2.seed = 99;
|
||||
PerlinNoiseNode n(0.1f);
|
||||
CHECK(n.Evaluate(c1, {}).AsFloat() != doctest::Approx(n.Evaluate(c2, {}).AsFloat()));
|
||||
}
|
||||
|
||||
TEST_CASE("SimplexNoiseNode: output is float in [-1, 1]") {
|
||||
EvalContext c; c.worldX = 7; c.worldY = 13; c.seed = 1;
|
||||
SimplexNoiseNode n(0.1f);
|
||||
float v = n.Evaluate(c, {}).AsFloat();
|
||||
CHECK(v >= -1.0f);
|
||||
CHECK(v <= 1.0f);
|
||||
}
|
||||
|
||||
TEST_CASE("SimplexNoiseNode: deterministic for same context") {
|
||||
EvalContext c; c.worldX = 3; c.worldY = 8; c.seed = 77;
|
||||
SimplexNoiseNode n(0.05f);
|
||||
CHECK(n.Evaluate(c, {}).AsFloat() == doctest::Approx(n.Evaluate(c, {}).AsFloat()));
|
||||
}
|
||||
|
||||
TEST_CASE("CellularNoiseNode: output is float in [-1, 1]") {
|
||||
EvalContext c; c.worldX = 2; c.worldY = 9; c.seed = 500;
|
||||
CellularNoiseNode n(0.1f);
|
||||
float v = n.Evaluate(c, {}).AsFloat();
|
||||
CHECK(v >= -1.0f);
|
||||
CHECK(v <= 1.0f);
|
||||
}
|
||||
|
||||
TEST_CASE("CellularNoiseNode: deterministic for same context") {
|
||||
EvalContext c; c.worldX = 15; c.worldY = -7; c.seed = 256;
|
||||
CellularNoiseNode n(0.08f);
|
||||
CHECK(n.Evaluate(c, {}).AsFloat() == doctest::Approx(n.Evaluate(c, {}).AsFloat()));
|
||||
}
|
||||
|
||||
TEST_CASE("ValueNoiseNode: output is float in [-1, 1]") {
|
||||
EvalContext c; c.worldX = 4; c.worldY = 6; c.seed = 11;
|
||||
ValueNoiseNode n(0.1f);
|
||||
float v = n.Evaluate(c, {}).AsFloat();
|
||||
CHECK(v >= -1.0f);
|
||||
CHECK(v <= 1.0f);
|
||||
}
|
||||
|
||||
TEST_CASE("ValueNoiseNode: deterministic for same context") {
|
||||
EvalContext c; c.worldX = -2; c.worldY = 3; c.seed = 404;
|
||||
ValueNoiseNode n(0.05f);
|
||||
CHECK(n.Evaluate(c, {}).AsFloat() == doctest::Approx(n.Evaluate(c, {}).AsFloat()));
|
||||
}
|
||||
|
||||
TEST_CASE("noise nodes: frequency affects output") {
|
||||
EvalContext c; c.worldX = 100; c.worldY = 100; c.seed = 1;
|
||||
PerlinNoiseNode lowFreq(0.001f);
|
||||
PerlinNoiseNode highFreq(0.5f);
|
||||
// Different frequencies must produce different values at the same position
|
||||
CHECK(lowFreq.Evaluate(c, {}).AsFloat() != doctest::Approx(highFreq.Evaluate(c, {}).AsFloat()));
|
||||
}
|
||||
|
||||
TEST_CASE("noise nodes: seed affects output") {
|
||||
EvalContext c1; c1.worldX = 10; c1.worldY = 10; c1.seed = 1;
|
||||
EvalContext c2; c2.worldX = 10; c2.worldY = 10; c2.seed = 2;
|
||||
PerlinNoiseNode n(0.1f);
|
||||
CHECK(n.Evaluate(c1, {}).AsFloat() != doctest::Approx(n.Evaluate(c2, {}).AsFloat()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user