Add diff compare method for DynamicConfig

Help the unit test report errors better.
This commit is contained in:
Cory Cross
2025-11-04 09:48:50 -08:00
parent 2cdf71414d
commit 6e7c81b986
2 changed files with 111 additions and 0 deletions

View File

@@ -1703,6 +1703,81 @@ t_config_option_keys DynamicConfig::keys() const
return keys;
}
DynamicConfig::DynamicConfigDifference DynamicConfig::diff_report(const DynamicConfig& rhs) const {
DynamicConfig::DynamicConfigDifference result;
std::set<t_config_option_key> all_keys;
for (const auto& kvp : this->options) {
all_keys.insert(kvp.first);
}
for (const auto& kvp : rhs.options) {
all_keys.insert(kvp.first);
}
for (const auto& key : all_keys) {
auto left_it = this->options.find(key);
auto right_it = rhs.options.find(key);
bool left_has = (left_it != this->options.end());
bool right_has = (right_it != rhs.options.end());
if (left_has && right_has) {
if (*left_it->second != *right_it->second) {
result.differences[key] = {
left_it->second->serialize(),
right_it->second->serialize()
};
}
} else if (left_has) {
result.differences[key] = {
left_it->second->serialize(),
std::nullopt
};
} else if (right_has) {
result.differences[key] = {
std::nullopt,
right_it->second->serialize()
};
}
}
return result;
}
std::ostream& operator<<(std::ostream& os, const DynamicConfig::DynamicConfigDifference& diff) {
if (!diff.is_different()) {
os << "Configurations are identical.\n";
return os;
}
int missing_right=0, missing_left=0, differ=0;
os << "DynamicConfig Differences Found (" << diff.differences.size() << " keys):\n";
for (const auto& kvp : diff.differences) {
const auto& key = kvp.first;
const auto& detail = kvp.second;
os << " Key: **" << key << "**\n";
if (detail.is_missing_key()) {
// Determine which side is missing the key
if (detail.left_value.has_value()) {
os << " - **Missing in Right**: Key exists in left config. Value: " << detail.left_value.value() << "\n";
missing_right++;
} else {
os << " - **Missing in Left**: Key exists in right config. Value: " << detail.right_value.value() << "\n";
missing_left++;
}
} else if (detail.is_different_value()) {
differ++;
os << " - **Value Differs**:\n";
os << " -> Left Value: " << detail.left_value.value() << "\n";
os << " -> Right Value: " << detail.right_value.value() << "\n";
}
}
os << "Summary: " << missing_right << " missing on right, " << missing_left << " missing on left, and " << differ << " have differing values\n";
return os;
}
void StaticConfig::set_defaults()
{
// use defaults from definition

View File

@@ -2783,6 +2783,40 @@ public:
std::map<t_config_option_key, std::unique_ptr<ConfigOption>>::const_iterator cend() const { return options.cend(); }
size_t size() const { return options.size(); }
/**
* @brief Detailed information about the difference found for a single key.
*/
struct KeyDifference {
std::optional<std::string> left_value;
std::optional<std::string> right_value;
bool is_missing_key() const {
return !left_value.has_value() || !right_value.has_value();
}
bool is_different_value() const {
return left_value.has_value() && right_value.has_value() && (left_value.value() != right_value.value());
}
};
/**
* @brief The full report object containing all detected differences.
*/
struct DynamicConfigDifference {
std::map<t_config_option_key, KeyDifference> differences;
bool is_different() const {
return !differences.empty();
}
};
/**
* @brief Computes the symmetric difference between this DynamicConfig (left)
* and another DynamicConfig (rhs).
* @param rhs The right-hand side config to compare against.
* @return DynamicConfigDifference report.
*/
DynamicConfigDifference diff_report(const DynamicConfig& rhs) const;
private:
std::map<t_config_option_key, std::unique_ptr<ConfigOption>> options;
@@ -2790,6 +2824,8 @@ private:
template<class Archive> void serialize(Archive &ar) { ar(options); }
};
std::ostream& operator<<(std::ostream& os, const DynamicConfig::DynamicConfigDifference& diff);
// Configuration store with a static definition of configuration values.
// In Slic3r, the static configuration stores are during the slicing / g-code generation for efficiency reasons,
// because the configuration values could be accessed directly.