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
This commit is contained in:
@@ -48,11 +48,15 @@ const NodeCache* IncrementalUpdateEngine::get_cache(int node_id) const {
|
||||
|
||||
void IncrementalUpdateEngine::invalidate_cache(int node_id) {
|
||||
auto it = caches_.find(node_id);
|
||||
if (it != caches_.end()) {
|
||||
it->second = NodeCache{};
|
||||
it->second.dirty = true;
|
||||
dirty_set_.insert(node_id);
|
||||
}
|
||||
if (it == caches_.end()) return;
|
||||
|
||||
// Clear cached data but keep the entry
|
||||
it->second.model.reset();
|
||||
it->second.mesh.reset();
|
||||
it->second.bounds.reset();
|
||||
|
||||
// Propagate dirty flag to this node and all downstream
|
||||
mark_dirty(node_id);
|
||||
}
|
||||
|
||||
void IncrementalUpdateEngine::clear_all() {
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
#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);
|
||||
@@ -49,7 +60,8 @@ TEST(IncrementalUpdateTest, RebuildClearsDirty) {
|
||||
engine.register_node(1);
|
||||
engine.mark_dirty(1);
|
||||
EXPECT_EQ(engine.dirty_count(), 1);
|
||||
FeatureHistory history;
|
||||
|
||||
auto history = make_history();
|
||||
engine.incremental_rebuild(history);
|
||||
EXPECT_EQ(engine.dirty_count(), 0);
|
||||
}
|
||||
@@ -58,22 +70,40 @@ TEST(IncrementalUpdateTest, RebuildWithCallback) {
|
||||
IncrementalUpdateEngine engine;
|
||||
engine.register_node(1);
|
||||
engine.mark_dirty(1);
|
||||
|
||||
int cb = 0;
|
||||
FeatureHistory history;
|
||||
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;
|
||||
FeatureHistory history;
|
||||
auto history = make_history();
|
||||
engine.incremental_rebuild(history, [&](int nid, const BrepModel&) { order.push_back(nid); });
|
||||
ASSERT_GE(order.size(), 2u);
|
||||
EXPECT_LT(std::find(order.begin(),order.end(),1), std::find(order.begin(),order.end(),2));
|
||||
// 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) {
|
||||
@@ -83,10 +113,15 @@ TEST(IncrementalUpdateTest, IncrementalVsFull) {
|
||||
if (i > 1) deps.push_back(i - 1);
|
||||
engine.register_node(i, deps);
|
||||
}
|
||||
FeatureHistory history;
|
||||
|
||||
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);
|
||||
@@ -95,15 +130,72 @@ TEST(IncrementalUpdateTest, IncrementalVsFull) {
|
||||
EXPECT_GT(ic, 0);
|
||||
}
|
||||
|
||||
TEST(IncrementalUpdateTest, HitRate) {
|
||||
TEST(IncrementalUpdateTest, InvalidateCachePropagates) {
|
||||
IncrementalUpdateEngine engine;
|
||||
EXPECT_EQ(engine.hit_rate(), 0.0);
|
||||
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, ClearAll) {
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user