@o-lang/resolver-tests 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/badge.js +33 -23
- package/lib/runner.js +6 -5
- package/package.json +1 -1
package/lib/badge.js
CHANGED
|
@@ -2,62 +2,72 @@ const fs = require("fs");
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
console.log("✅ O-lang badge generator loaded");
|
|
4
4
|
|
|
5
|
-
// ----------------------
|
|
6
|
-
// Resolver-specific badge generator with O-lang tag
|
|
7
|
-
// ----------------------
|
|
8
5
|
function generateBadge({
|
|
9
6
|
resolverName = "Unknown",
|
|
10
7
|
version = "",
|
|
11
8
|
passed = false,
|
|
12
|
-
outputDir = process.cwd()
|
|
9
|
+
outputDir = process.cwd()
|
|
13
10
|
}) {
|
|
14
|
-
|
|
11
|
+
// Colors
|
|
12
|
+
const olangColor = "#8A2BE2"; // Purple for "O-lang"
|
|
13
|
+
const statusColor = passed ? "#4CAF50" : "#F44336"; // Green/Red for status
|
|
14
|
+
|
|
15
15
|
const statusText = passed ? "Certified" : "Failed";
|
|
16
16
|
const versionText = version ? ` v${version}` : "";
|
|
17
17
|
const timestamp = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
|
|
18
18
|
|
|
19
|
-
// O-lang
|
|
20
|
-
const
|
|
19
|
+
// Left label: "O-lang"
|
|
20
|
+
const leftLabel = "O-lang";
|
|
21
|
+
// Right message: "resolver-name v1.0 — Certified (2026-01-22)"
|
|
22
|
+
const rightMessage = `${resolverName}${versionText} — ${statusText} (${timestamp})`;
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
// Estimate text widths (approx. 7px per char + padding)
|
|
25
|
+
const leftWidth = 12 + leftLabel.length * 7;
|
|
26
|
+
const rightWidth = 12 + rightMessage.length * 7;
|
|
27
|
+
const totalWidth = leftWidth + rightWidth;
|
|
23
28
|
|
|
24
29
|
const badgeSvg = `
|
|
25
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="${
|
|
26
|
-
|
|
27
|
-
<
|
|
30
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth}" height="20">
|
|
31
|
+
<!-- Left segment: O-lang (purple) -->
|
|
32
|
+
<rect x="0" y="0" width="${leftWidth}" height="20" fill="${olangColor}" rx="3" ry="3"/>
|
|
33
|
+
<text x="${leftWidth / 2}" y="14"
|
|
34
|
+
fill="#fff"
|
|
35
|
+
font-family="Verdana, DejaVu Sans, sans-serif"
|
|
36
|
+
font-size="11"
|
|
37
|
+
font-weight="bold"
|
|
38
|
+
text-anchor="middle">
|
|
39
|
+
${leftLabel}
|
|
40
|
+
</text>
|
|
41
|
+
|
|
42
|
+
<!-- Right segment: status info (green/red) -->
|
|
43
|
+
<rect x="${leftWidth}" y="0" width="${rightWidth}" height="20" fill="${statusColor}" rx="3" ry="3"/>
|
|
44
|
+
<text x="${leftWidth + rightWidth / 2}" y="14"
|
|
28
45
|
fill="#fff"
|
|
29
|
-
font-family="Verdana"
|
|
30
|
-
font-size="
|
|
46
|
+
font-family="Verdana, DejaVu Sans, sans-serif"
|
|
47
|
+
font-size="11"
|
|
31
48
|
text-anchor="middle">
|
|
32
|
-
${
|
|
49
|
+
${rightMessage}
|
|
33
50
|
</text>
|
|
34
51
|
</svg>
|
|
35
52
|
`.trim();
|
|
36
53
|
|
|
37
|
-
// ----------------------
|
|
38
54
|
// Ensure badges folder exists
|
|
39
|
-
// ----------------------
|
|
40
55
|
const badgesDir = path.join(outputDir, "badges");
|
|
41
56
|
if (!fs.existsSync(badgesDir)) {
|
|
42
57
|
fs.mkdirSync(badgesDir, { recursive: true });
|
|
43
58
|
}
|
|
44
59
|
|
|
45
|
-
// ----------------------
|
|
46
60
|
// Write badge file
|
|
47
|
-
// ----------------------
|
|
48
61
|
const safeName = resolverName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
49
62
|
const badgePath = path.join(badgesDir, `${safeName}-badge.svg`);
|
|
50
63
|
|
|
51
64
|
fs.writeFileSync(badgePath, badgeSvg, "utf8");
|
|
52
|
-
|
|
53
65
|
console.log(`🏷 Badge written to ${badgePath}`);
|
|
54
66
|
|
|
55
67
|
return badgePath;
|
|
56
68
|
}
|
|
57
69
|
|
|
58
|
-
// ----------------------
|
|
59
|
-
// Export
|
|
60
|
-
// ----------------------
|
|
61
70
|
module.exports = {
|
|
71
|
+
generateBadges: generateBadge, // alias for backward compat if needed
|
|
62
72
|
generateBadge
|
|
63
|
-
};
|
|
73
|
+
};
|
package/lib/runner.js
CHANGED
|
@@ -85,6 +85,7 @@ function checkOutputIsObject(output) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
function checkOutputFieldsMatchContract(output, resolverMeta) {
|
|
88
|
+
if (!output) return false; // 🔒 SAFETY: prevent 'in' operator crash on null/undefined
|
|
88
89
|
const declaredNames = (resolverMeta.outputs || []).map(o => o.name);
|
|
89
90
|
return declaredNames.every(name => name in output);
|
|
90
91
|
}
|
|
@@ -171,7 +172,7 @@ function runAssertions(testSpec, target, status = {}) {
|
|
|
171
172
|
// ----------------------
|
|
172
173
|
// Runtime resolver invoker with observation
|
|
173
174
|
// ----------------------
|
|
174
|
-
async function invokeResolverWithObservation(resolver, resolverMeta, testSpec) {
|
|
175
|
+
async function invokeResolverWithObservation(resolver, resolverMeta, testSpec, fixture) {
|
|
175
176
|
const ctx = {
|
|
176
177
|
resolver,
|
|
177
178
|
resolverMeta,
|
|
@@ -182,10 +183,9 @@ async function invokeResolverWithObservation(resolver, resolverMeta, testSpec) {
|
|
|
182
183
|
retryCount: 0,
|
|
183
184
|
};
|
|
184
185
|
|
|
185
|
-
// Use
|
|
186
|
-
const input = {};
|
|
186
|
+
// ✅ Use input from test fixture (critical fix!)
|
|
187
|
+
const input = fixture?.invoke || {};
|
|
187
188
|
|
|
188
|
-
// Run multiple times for determinism test
|
|
189
189
|
const runs = testSpec.test_id === 'R-011-determinism' ? 3 : 1;
|
|
190
190
|
|
|
191
191
|
for (let i = 0; i < runs; i++) {
|
|
@@ -257,7 +257,8 @@ async function runAllTests({ suites, resolver }) {
|
|
|
257
257
|
} else if (testSpec.category === "resolver-runtime") {
|
|
258
258
|
// R-006 → R-012: Observe real resolver behavior
|
|
259
259
|
try {
|
|
260
|
-
|
|
260
|
+
// ✅ Pass fixture to invoker
|
|
261
|
+
const runtimeContext = await invokeResolverWithObservation(resolver, resolverMeta, testSpec, fixture);
|
|
261
262
|
const result = runAssertions(testSpec, runtimeContext);
|
|
262
263
|
|
|
263
264
|
if (!result.ok) {
|