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