Files
ViewDesignEngine/tests/brep/test_incremental_update.cpp
T
茂之钳 138d8d24a0 fix(v4.4): repair incremental_update test API mismatch + invalidate_cache propagation
- Rewrote test_incremental_update.cpp to match new API (FeatureHistory param)
- Fixed invalidate_cache to propagate dirty flag to downstream nodes via mark_dirty
- 15/15 tests pass on Linux build
2026-07-26 16:48:22 +08:00

202 lines
5.7 KiB
C++

#include <gtest/gtest.h>
#include "vde/brep/incremental_update.h"
#include "vde/brep/modeling.h"
#include "vde/brep/feature_tree.h"
using namespace vde::brep;
using namespace vde::core;
// Helper: create a FeatureHistory with an initial BrepModel
static FeatureHistory make_history() {
FeatureHistory history;
FeatureParams params;
params.name = "box";
params.values = {1.0, 1.0, 1.0};
history.apply(make_box(1, 1, 1), FeatureType::PrimitiveBox, params);
return history;
}
TEST(IncrementalUpdateTest, RegisterNode) {
IncrementalUpdateEngine engine;
engine.register_node(1);
EXPECT_EQ(engine.total_nodes(), 1);
}
TEST(IncrementalUpdateTest, RegisterWithDeps) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.register_node(2, {1});
engine.register_node(3, {1, 2});
EXPECT_EQ(engine.total_nodes(), 3);
}
TEST(IncrementalUpdateTest, MarkDirtyPropagates) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.register_node(2, {1});
engine.register_node(3, {2});
engine.mark_dirty(1);
EXPECT_EQ(engine.dirty_count(), 3);
}
TEST(IncrementalUpdateTest, MarkDirtyNoUpstream) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.register_node(2, {1});
engine.mark_dirty(2);
EXPECT_EQ(engine.dirty_count(), 1);
}
TEST(IncrementalUpdateTest, CacheMissOnDirty) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.mark_dirty(1);
EXPECT_TRUE(engine.get_cache(1) == nullptr);
EXPECT_EQ(engine.cache_misses(), 1);
}
TEST(IncrementalUpdateTest, RebuildClearsDirty) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.mark_dirty(1);
EXPECT_EQ(engine.dirty_count(), 1);
auto history = make_history();
engine.incremental_rebuild(history);
EXPECT_EQ(engine.dirty_count(), 0);
}
TEST(IncrementalUpdateTest, RebuildWithCallback) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.mark_dirty(1);
int cb = 0;
auto history = make_history();
engine.incremental_rebuild(history, [&](int nid, const BrepModel&) { cb++; });
EXPECT_EQ(cb, 1);
}
TEST(IncrementalUpdateTest, RebuildClearsCacheDirty) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.mark_dirty(1);
auto history = make_history();
engine.incremental_rebuild(history);
const auto* cache = engine.get_cache(1);
ASSERT_TRUE(cache != nullptr);
EXPECT_FALSE(cache->dirty);
EXPECT_EQ(engine.cache_hits(), 1);
}
TEST(IncrementalUpdateTest, ChainDependencyOrder) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.register_node(2, {1});
engine.mark_dirty(1);
std::vector<int> order;
auto history = make_history();
engine.incremental_rebuild(history, [&](int nid, const BrepModel&) { order.push_back(nid); });
ASSERT_GE(order.size(), 2u);
// Node 1 must be rebuilt before node 2 (upstream before downstream)
EXPECT_LT(std::find(order.begin(), order.end(), 1) - order.begin(),
std::find(order.begin(), order.end(), 2) - order.begin());
}
TEST(IncrementalUpdateTest, IncrementalVsFull) {
IncrementalUpdateEngine engine;
for (int i = 1; i <= 10; ++i) {
std::vector<int> deps;
if (i > 1) deps.push_back(i - 1);
engine.register_node(i, deps);
}
auto history = make_history();
// Full rebuild (clear_all then rebuild)
engine.clear_all();
int fc = engine.incremental_rebuild(history);
EXPECT_EQ(fc, 10);
// Mark only node 5 dirty — should rebuild fewer nodes
engine.clear_all();
engine.incremental_rebuild(history);
engine.mark_dirty(5);
int ic = engine.incremental_rebuild(history);
EXPECT_LT(ic, fc);
EXPECT_GT(ic, 0);
}
TEST(IncrementalUpdateTest, InvalidateCachePropagates) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.register_node(2, {1});
engine.register_node(3, {2});
auto history = make_history();
engine.incremental_rebuild(history); // build all
EXPECT_EQ(engine.dirty_count(), 0);
engine.invalidate_cache(1);
// Node 1 and its dependents (2, 3) should all be dirty
EXPECT_EQ(engine.dirty_count(), 3);
}
TEST(IncrementalUpdateTest, HitRate) {
IncrementalUpdateEngine engine;
// No cache access yet → 0 hit rate
EXPECT_DOUBLE_EQ(engine.hit_rate(), 0.0);
engine.register_node(1);
// get_cache on dirty node → miss
engine.mark_dirty(1);
engine.get_cache(1);
EXPECT_DOUBLE_EQ(engine.hit_rate(), 0.0);
// After rebuild, get_cache should hit
auto history = make_history();
engine.incremental_rebuild(history);
engine.get_cache(1);
EXPECT_GT(engine.hit_rate(), 0.0);
}
TEST(IncrementalUpdateTest, ClearAllMarksAllDirty) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.register_node(2);
auto history = make_history();
engine.incremental_rebuild(history);
EXPECT_EQ(engine.dirty_count(), 0);
engine.clear_all();
EXPECT_EQ(engine.dirty_count(), 2);
}
TEST(IncrementalUpdateTest, RebuildWithoutEvaluator) {
IncrementalUpdateEngine engine;
engine.register_node(1); // no evaluator registered (just topology)
engine.mark_dirty(1);
int cb = 0;
auto history = make_history();
engine.incremental_rebuild(history, [&](int, const BrepModel&) { cb++; });
EXPECT_EQ(cb, 1); // callback still fires
EXPECT_EQ(engine.dirty_count(), 0);
}
TEST(IncrementalUpdateTest, FullRebuild) {
IncrementalUpdateEngine engine;
engine.register_node(1);
engine.register_node(2, {1});
engine.register_node(3, {2});
auto history = make_history();
int count = engine.full_rebuild(history);
EXPECT_EQ(count, 3);
EXPECT_EQ(engine.dirty_count(), 0);
}