GCC Code Coverage Report


src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
52 / 52
100.0%
Branches:
12 / 12, 24 excl
100.0%
Functions:
6 / 6
100.0%

util/common-util.spice
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 // Std imports
4 import "std/text/stringstream";
5 import "std/bindings/llvm/llvm" as llvm;
6 import "std/text/json/json-value";
7 import "std/time/time";
8 import "std/type/type-conversion";
9
10 // External functions
11 ext f<int> memcmp(string, string, unsigned long);
12
13 /**
14 * Split the given haystack by the needle and return the last fragment
15 *
16 * @param haystack Input string
17 * @param needle String to search
18 * @return Last fragment
19 */
20 109793 public f<String> getLastFragment(const String &haystack, const string needle) {
21 109793 const unsigned long index = haystack.rfind(needle);
22
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 109790 times.
109793 return index != -1l ? haystack.getSubstring(index + getRawLength(needle)) : haystack;
23 }
24
25 /**
26 * Generate the version info string for the Spice driver
27 *
28 * @return Version info string
29 */
30 1099 public f<String> buildVersionInfo() {
31 1099 const string version = __get_build_var<string>("SPICE_VERSION", "dev");
32 1099 const string targetOs = __get_build_var<string>("SPICE_TARGET_OS", "dev");
33 1099 const string targetArch = __get_build_var<string>("SPICE_TARGET_ARCH", "dev");
34 1099 const string gitHash = __get_build_var<string>("SPICE_GIT_HASH", "dev");
35 1099 const string builtBy = __get_build_var<string>("SPICE_BUILT_BY", "dev");
36
37 1099 StringStream versionString;
38 1099 versionString << "Spice version: " << version << " " << targetOs << "/" << targetArch << endl();
39 1099 versionString << "Git hash: " << gitHash << endl();
40 1099 versionString << "LLVM version: " << llvm::getVersionString() << endl();
41 1099 versionString << "built by: " << builtBy << endl() << endl();
42 1099 versionString << "(c) Marc Auberer 2021-" << toString(getCurrentYear());
43 2198 return versionString.str();
44 1099 }
45
46 /**
47 * Checks if the first string sorts lexicographically before the second one. This compares byte-wise.
48 *
49 * @param lhs First string
50 * @param rhs Second string
51 * @return Sorts before or not
52 */
53 6917043 public f<bool> isStringLess(const String& lhs, const String& rhs) {
54 6917043 const unsigned long lhsLength = lhs.getLength();
55 6917043 const unsigned long rhsLength = rhs.getLength();
56
2/2
✓ Branch 0 taken 4689906 times.
✓ Branch 1 taken 2227137 times.
6917043 const unsigned long commonLength = lhsLength < rhsLength ? lhsLength : rhsLength;
57
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 6917042 times.
6917043 if commonLength > 0l {
58 6917042 const int comparison = memcmp(lhs.getRaw(), rhs.getRaw(), commonLength);
59
2/2
✓ Branch 0 taken 6917040 times.
✓ Branch 1 taken 2 times.
6917042 if comparison != 0 {
60 6917040 return comparison < 0;
61 }
62 2 }
63 3 return lhsLength < rhsLength;
64 }
65
66 /**
67 * Add a field to a JSON object, keeping the fields sorted by key.
68 * The object takes ownership of the heap-allocated field value.
69 *
70 * @param object JSON object
71 * @param key Field key
72 * @param value Field value
73 */
74 3738083 public p setJsonField(JsonValue* object, const String& key, JsonValue* value) {
75 3738083 const unsigned long size = object.getObjectSize();
76 3738083 unsigned long idx = 0l;
77
4/4
✓ Branch 0 taken 1029432 times.
✓ Branch 1 taken 6917037 times.
✓ Branch 2 taken 4208386 times.
✓ Branch 3 taken 3738083 times.
7946469 while idx < size && isStringLess(object.getObjectKey(idx), key) {
78 4208386 idx++;
79 4208386 }
80 3738083 assert idx == size || object.getObjectKey(idx) != key; // Overwriting fields is not supported
81 3738083 object.insertObjectField(idx, key, value);
82 3738083 }
83
84 // ─── tests ────────────────────────────────────────────────────────────────────
85
86 1 #[test]
87 f<bool> testGetLastFragment() {
88 1 assert getLastFragment(String("This is a test"), " ") == "test";
89 1 assert getLastFragment(String("This_is_a_test"), "_") == "test";
90 1 assert getLastFragment(String("This.is.a."), ".") == "";
91 1 assert getLastFragment(String("This is a test"), "This is a test ") == "This is a test";
92 1 return true;
93 1 }
94
95 1 #[test]
96 f<bool> testIsStringLess() {
97 1 assert isStringLess(String("a"), String("b"));
98 1 assert !isStringLess(String("b"), String("a"));
99 1 assert !isStringLess(String("a"), String("a"));
100 1 assert isStringLess(String("ab"), String("abc")); // A prefix sorts first
101 1 assert isStringLess(String(""), String("a"));
102 1 assert isStringLess(String("Z"), String("a")); // Byte-wise, like std::string
103 1 return true;
104 1 }
105