1 #include "check_entity.hpp"
2 #include "pool/entity.hpp"
3 #include "check_util.hpp"
4 #include <glibmm/regex.h>
5
6 namespace horizon {
7
check_entity(const Entity & entity)8 RulesCheckResult check_entity(const Entity &entity)
9 {
10 RulesCheckResult r;
11 r.level = RulesCheckErrorLevel::PASS;
12
13 if (!entity.name.size()) {
14 r.errors.emplace_back(RulesCheckErrorLevel::FAIL, "Name must not be empty");
15 }
16 if (needs_trim(entity.name)) {
17 r.errors.emplace_back(RulesCheckErrorLevel::FAIL, "Name has trailing/leading whitespace");
18 }
19 if (needs_trim(entity.manufacturer)) {
20 r.errors.emplace_back(RulesCheckErrorLevel::FAIL, "Manufacturer has trailing/leading whitespace");
21 }
22 {
23 const Glib::ustring up(entity.prefix);
24 if (!Glib::Regex::match_simple("^[A-Z]+$", up)) {
25 r.errors.emplace_back(RulesCheckErrorLevel::FAIL, "Prefix doesn't match regex");
26 }
27 }
28 if (entity.tags.size() == 0) {
29 r.errors.emplace_back(RulesCheckErrorLevel::FAIL, "Tags must not be empty");
30 }
31 for (const auto &tag : entity.tags) {
32 if (!check_tag(tag)) {
33 r.errors.emplace_back(RulesCheckErrorLevel::FAIL, "Tag \"" + tag + "\" doesn't match regex");
34 }
35 }
36 static auto re_gate_suffix = Glib::Regex::create("^[A-Z]+$");
37 const auto n_gates = entity.gates.size();
38 if (n_gates == 0) {
39 r.errors.emplace_back(RulesCheckErrorLevel::FAIL, "Entity has no gates");
40 }
41 else if (n_gates == 1) {
42 const auto &gate = entity.gates.begin()->second;
43 if (gate.name != "Main") {
44 r.errors.emplace_back(RulesCheckErrorLevel::WARN, "Only gate must be named \"Main\"");
45 }
46 if (gate.suffix != "") {
47 r.errors.emplace_back(RulesCheckErrorLevel::WARN, "Only gate must have empty suffix");
48 }
49 if (gate.swap_group != 0) {
50 r.errors.emplace_back(RulesCheckErrorLevel::WARN, "Only gate must have zero swap group");
51 }
52 }
53 else {
54 std::set<std::string> gate_names;
55 std::set<std::string> gate_suffixes;
56 std::map<unsigned int, std::set<const Gate *>> gates_swap_group;
57 for (const auto &[uu, gate] : entity.gates) {
58 if (needs_trim(gate.name)) {
59 r.errors.emplace_back(RulesCheckErrorLevel::FAIL,
60 "Gate \"" + gate.name + "\" has trailing/leading whitespace");
61 }
62 if (gate_names.count(gate.name)) {
63 r.errors.emplace_back(RulesCheckErrorLevel::FAIL, "Gate \"" + gate.name + "\" not unique");
64 }
65 gate_names.insert(gate.name);
66
67 if (gate_suffixes.count(gate.suffix)) {
68 r.errors.emplace_back(RulesCheckErrorLevel::FAIL, "Gate suffix \"" + gate.suffix + "\" not unique");
69 }
70 gate_suffixes.insert(gate.suffix);
71 {
72 Glib::ustring suffix(gate.suffix);
73 if (!re_gate_suffix->match(suffix)) {
74 r.errors.emplace_back(RulesCheckErrorLevel::FAIL,
75 "Gate suffix \"" + gate.suffix + "\" doesn't match regex");
76 }
77 }
78 if (gate.swap_group)
79 gates_swap_group[gate.swap_group].insert(&gate);
80 }
81 for (const auto &[swap_group, gates] : gates_swap_group) {
82 if (gates.size() == 1) {
83 r.errors.emplace_back(RulesCheckErrorLevel::WARN,
84 "Swap group " + std::to_string(swap_group) + " only has one gate");
85 }
86 else {
87 std::set<UUID> units;
88 for (const auto &gate : gates) {
89 units.insert(gate->unit->uuid);
90 }
91 if (units.size() > 1) {
92 r.errors.emplace_back(RulesCheckErrorLevel::WARN,
93 "Swap group " + std::to_string(swap_group)
94 + " has gates with more than one distinct unit");
95 }
96 }
97 }
98 }
99
100
101 r.update();
102 return r;
103 }
104
105 } // namespace horizon
106