GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
62 / 64
96.9%
Branches:
69 / 118
58.5%
Functions:
7 / 7
100.0%

scene/validate.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file validate.cpp
3 /// @brief Checking scene files: loading's problems, with near-miss suggestions, and relationships
4 /// to missing prims.
5 #include "ernie/scene/reference.h"
6 #include "ernie/scene/scene.h"
7 #include "ernie/util/text.h"
8
9 #include <limits>
10
11 namespace ernie {
12 namespace {
13
14 /// @return Every attribute name the prim's type and API schemas declare.
15 2 std::vector<std::string> DeclaredNames(const Scene& scene, PrimId prim) {
16 2 std::vector<std::string> names;
17 5 const auto add = [&](const ApiName& api) {
18
2/2
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 3 times.
39 for (const AttributeDef* def : api.schema->AllAttributes()) {
19
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
72 names.push_back(api.Attribute(def->name));
20 3 }
21 3 };
22
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 if (const SchemaDef* schema = scene.Schema(prim)) {
23
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 add({schema, {}});
24
3/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2 times.
3 for (const std::string_view builtin : schema->AllBuiltinApis()) {
25
2/4
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
1 add(ApiName::Parse(builtin));
26 2 }
27 }
28
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
2 for (const std::string& api : scene.AppliedApis(prim)) {
29
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ add(ApiName::Parse(api));
30 2 }
31 2 return names;
32 ✗ }
33
34 /// @return The declared name nearest a misspelt one, if near enough to be meant.
35 2 std::string Nearest(const std::vector<std::string>& names, std::string_view name) {
36 2 std::string nearest;
37 2 std::size_t best = std::numeric_limits<std::size_t>::max();
38
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2 times.
38 for (const std::string& candidate : names) {
39
3/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 30 times.
36 if (const std::size_t distance = EditDistance(candidate, name); distance < best) {
40 6 best = distance;
41
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
42 nearest = candidate;
42 }
43 }
44
4/6
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
3 return best <= std::max<std::size_t>(2, name.size() / 3) ? nearest : std::string();
45 2 }
46
47 12 void Suggest(const Scene& scene, SceneProblem& problem) {
48 12 const std::optional<PrimId> prim =
49
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
22 problem.path.empty() ? std::nullopt : scene.Find(Path(problem.path));
50
4/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
12 if (!prim || problem.what.find("has no attribute") == std::string::npos) {
51 10 return;
52 }
53
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 if (const std::string nearest = Nearest(DeclaredNames(scene, *prim), problem.key);
54
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 !nearest.empty()) {
55
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
6 problem.what += "; did you mean '" + nearest + "'?";
56 2 }
57 }
58
59 271 std::vector<Path> Targets(const Value& value) {
60
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 5 times.
271 if (const auto* path = value.Get<Path>()) {
61
3/8
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 5 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
15 return path->IsEmpty() ? std::vector<Path>{} : std::vector<Path>{*path};
62 }
63
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 262 times.
266 if (const auto* paths = value.Get<std::vector<Path>>()) {
64 4 return *paths;
65 }
66 262 return {};
67
2/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
5 }
68
69 /// Adds a problem for each relationship of the prim targeting a prim the scene doesn't have.
70 149 void CheckTargets(const Scene& scene, const Path& path, std::vector<SceneProblem>& problems) {
71 149 const PrimId prim = *scene.Find(path);
72
2/2
✓ Branch 1 taken 271 times.
✓ Branch 2 taken 149 times.
420 for (const std::string& name : scene.Attributes(path)) {
73
1/2
✓ Branch 1 taken 271 times.
✗ Branch 2 not taken.
271 const std::optional<Value> value = scene.Get(prim, name);
74
4/6
✓ Branch 0 taken 271 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 271 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 271 times.
280 for (const Path& target : value ? Targets(*value) : std::vector<Path>{}) {
75 // A property target, as a connection's, names its prim before the dot.
76
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 const std::string text = target.String();
77
4/6
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 8 times.
18 if (!scene.Has(Path(text.substr(0, text.find('.'))))) {
78
2/4
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
3 problems.push_back({path.String(), name, "targets " + text + ", which is no prim"});
79 }
80 280 }
81 420 }
82
3/10
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
151 }
83
84 } // namespace
85
86 70 std::vector<SceneProblem> ValidateScene(std::string_view json) {
87 70 Scene scene;
88 70 std::vector<SceneProblem> problems;
89
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 LoadScene(scene, json, {}, &problems);
90
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 70 times.
82 for (SceneProblem& problem : problems) {
91
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 Suggest(scene, problem);
92 }
93
3/4
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 149 times.
✓ Branch 4 taken 70 times.
219 for (const Path& path : scene.Prims()) {
94
1/2
✓ Branch 1 taken 149 times.
✗ Branch 2 not taken.
149 CheckTargets(scene, path, problems);
95 70 }
96 70 return problems;
97 70 }
98
99 } // namespace ernie
100