mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-03 00:02:14 +00:00
feat(automation): resolve_unique + wait-state evaluation
This commit is contained in:
@@ -45,6 +45,12 @@ std::vector<const UiNode*> find_matches(const UiNode& root, const Target& target
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UiNode* resolve_unique(const UiNode& root, const Target& target, int& match_count) {
|
||||||
|
const auto m = find_matches(root, target);
|
||||||
|
match_count = static_cast<int>(m.size());
|
||||||
|
return m.size() == 1 ? m.front() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool evaluate_state(const UiNode* node, WaitState state,
|
bool evaluate_state(const UiNode* node, WaitState state,
|
||||||
const std::optional<std::string>& expected_value) {
|
const std::optional<std::string>& expected_value) {
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ std::vector<const UiNode*> flatten(const UiNode& root);
|
|||||||
// All nodes matching the target spec (resolution-order aware).
|
// All nodes matching the target spec (resolution-order aware).
|
||||||
std::vector<const UiNode*> find_matches(const UiNode& root, const Target& target);
|
std::vector<const UiNode*> find_matches(const UiNode& root, const Target& target);
|
||||||
|
|
||||||
|
// Resolve to exactly one node for actions. Returns the node on a unique match;
|
||||||
|
// returns nullptr otherwise and sets match_count (0 = not found, >1 = ambiguous).
|
||||||
|
const UiNode* resolve_unique(const UiNode& root, const Target& target, int& match_count);
|
||||||
|
|
||||||
enum class WaitState { Exists, Visible, Enabled, Value };
|
enum class WaitState { Exists, Visible, Enabled, Value };
|
||||||
|
|
||||||
// True if `node` satisfies the wait condition. A null node only satisfies a
|
// True if `node` satisfies the wait condition. A null node only satisfies a
|
||||||
|
|||||||
@@ -90,3 +90,34 @@ TEST_CASE("find_matches not found returns empty", "[automation][locator]") {
|
|||||||
Target t; t.id = "nope";
|
Target t; t.id = "nope";
|
||||||
CHECK(find_matches(tree, t).empty());
|
CHECK(find_matches(tree, t).empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("resolve_unique success / not-found / ambiguous",
|
||||||
|
"[automation][locator]") {
|
||||||
|
const auto tree = make_tree();
|
||||||
|
int count = -1;
|
||||||
|
|
||||||
|
Target ok; ok.id = "btn_slice";
|
||||||
|
CHECK(resolve_unique(tree, ok, count) != nullptr);
|
||||||
|
CHECK(count == 1);
|
||||||
|
|
||||||
|
Target missing; missing.id = "nope";
|
||||||
|
CHECK(resolve_unique(tree, missing, count) == nullptr);
|
||||||
|
CHECK(count == 0);
|
||||||
|
|
||||||
|
Target ambiguous; ambiguous.label = "Export";
|
||||||
|
CHECK(resolve_unique(tree, ambiguous, count) == nullptr);
|
||||||
|
CHECK(count == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("evaluate_state covers exists/visible/enabled/value",
|
||||||
|
"[automation][locator]") {
|
||||||
|
UiNode n; n.visible = true; n.enabled = false;
|
||||||
|
n.has_value = true; n.value = "PLA";
|
||||||
|
|
||||||
|
CHECK(evaluate_state(&n, WaitState::Exists, std::nullopt));
|
||||||
|
CHECK(evaluate_state(&n, WaitState::Visible, std::nullopt));
|
||||||
|
CHECK_FALSE(evaluate_state(&n, WaitState::Enabled, std::nullopt)); // disabled
|
||||||
|
CHECK(evaluate_state(&n, WaitState::Value, std::string("PLA")));
|
||||||
|
CHECK_FALSE(evaluate_state(&n, WaitState::Value, std::string("ABS")));
|
||||||
|
CHECK_FALSE(evaluate_state(nullptr, WaitState::Exists, std::nullopt));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user