@unerr-ai/unerr 0.1.6 → 0.1.7
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/README.md +70 -194
- package/dist/cli.js +39149 -36991
- package/package.json +9 -2
- package/dist/__tests__/architecture-guard.test.js +0 -122
- package/dist/__tests__/arg-validator.test.js +0 -205
- package/dist/__tests__/ast-extractor.test.js +0 -203
- package/dist/__tests__/auto-bootstrap.test.js +0 -280
- package/dist/__tests__/background-indexer.test.js +0 -228
- package/dist/__tests__/blast-radius-engine.test.js +0 -200
- package/dist/__tests__/bridge-isolation.test.js +0 -37
- package/dist/__tests__/budget-enforcer.test.js +0 -53
- package/dist/__tests__/cfg-test-detection-perf.test.js +0 -82
- package/dist/__tests__/change-narrative.test.js +0 -190
- package/dist/__tests__/check-commit.test.js +0 -258
- package/dist/__tests__/checksum.test.js +0 -34
- package/dist/__tests__/commit-watcher.test.js +0 -154
- package/dist/__tests__/community-detection.test.js +0 -179
- package/dist/__tests__/community-tools.test.js +0 -299
- package/dist/__tests__/components.test.js +0 -449
- package/dist/__tests__/compression-log.test.js +0 -174
- package/dist/__tests__/compression-quality-monitor.test.js +0 -40
- package/dist/__tests__/config-healer.test.js +0 -165
- package/dist/__tests__/context-ledger.test.js +0 -58
- package/dist/__tests__/convention-detector.test.js +0 -99
- package/dist/__tests__/convention-learner.test.js +0 -86
- package/dist/__tests__/correction-detector.test.js +0 -330
- package/dist/__tests__/daemon-autostart-install.test.js +0 -283
- package/dist/__tests__/daemon-bridge.test.js +0 -222
- package/dist/__tests__/daemon-dashboard.test.js +0 -202
- package/dist/__tests__/daemon-registry.test.js +0 -240
- package/dist/__tests__/daemon-supervisor.test.js +0 -318
- package/dist/__tests__/daemon-version-check.test.js +0 -275
- package/dist/__tests__/decision-point-detector.test.js +0 -98
- package/dist/__tests__/deep-link.test.js +0 -143
- package/dist/__tests__/disallowed-tools.test.js +0 -115
- package/dist/__tests__/drift-tracker.test.js +0 -582
- package/dist/__tests__/durability-scorer.test.js +0 -152
- package/dist/__tests__/efficiency-tracker.test.js +0 -65
- package/dist/__tests__/enrich.test.js +0 -144
- package/dist/__tests__/entity-rewind.test.js +0 -248
- package/dist/__tests__/ephemeral.test.js +0 -111
- package/dist/__tests__/exploration-cost.test.js +0 -93
- package/dist/__tests__/fact-generator.test.js +0 -197
- package/dist/__tests__/file-l0-graph.test.js +0 -244
- package/dist/__tests__/file-logger.test.js +0 -82
- package/dist/__tests__/file-outline.test.js +0 -141
- package/dist/__tests__/file-read-protocol.test.js +0 -188
- package/dist/__tests__/format-encoder.test.js +0 -233
- package/dist/__tests__/git-attribution.test.js +0 -259
- package/dist/__tests__/graph-temporal-joiner.test.js +0 -219
- package/dist/__tests__/health-grade-enhanced.test.js +0 -138
- package/dist/__tests__/health-map-data.test.js +0 -173
- package/dist/__tests__/helpers/mcp-harness.js +0 -45
- package/dist/__tests__/helpers/mcp-harness.test.js +0 -68
- package/dist/__tests__/hook-dedup.test.js +0 -112
- package/dist/__tests__/hook-runner.test.js +0 -253
- package/dist/__tests__/indexer-cfg.test.js +0 -185
- package/dist/__tests__/indexer-cross-file.test.js +0 -172
- package/dist/__tests__/indexer-extraction.test.js +0 -245
- package/dist/__tests__/indexer-incremental.test.js +0 -232
- package/dist/__tests__/indexer-language-expansion.test.js +0 -165
- package/dist/__tests__/init-push.test.js +0 -131
- package/dist/__tests__/instruction-writer.test.js +0 -179
- package/dist/__tests__/intelligence-integration.test.js +0 -217
- package/dist/__tests__/intent-correlator.test.js +0 -175
- package/dist/__tests__/intent-detector.test.js +0 -235
- package/dist/__tests__/intent-encoder.test.js +0 -167
- package/dist/__tests__/java-build-tool-detection.test.js +0 -174
- package/dist/__tests__/layer3-sprint-q.test.js +0 -160
- package/dist/__tests__/layer3-sprint-r.test.js +0 -91
- package/dist/__tests__/layer3-sprint-s.test.js +0 -183
- package/dist/__tests__/layer3-sprint-t.test.js +0 -201
- package/dist/__tests__/layer3-sprint-u.test.js +0 -174
- package/dist/__tests__/layer4-sprint-ba2.test.js +0 -354
- package/dist/__tests__/layer4-sprint-ba4.test.js +0 -84
- package/dist/__tests__/layer4-sprint-vs.test.js +0 -105
- package/dist/__tests__/ledger-chains.test.js +0 -162
- package/dist/__tests__/lifecycle-machine.test.js +0 -226
- package/dist/__tests__/local-chat-provider.test.js +0 -170
- package/dist/__tests__/local-convention-detector.test.js +0 -308
- package/dist/__tests__/local-embeddings.test.js +0 -422
- package/dist/__tests__/local-graph.test.js +0 -540
- package/dist/__tests__/local-indexer.test.js +0 -228
- package/dist/__tests__/local-intelligence-l3.test.js +0 -332
- package/dist/__tests__/local-llm.test.js +0 -253
- package/dist/__tests__/local-mode-offline.test.js +0 -187
- package/dist/__tests__/local-mode-stats.test.js +0 -273
- package/dist/__tests__/local-mode-tui.test.js +0 -343
- package/dist/__tests__/local-parse.test.js +0 -199
- package/dist/__tests__/log-tailer.test.js +0 -208
- package/dist/__tests__/loop-breaker.test.js +0 -276
- package/dist/__tests__/loop-miner.test.js +0 -226
- package/dist/__tests__/mcp-config.test.js +0 -126
- package/dist/__tests__/mcp-content-json.test.js +0 -10
- package/dist/__tests__/mcp-envelope.test.js +0 -124
- package/dist/__tests__/metrics-store.test.js +0 -223
- package/dist/__tests__/native-watcher.test.js +0 -191
- package/dist/__tests__/navigation-hooks-agent-aware.test.js +0 -145
- package/dist/__tests__/negative-knowledge.test.js +0 -116
- package/dist/__tests__/network-boundary.test.js +0 -190
- package/dist/__tests__/network-firewall.test.js +0 -112
- package/dist/__tests__/nudge-invariants.test.js +0 -160
- package/dist/__tests__/nudge-v2.test.js +0 -225
- package/dist/__tests__/offline-rewind.test.js +0 -251
- package/dist/__tests__/open-threads.test.js +0 -89
- package/dist/__tests__/output-compressor.test.js +0 -93
- package/dist/__tests__/pending-violations.test.js +0 -112
- package/dist/__tests__/persistence-effectiveness.test.js +0 -143
- package/dist/__tests__/provider-factory.test.js +0 -42
- package/dist/__tests__/providers.test.js +0 -24
- package/dist/__tests__/proxy.test.js +0 -314
- package/dist/__tests__/query-router.test.js +0 -1018
- package/dist/__tests__/reasoning-quality-route.test.js +0 -138
- package/dist/__tests__/redactor.test.js +0 -120
- package/dist/__tests__/resource-monitor.test.js +0 -57
- package/dist/__tests__/response-envelope.test.js +0 -100
- package/dist/__tests__/risk-classifier.test.js +0 -101
- package/dist/__tests__/risk-signal-scope.test.js +0 -75
- package/dist/__tests__/rule-evaluator.test.js +0 -280
- package/dist/__tests__/scip-decoder.test.js +0 -49
- package/dist/__tests__/scip-downloader.test.js +0 -201
- package/dist/__tests__/scip-merger.test.js +0 -103
- package/dist/__tests__/search-index.test.js +0 -422
- package/dist/__tests__/semantic-enrichment.test.js +0 -360
- package/dist/__tests__/session-brief-builder.test.js +0 -187
- package/dist/__tests__/session-context.test.js +0 -221
- package/dist/__tests__/session-continuity.test.js +0 -144
- package/dist/__tests__/session-dedup.test.js +0 -74
- package/dist/__tests__/session-event-wiring.test.js +0 -206
- package/dist/__tests__/session-events.test.js +0 -149
- package/dist/__tests__/session-legend.test.js +0 -20
- package/dist/__tests__/session-persistence.test.js +0 -131
- package/dist/__tests__/session-resume-block.test.js +0 -107
- package/dist/__tests__/session-resume.test.js +0 -97
- package/dist/__tests__/session-summary-writer.test.js +0 -134
- package/dist/__tests__/shadow-ledger.test.js +0 -203
- package/dist/__tests__/shell-classifier.test.js +0 -151
- package/dist/__tests__/shell-compression-floor.test.js +0 -189
- package/dist/__tests__/shell-compression-v2.test.js +0 -339
- package/dist/__tests__/shell-compressor.test.js +0 -35
- package/dist/__tests__/shell-hooks.test.js +0 -128
- package/dist/__tests__/shell-strategies.test.js +0 -644
- package/dist/__tests__/shell-tee.test.js +0 -133
- package/dist/__tests__/signal-dedup.test.js +0 -158
- package/dist/__tests__/signal-reinforcer.test.js +0 -77
- package/dist/__tests__/signal-scorer.test.js +0 -251
- package/dist/__tests__/signal-show-store.test.js +0 -108
- package/dist/__tests__/smart-truncate.test.js +0 -215
- package/dist/__tests__/snapshot-v2.test.js +0 -113
- package/dist/__tests__/sprint-l1-local-mode.test.js +0 -130
- package/dist/__tests__/sprint-l10-boot.test.js +0 -220
- package/dist/__tests__/sprint-l9-offline-commands.test.js +0 -189
- package/dist/__tests__/sprint-q-persistent-context.test.js +0 -198
- package/dist/__tests__/sprint-s1-wiring.test.js +0 -215
- package/dist/__tests__/sprint-s2-wiring.test.js +0 -256
- package/dist/__tests__/sprint-s3-wiring.test.js +0 -195
- package/dist/__tests__/sprint-s4-wiring.test.js +0 -213
- package/dist/__tests__/sprint-s6-hooks.test.js +0 -222
- package/dist/__tests__/sprint-s7-persistent.test.js +0 -263
- package/dist/__tests__/sprint-s8-value.test.js +0 -167
- package/dist/__tests__/sprint-s9-behavioral.test.js +0 -179
- package/dist/__tests__/sprint3-intelligence.test.js +0 -297
- package/dist/__tests__/sprint5-mcp-server.test.js +0 -136
- package/dist/__tests__/startup-display.test.js +0 -302
- package/dist/__tests__/startup-log-file.test.js +0 -97
- package/dist/__tests__/stash-manager.test.js +0 -229
- package/dist/__tests__/state-detector.test.js +0 -92
- package/dist/__tests__/status-dashboard.test.js +0 -142
- package/dist/__tests__/temporal-facts.test.js +0 -292
- package/dist/__tests__/temporal-routes.test.js +0 -142
- package/dist/__tests__/test-detector.test.js +0 -174
- package/dist/__tests__/theme.test.js +0 -72
- package/dist/__tests__/timeline-agents.test.js +0 -122
- package/dist/__tests__/timeline-bootstrap.test.js +0 -176
- package/dist/__tests__/timeline-filters.test.js +0 -193
- package/dist/__tests__/timeline-markers.test.js +0 -151
- package/dist/__tests__/timeline-routes.test.js +0 -156
- package/dist/__tests__/timeline-store.test.js +0 -171
- package/dist/__tests__/token-counter.test.js +0 -86
- package/dist/__tests__/token-estimator.test.js +0 -96
- package/dist/__tests__/token-flow-api.test.js +0 -239
- package/dist/__tests__/token-flow-instrumentation.test.js +0 -437
- package/dist/__tests__/token-flow-persistence.test.js +0 -356
- package/dist/__tests__/token-flow-routes.test.js +0 -199
- package/dist/__tests__/token-flow.test.js +0 -695
- package/dist/__tests__/tool-clusters.test.js +0 -177
- package/dist/__tests__/transport-mux.test.js +0 -283
- package/dist/__tests__/turn-segmenter.test.js +0 -166
- package/dist/__tests__/uninstall.test.js +0 -141
- package/dist/__tests__/warm-start-policy.test.js +0 -271
- package/dist/__tests__/wire-cap-nudge.test.js +0 -77
- package/dist/__tests__/worker-pool.test.js +0 -101
- package/dist/ui/assets/index-7gl3mIuY.css +0 -1
- package/dist/ui/assets/index-CX4FCWGT.js +0 -10
- package/dist/ui/assets/rolldown-runtime-S-ySWqyJ.js +0 -1
- package/dist/ui/assets/vis-network-NIJHUFI3.js +0 -908
- package/dist/ui/fonts/jetbrains-mono-latin-400-normal.woff +0 -0
- package/dist/ui/icon-wordmark.png +0 -0
- package/dist/ui/icon-wordmark.svg +0 -30
- package/dist/ui/icon.png +0 -0
- package/dist/ui/icon.svg +0 -25
- package/dist/ui/index.html +0 -15
- package/dist/ui/prototype-sandbox/index.html +0 -257
- package/dist/ui/screenshots/activity.png +0 -0
- package/dist/ui/screenshots/code-base-intelligence.png +0 -0
- package/dist/ui/screenshots/dashboard.png +0 -0
- package/dist/ui/screenshots/project-memory.png +0 -0
- package/dist/ui/screenshots/reasoning-quality.png +0 -0
- package/dist/ui/screenshots/reasoning-session.png +0 -0
- package/dist/ui/screenshots/token-session.png +0 -0
- package/dist/ui/screenshots/token-trace-main.png +0 -0
- package/dist/ui/screenshots/token-turn.png +0 -0
- package/dist/ui/unerr-wordmark.png +0 -0
- package/dist/ui/unerr-wordmark.svg +0 -9
- package/dist/ui/unerr.png +0 -0
- package/dist/ui/unerr.svg +0 -25
- package/dist/ui/web-app-manifest-192x192.png +0 -0
- package/dist/ui/web-app-manifest-512x512.png +0 -0
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 10b TEST-02/03/04: Rule evaluator tests.
|
|
3
|
-
*
|
|
4
|
-
* Tests naming rule evaluation (regex against entity names).
|
|
5
|
-
* Structural tests are integration-level (require tree-sitter WASM).
|
|
6
|
-
*/
|
|
7
|
-
import { describe, expect, it, vi } from "vitest";
|
|
8
|
-
// Mock web-tree-sitter to avoid resolution error in test environment
|
|
9
|
-
vi.mock("web-tree-sitter", () => ({
|
|
10
|
-
default: {
|
|
11
|
-
init: vi.fn(),
|
|
12
|
-
Language: { load: vi.fn() },
|
|
13
|
-
},
|
|
14
|
-
}));
|
|
15
|
-
import { evaluateRules } from "../intelligence/rule-evaluator.js";
|
|
16
|
-
function createMockLocalGraph(entities = []) {
|
|
17
|
-
return {
|
|
18
|
-
getEntitiesByFile: vi.fn().mockReturnValue(entities),
|
|
19
|
-
getEntity: vi.fn(),
|
|
20
|
-
getCallersOf: vi.fn().mockReturnValue([]),
|
|
21
|
-
getCalleesOf: vi.fn().mockReturnValue([]),
|
|
22
|
-
searchEntities: vi.fn().mockReturnValue([]),
|
|
23
|
-
getImports: vi.fn().mockReturnValue([]),
|
|
24
|
-
healthCheck: vi.fn().mockReturnValue({ status: "up", latencyMs: 0 }),
|
|
25
|
-
isLoaded: vi.fn().mockReturnValue(true),
|
|
26
|
-
loadSnapshot: vi.fn(),
|
|
27
|
-
loadRules: vi.fn(),
|
|
28
|
-
loadPatterns: vi.fn(),
|
|
29
|
-
hasRules: vi.fn().mockReturnValue(true),
|
|
30
|
-
getRules: vi.fn().mockReturnValue([]),
|
|
31
|
-
getPatterns: vi.fn().mockReturnValue([]),
|
|
32
|
-
loadRuleExceptions: vi.fn(),
|
|
33
|
-
getRuleExceptions: vi.fn().mockReturnValue([]),
|
|
34
|
-
getExpiringExceptions: vi.fn().mockReturnValue([]),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
describe("evaluateRules", () => {
|
|
38
|
-
describe("naming engine", () => {
|
|
39
|
-
it("detects naming violations via regex", async () => {
|
|
40
|
-
const rules = [
|
|
41
|
-
{
|
|
42
|
-
key: "rule-1",
|
|
43
|
-
name: "PascalCase classes",
|
|
44
|
-
scope: "repo",
|
|
45
|
-
severity: "error",
|
|
46
|
-
engine: "naming",
|
|
47
|
-
query: "^[a-z]",
|
|
48
|
-
message: "Classes must start with uppercase",
|
|
49
|
-
file_glob: "",
|
|
50
|
-
enabled: true,
|
|
51
|
-
repo_id: "repo-1",
|
|
52
|
-
},
|
|
53
|
-
];
|
|
54
|
-
const entities = [
|
|
55
|
-
{
|
|
56
|
-
key: "cls1",
|
|
57
|
-
kind: "class",
|
|
58
|
-
name: "myClass",
|
|
59
|
-
file_path: "src/foo.ts",
|
|
60
|
-
start_line: 5,
|
|
61
|
-
signature: "class myClass",
|
|
62
|
-
body: "",
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
key: "cls2",
|
|
66
|
-
kind: "class",
|
|
67
|
-
name: "MyClass",
|
|
68
|
-
file_path: "src/foo.ts",
|
|
69
|
-
start_line: 20,
|
|
70
|
-
signature: "class MyClass",
|
|
71
|
-
body: "",
|
|
72
|
-
},
|
|
73
|
-
];
|
|
74
|
-
const localGraph = createMockLocalGraph(entities);
|
|
75
|
-
const result = await evaluateRules(rules, "src/foo.ts", "", localGraph);
|
|
76
|
-
expect(result.violations.length).toBe(1);
|
|
77
|
-
expect(result.violations[0]?.matchedCode).toBe("myClass");
|
|
78
|
-
expect(result.violations[0]?.severity).toBe("error");
|
|
79
|
-
expect(result._meta.engines.naming).toBe(1);
|
|
80
|
-
});
|
|
81
|
-
it("returns no violations when no entities match", async () => {
|
|
82
|
-
const rules = [
|
|
83
|
-
{
|
|
84
|
-
key: "rule-1",
|
|
85
|
-
name: "No test_ prefix",
|
|
86
|
-
scope: "repo",
|
|
87
|
-
severity: "warn",
|
|
88
|
-
engine: "naming",
|
|
89
|
-
query: "^test_",
|
|
90
|
-
message: "Avoid test_ prefix",
|
|
91
|
-
file_glob: "",
|
|
92
|
-
enabled: true,
|
|
93
|
-
repo_id: "repo-1",
|
|
94
|
-
},
|
|
95
|
-
];
|
|
96
|
-
const entities = [
|
|
97
|
-
{
|
|
98
|
-
key: "fn1",
|
|
99
|
-
kind: "function",
|
|
100
|
-
name: "doStuff",
|
|
101
|
-
file_path: "src/foo.ts",
|
|
102
|
-
start_line: 1,
|
|
103
|
-
signature: "",
|
|
104
|
-
body: "",
|
|
105
|
-
},
|
|
106
|
-
];
|
|
107
|
-
const localGraph = createMockLocalGraph(entities);
|
|
108
|
-
const result = await evaluateRules(rules, "src/foo.ts", "", localGraph);
|
|
109
|
-
expect(result.violations.length).toBe(0);
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
describe("engine partitioning", () => {
|
|
113
|
-
it("skips semgrep and llm rules", async () => {
|
|
114
|
-
const rules = [
|
|
115
|
-
{
|
|
116
|
-
key: "rule-semgrep",
|
|
117
|
-
name: "Semgrep rule",
|
|
118
|
-
scope: "repo",
|
|
119
|
-
severity: "warn",
|
|
120
|
-
engine: "semgrep",
|
|
121
|
-
query: "pattern-not: $X",
|
|
122
|
-
message: "Semgrep",
|
|
123
|
-
file_glob: "",
|
|
124
|
-
enabled: true,
|
|
125
|
-
repo_id: "repo-1",
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
key: "rule-llm",
|
|
129
|
-
name: "LLM rule",
|
|
130
|
-
scope: "repo",
|
|
131
|
-
severity: "info",
|
|
132
|
-
engine: "llm",
|
|
133
|
-
query: "review for security",
|
|
134
|
-
message: "LLM review",
|
|
135
|
-
file_glob: "",
|
|
136
|
-
enabled: true,
|
|
137
|
-
repo_id: "repo-1",
|
|
138
|
-
},
|
|
139
|
-
];
|
|
140
|
-
const localGraph = createMockLocalGraph();
|
|
141
|
-
const result = await evaluateRules(rules, "src/foo.ts", "const x = 1", localGraph);
|
|
142
|
-
expect(result.violations.length).toBe(0);
|
|
143
|
-
expect(result._meta.skippedRules).toBe(2);
|
|
144
|
-
expect(result._meta.evaluatedRules).toBe(0);
|
|
145
|
-
});
|
|
146
|
-
it("skips disabled rules", async () => {
|
|
147
|
-
const rules = [
|
|
148
|
-
{
|
|
149
|
-
key: "rule-disabled",
|
|
150
|
-
name: "Disabled rule",
|
|
151
|
-
scope: "repo",
|
|
152
|
-
severity: "warn",
|
|
153
|
-
engine: "naming",
|
|
154
|
-
query: ".*",
|
|
155
|
-
message: "Match all",
|
|
156
|
-
file_glob: "",
|
|
157
|
-
enabled: false,
|
|
158
|
-
repo_id: "repo-1",
|
|
159
|
-
},
|
|
160
|
-
];
|
|
161
|
-
const localGraph = createMockLocalGraph([
|
|
162
|
-
{
|
|
163
|
-
key: "fn1",
|
|
164
|
-
kind: "function",
|
|
165
|
-
name: "anything",
|
|
166
|
-
file_path: "src/foo.ts",
|
|
167
|
-
start_line: 1,
|
|
168
|
-
signature: "",
|
|
169
|
-
body: "",
|
|
170
|
-
},
|
|
171
|
-
]);
|
|
172
|
-
const result = await evaluateRules(rules, "src/foo.ts", "", localGraph);
|
|
173
|
-
expect(result.violations.length).toBe(0);
|
|
174
|
-
expect(result._meta.skippedRules).toBe(1);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
describe("structural engine (graceful degradation)", () => {
|
|
178
|
-
it("returns empty violations when tree-sitter is not available", async () => {
|
|
179
|
-
const rules = [
|
|
180
|
-
{
|
|
181
|
-
key: "rule-struct",
|
|
182
|
-
name: "Structural rule",
|
|
183
|
-
scope: "repo",
|
|
184
|
-
severity: "warn",
|
|
185
|
-
engine: "structural",
|
|
186
|
-
query: "call_expression",
|
|
187
|
-
message: "Found call",
|
|
188
|
-
file_glob: "",
|
|
189
|
-
enabled: true,
|
|
190
|
-
repo_id: "repo-1",
|
|
191
|
-
},
|
|
192
|
-
];
|
|
193
|
-
const localGraph = createMockLocalGraph();
|
|
194
|
-
const result = await evaluateRules(rules, "src/foo.ts", "console.log('hello')", localGraph);
|
|
195
|
-
// Without tree-sitter WASM files installed, should gracefully return 0 violations
|
|
196
|
-
expect(result._meta.engines.structural).toBe(1);
|
|
197
|
-
expect(result._meta.source).toBe("local");
|
|
198
|
-
});
|
|
199
|
-
it("handles unsupported file extensions gracefully", async () => {
|
|
200
|
-
const rules = [
|
|
201
|
-
{
|
|
202
|
-
key: "rule-struct",
|
|
203
|
-
name: "Structural rule",
|
|
204
|
-
scope: "repo",
|
|
205
|
-
severity: "warn",
|
|
206
|
-
engine: "structural",
|
|
207
|
-
query: "call_expression",
|
|
208
|
-
message: "Found call",
|
|
209
|
-
file_glob: "",
|
|
210
|
-
enabled: true,
|
|
211
|
-
repo_id: "repo-1",
|
|
212
|
-
},
|
|
213
|
-
];
|
|
214
|
-
const localGraph = createMockLocalGraph();
|
|
215
|
-
const result = await evaluateRules(rules, "src/foo.rb", "puts 'hello'", localGraph);
|
|
216
|
-
expect(result.violations.length).toBe(0);
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
describe("meta information", () => {
|
|
220
|
-
it("reports correct engine counts", async () => {
|
|
221
|
-
const rules = [
|
|
222
|
-
{
|
|
223
|
-
key: "r1",
|
|
224
|
-
name: "R1",
|
|
225
|
-
scope: "repo",
|
|
226
|
-
severity: "warn",
|
|
227
|
-
engine: "naming",
|
|
228
|
-
query: "^_",
|
|
229
|
-
message: "",
|
|
230
|
-
file_glob: "",
|
|
231
|
-
enabled: true,
|
|
232
|
-
repo_id: "r",
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
key: "r2",
|
|
236
|
-
name: "R2",
|
|
237
|
-
scope: "repo",
|
|
238
|
-
severity: "warn",
|
|
239
|
-
engine: "structural",
|
|
240
|
-
query: "fn_def",
|
|
241
|
-
message: "",
|
|
242
|
-
file_glob: "",
|
|
243
|
-
enabled: true,
|
|
244
|
-
repo_id: "r",
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
key: "r3",
|
|
248
|
-
name: "R3",
|
|
249
|
-
scope: "repo",
|
|
250
|
-
severity: "warn",
|
|
251
|
-
engine: "semgrep",
|
|
252
|
-
query: "p",
|
|
253
|
-
message: "",
|
|
254
|
-
file_glob: "",
|
|
255
|
-
enabled: true,
|
|
256
|
-
repo_id: "r",
|
|
257
|
-
},
|
|
258
|
-
{
|
|
259
|
-
key: "r4",
|
|
260
|
-
name: "R4",
|
|
261
|
-
scope: "repo",
|
|
262
|
-
severity: "warn",
|
|
263
|
-
engine: "naming",
|
|
264
|
-
query: "^x",
|
|
265
|
-
message: "",
|
|
266
|
-
file_glob: "",
|
|
267
|
-
enabled: false,
|
|
268
|
-
repo_id: "r",
|
|
269
|
-
},
|
|
270
|
-
];
|
|
271
|
-
const localGraph = createMockLocalGraph();
|
|
272
|
-
const result = await evaluateRules(rules, "src/foo.ts", "", localGraph);
|
|
273
|
-
expect(result._meta.engines.naming).toBe(1);
|
|
274
|
-
expect(result._meta.engines.structural).toBe(1);
|
|
275
|
-
expect(result._meta.engines.skipped).toBe(2); // semgrep + disabled
|
|
276
|
-
expect(result._meta.evaluatedRules).toBe(2);
|
|
277
|
-
expect(result._meta.skippedRules).toBe(2);
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
});
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
-
import { decodeScipOutput } from "../intelligence/indexer/scip/decoder.js";
|
|
6
|
-
let tempDir;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
tempDir = join(tmpdir(), `unerr-scip-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
9
|
-
mkdirSync(tempDir, { recursive: true });
|
|
10
|
-
});
|
|
11
|
-
afterEach(() => {
|
|
12
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
13
|
-
});
|
|
14
|
-
describe("SCIP Decoder", () => {
|
|
15
|
-
it("handles empty file gracefully", async () => {
|
|
16
|
-
const filePath = join(tempDir, "empty.scip");
|
|
17
|
-
writeFileSync(filePath, "");
|
|
18
|
-
const result = await decodeScipOutput(filePath);
|
|
19
|
-
expect(result.documents).toHaveLength(0);
|
|
20
|
-
expect(result.symbolCount).toBe(0);
|
|
21
|
-
expect(result.durationMs).toBeGreaterThanOrEqual(0);
|
|
22
|
-
});
|
|
23
|
-
it("handles binary protobuf data without crashing", async () => {
|
|
24
|
-
const filePath = join(tempDir, "binary.scip");
|
|
25
|
-
const randomData = Buffer.alloc(1024);
|
|
26
|
-
for (let i = 0; i < 1024; i++) {
|
|
27
|
-
randomData[i] = Math.floor(Math.random() * 256);
|
|
28
|
-
}
|
|
29
|
-
writeFileSync(filePath, randomData);
|
|
30
|
-
const result = await decodeScipOutput(filePath);
|
|
31
|
-
expect(result.durationMs).toBeGreaterThanOrEqual(0);
|
|
32
|
-
});
|
|
33
|
-
it("produces valid decode result structure", async () => {
|
|
34
|
-
const filePath = join(tempDir, "valid.scip");
|
|
35
|
-
writeFileSync(filePath, Buffer.from([0x0a, 0x02, 0x22, 0x00]));
|
|
36
|
-
const result = await decodeScipOutput(filePath);
|
|
37
|
-
expect(typeof result.symbolCount).toBe("number");
|
|
38
|
-
expect(typeof result.definitionCount).toBe("number");
|
|
39
|
-
expect(typeof result.referenceCount).toBe("number");
|
|
40
|
-
expect(Array.isArray(result.documents)).toBe(true);
|
|
41
|
-
});
|
|
42
|
-
it("reports duration in milliseconds", async () => {
|
|
43
|
-
const filePath = join(tempDir, "timing.scip");
|
|
44
|
-
writeFileSync(filePath, Buffer.alloc(100));
|
|
45
|
-
const result = await decodeScipOutput(filePath);
|
|
46
|
-
expect(result.durationMs).toBeGreaterThanOrEqual(0);
|
|
47
|
-
expect(result.durationMs).toBeLessThan(5000);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { buildDownloadUrl, getAutoDownloadLanguages, getCachedBinaryPath, getDownloadSpec, getManualInstallInstructions, getScipBinDir, isAutoDownloadSupported, resolvePlatform, } from "../intelligence/indexer/scip/downloader.js";
|
|
3
|
-
describe("SCIP Downloader", () => {
|
|
4
|
-
describe("resolvePlatform", () => {
|
|
5
|
-
it("returns valid platform identifiers", () => {
|
|
6
|
-
const platform = resolvePlatform();
|
|
7
|
-
expect(platform.os).toBeDefined();
|
|
8
|
-
expect(platform.arch).toBeDefined();
|
|
9
|
-
expect(platform.rustTriple).toBeDefined();
|
|
10
|
-
expect(platform.nodeArch).toBeDefined();
|
|
11
|
-
expect(["darwin", "linux", "windows"]).toContain(platform.os);
|
|
12
|
-
expect(["x86_64", "aarch64"]).toContain(platform.arch);
|
|
13
|
-
});
|
|
14
|
-
it("returns correct rust triple for current platform", () => {
|
|
15
|
-
const platform = resolvePlatform();
|
|
16
|
-
expect(platform.rustTriple).toMatch(/^(x86_64|aarch64)-(apple-darwin|unknown-linux-gnu|pc-windows-msvc)$/);
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
describe("getAutoDownloadLanguages", () => {
|
|
20
|
-
it("returns exactly the 5 auto-download languages (not bundled ones)", () => {
|
|
21
|
-
const langs = getAutoDownloadLanguages();
|
|
22
|
-
expect(langs).toContain("go");
|
|
23
|
-
expect(langs).toContain("java");
|
|
24
|
-
expect(langs).toContain("rust");
|
|
25
|
-
expect(langs).toContain("ruby");
|
|
26
|
-
expect(langs).toContain("cpp");
|
|
27
|
-
expect(langs).toHaveLength(5);
|
|
28
|
-
// Python is bundled as npm dep, not auto-downloaded
|
|
29
|
-
expect(langs).not.toContain("python");
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
describe("isAutoDownloadSupported", () => {
|
|
33
|
-
it("returns true for auto-download languages", () => {
|
|
34
|
-
expect(isAutoDownloadSupported("go")).toBe(true);
|
|
35
|
-
expect(isAutoDownloadSupported("java")).toBe(true);
|
|
36
|
-
expect(isAutoDownloadSupported("rust")).toBe(true);
|
|
37
|
-
expect(isAutoDownloadSupported("ruby")).toBe(true);
|
|
38
|
-
expect(isAutoDownloadSupported("cpp")).toBe(true);
|
|
39
|
-
});
|
|
40
|
-
it("returns false for bundled and unsupported languages", () => {
|
|
41
|
-
// Bundled as npm deps — not in downloader
|
|
42
|
-
expect(isAutoDownloadSupported("typescript")).toBe(false);
|
|
43
|
-
expect(isAutoDownloadSupported("python")).toBe(false);
|
|
44
|
-
// Not supported at all
|
|
45
|
-
expect(isAutoDownloadSupported("csharp")).toBe(false);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe("getDownloadSpec", () => {
|
|
49
|
-
it("returns spec for go with correct repo", () => {
|
|
50
|
-
const spec = getDownloadSpec("go");
|
|
51
|
-
expect(spec).not.toBeNull();
|
|
52
|
-
expect(spec.binaryName).toBe("scip-go");
|
|
53
|
-
expect(spec.repo).toBe("scip-code/scip-go");
|
|
54
|
-
});
|
|
55
|
-
it("returns spec for rust with correct binary name", () => {
|
|
56
|
-
const spec = getDownloadSpec("rust");
|
|
57
|
-
expect(spec).not.toBeNull();
|
|
58
|
-
expect(spec.binaryName).toBe("rust-analyzer");
|
|
59
|
-
expect(spec.repo).toBe("rust-lang/rust-analyzer");
|
|
60
|
-
});
|
|
61
|
-
it("returns spec for java", () => {
|
|
62
|
-
const spec = getDownloadSpec("java");
|
|
63
|
-
expect(spec).not.toBeNull();
|
|
64
|
-
expect(spec.binaryName).toBe("scip-java");
|
|
65
|
-
expect(spec.repo).toBe("sourcegraph/scip-java");
|
|
66
|
-
});
|
|
67
|
-
it("returns spec for ruby with correct binary name", () => {
|
|
68
|
-
const spec = getDownloadSpec("ruby");
|
|
69
|
-
expect(spec).not.toBeNull();
|
|
70
|
-
expect(spec.binaryName).toBe("scip-ruby");
|
|
71
|
-
expect(spec.repo).toBe("sourcegraph/scip-ruby");
|
|
72
|
-
});
|
|
73
|
-
it("returns spec for cpp with correct binary name", () => {
|
|
74
|
-
const spec = getDownloadSpec("cpp");
|
|
75
|
-
expect(spec).not.toBeNull();
|
|
76
|
-
expect(spec.binaryName).toBe("scip-clang");
|
|
77
|
-
expect(spec.repo).toBe("sourcegraph/scip-clang");
|
|
78
|
-
});
|
|
79
|
-
it("returns null for bundled and unsupported languages", () => {
|
|
80
|
-
expect(getDownloadSpec("typescript")).toBeNull();
|
|
81
|
-
expect(getDownloadSpec("python")).toBeNull();
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
describe("getManualInstallInstructions", () => {
|
|
85
|
-
it("returns instructions for each auto-download language", () => {
|
|
86
|
-
expect(getManualInstallInstructions("go")).toContain("go install");
|
|
87
|
-
expect(getManualInstallInstructions("rust")).toContain("rustup");
|
|
88
|
-
expect(getManualInstallInstructions("java")).toContain("scip-java");
|
|
89
|
-
});
|
|
90
|
-
it("returns null for bundled and unsupported languages", () => {
|
|
91
|
-
expect(getManualInstallInstructions("typescript")).toBeNull();
|
|
92
|
-
expect(getManualInstallInstructions("python")).toBeNull();
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
describe("buildDownloadUrl", () => {
|
|
96
|
-
it("builds correct URL for rust-analyzer with rust triple", () => {
|
|
97
|
-
const spec = getDownloadSpec("rust");
|
|
98
|
-
const platform = {
|
|
99
|
-
os: "darwin",
|
|
100
|
-
arch: "aarch64",
|
|
101
|
-
nodeArch: "arm64",
|
|
102
|
-
rustTriple: "aarch64-apple-darwin",
|
|
103
|
-
};
|
|
104
|
-
const url = buildDownloadUrl(spec, platform, "2024-01-01");
|
|
105
|
-
expect(url).toBe("https://github.com/rust-lang/rust-analyzer/releases/download/2024-01-01/rust-analyzer-aarch64-apple-darwin.gz");
|
|
106
|
-
});
|
|
107
|
-
it("builds correct URL for go on linux arm64", () => {
|
|
108
|
-
const spec = getDownloadSpec("go");
|
|
109
|
-
const platform = {
|
|
110
|
-
os: "linux",
|
|
111
|
-
arch: "aarch64",
|
|
112
|
-
nodeArch: "arm64",
|
|
113
|
-
rustTriple: "aarch64-unknown-linux-gnu",
|
|
114
|
-
};
|
|
115
|
-
const url = buildDownloadUrl(spec, platform, "v0.5.0");
|
|
116
|
-
expect(url).toBe("https://github.com/scip-code/scip-go/releases/download/v0.5.0/scip-go-linux-arm64.tar.gz");
|
|
117
|
-
});
|
|
118
|
-
it("returns null for unsupported platform combinations", () => {
|
|
119
|
-
const spec = getDownloadSpec("go");
|
|
120
|
-
// go has no darwin-amd64 build
|
|
121
|
-
const platform = {
|
|
122
|
-
os: "darwin",
|
|
123
|
-
arch: "x86_64",
|
|
124
|
-
nodeArch: "x64",
|
|
125
|
-
rustTriple: "x86_64-apple-darwin",
|
|
126
|
-
};
|
|
127
|
-
const url = buildDownloadUrl(spec, platform, "v0.5.0");
|
|
128
|
-
expect(url).toBeNull();
|
|
129
|
-
});
|
|
130
|
-
it("returns null for windows", () => {
|
|
131
|
-
const spec = getDownloadSpec("rust");
|
|
132
|
-
const platform = {
|
|
133
|
-
os: "windows",
|
|
134
|
-
arch: "x86_64",
|
|
135
|
-
nodeArch: "x64",
|
|
136
|
-
rustTriple: "x86_64-pc-windows-msvc",
|
|
137
|
-
};
|
|
138
|
-
const url = buildDownloadUrl(spec, platform, "2024-01-01");
|
|
139
|
-
expect(url).toBeNull();
|
|
140
|
-
});
|
|
141
|
-
it("builds correct URL for scip-ruby on darwin arm64", () => {
|
|
142
|
-
const spec = getDownloadSpec("ruby");
|
|
143
|
-
const platform = {
|
|
144
|
-
os: "darwin",
|
|
145
|
-
arch: "aarch64",
|
|
146
|
-
nodeArch: "arm64",
|
|
147
|
-
rustTriple: "aarch64-apple-darwin",
|
|
148
|
-
};
|
|
149
|
-
const url = buildDownloadUrl(spec, platform, "scip-ruby-v0.4.7");
|
|
150
|
-
expect(url).toBe("https://github.com/sourcegraph/scip-ruby/releases/download/scip-ruby-v0.4.7/scip-ruby-arm64-darwin");
|
|
151
|
-
});
|
|
152
|
-
it("builds correct URL for scip-clang on linux x64", () => {
|
|
153
|
-
const spec = getDownloadSpec("cpp");
|
|
154
|
-
const platform = {
|
|
155
|
-
os: "linux",
|
|
156
|
-
arch: "x86_64",
|
|
157
|
-
nodeArch: "x64",
|
|
158
|
-
rustTriple: "x86_64-unknown-linux-gnu",
|
|
159
|
-
};
|
|
160
|
-
const url = buildDownloadUrl(spec, platform, "v0.4.0");
|
|
161
|
-
expect(url).toBe("https://github.com/sourcegraph/scip-clang/releases/download/v0.4.0/scip-clang-x86_64-linux");
|
|
162
|
-
});
|
|
163
|
-
it("returns null for scip-ruby on darwin x64 (no build available)", () => {
|
|
164
|
-
const spec = getDownloadSpec("ruby");
|
|
165
|
-
const platform = {
|
|
166
|
-
os: "darwin",
|
|
167
|
-
arch: "x86_64",
|
|
168
|
-
nodeArch: "x64",
|
|
169
|
-
rustTriple: "x86_64-apple-darwin",
|
|
170
|
-
};
|
|
171
|
-
const url = buildDownloadUrl(spec, platform, "scip-ruby-v0.4.7");
|
|
172
|
-
expect(url).toBeNull();
|
|
173
|
-
});
|
|
174
|
-
it("returns null for scip-clang on linux arm64 (no build available)", () => {
|
|
175
|
-
const spec = getDownloadSpec("cpp");
|
|
176
|
-
const platform = {
|
|
177
|
-
os: "linux",
|
|
178
|
-
arch: "aarch64",
|
|
179
|
-
nodeArch: "arm64",
|
|
180
|
-
rustTriple: "aarch64-unknown-linux-gnu",
|
|
181
|
-
};
|
|
182
|
-
const url = buildDownloadUrl(spec, platform, "v0.4.0");
|
|
183
|
-
expect(url).toBeNull();
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
describe("getCachedBinaryPath", () => {
|
|
187
|
-
it("returns null when no cached binary exists for unsupported language", () => {
|
|
188
|
-
expect(getCachedBinaryPath("haskell")).toBeNull();
|
|
189
|
-
});
|
|
190
|
-
it("returns null for unsupported languages", () => {
|
|
191
|
-
expect(getCachedBinaryPath("typescript")).toBeNull();
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
describe("getScipBinDir", () => {
|
|
195
|
-
it("returns path under ~/.unerr/bin", () => {
|
|
196
|
-
const binDir = getScipBinDir();
|
|
197
|
-
expect(binDir).toContain(".unerr");
|
|
198
|
-
expect(binDir).toContain("bin");
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
});
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { applyScipFallback, classifyScipError, } from "../intelligence/indexer/scip/fallback.js";
|
|
3
|
-
import { mergeScipResults, } from "../intelligence/indexer/scip/merger.js";
|
|
4
|
-
describe("SCIP Merger (L2.4)", () => {
|
|
5
|
-
it("upgrades edges when SCIP evidence exists", () => {
|
|
6
|
-
const edges = [
|
|
7
|
-
{
|
|
8
|
-
from_key: "a",
|
|
9
|
-
to_key: "b",
|
|
10
|
-
type: "calls",
|
|
11
|
-
file_path: "src/main.ts",
|
|
12
|
-
line: 10,
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
from_key: "c",
|
|
16
|
-
to_key: "d",
|
|
17
|
-
type: "calls",
|
|
18
|
-
file_path: "src/utils.ts",
|
|
19
|
-
line: 20,
|
|
20
|
-
},
|
|
21
|
-
];
|
|
22
|
-
const scipResult = {
|
|
23
|
-
documents: [
|
|
24
|
-
{
|
|
25
|
-
relativePath: "src/main.ts",
|
|
26
|
-
symbols: [
|
|
27
|
-
{
|
|
28
|
-
symbol: "scip-typescript npm test 0.1.0 src/`main.ts`/b.",
|
|
29
|
-
filePath: "src/main.ts",
|
|
30
|
-
line: 10,
|
|
31
|
-
isDefinition: true,
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
},
|
|
35
|
-
],
|
|
36
|
-
symbolCount: 1,
|
|
37
|
-
definitionCount: 1,
|
|
38
|
-
referenceCount: 0,
|
|
39
|
-
durationMs: 100,
|
|
40
|
-
};
|
|
41
|
-
// Provide entity info so merger can match by (name, file_path)
|
|
42
|
-
const entities = [
|
|
43
|
-
{ key: "b", name: "b", file_path: "src/main.ts" },
|
|
44
|
-
{ key: "d", name: "d", file_path: "src/utils.ts" },
|
|
45
|
-
];
|
|
46
|
-
const { edges: enriched, result } = mergeScipResults(edges, scipResult, entities);
|
|
47
|
-
expect(enriched).toHaveLength(2);
|
|
48
|
-
expect(result.edgesUpgraded).toBeGreaterThanOrEqual(1);
|
|
49
|
-
const upgraded = enriched.find((e) => e.scipVerified);
|
|
50
|
-
if (upgraded) {
|
|
51
|
-
expect(upgraded.confidence).toBe("compiler-verified");
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
it("preserves structural confidence when no SCIP evidence", () => {
|
|
55
|
-
const edges = [
|
|
56
|
-
{
|
|
57
|
-
from_key: "x",
|
|
58
|
-
to_key: "y",
|
|
59
|
-
type: "contains",
|
|
60
|
-
file_path: "src/a.ts",
|
|
61
|
-
line: 5,
|
|
62
|
-
},
|
|
63
|
-
];
|
|
64
|
-
const scipResult = {
|
|
65
|
-
documents: [],
|
|
66
|
-
symbolCount: 0,
|
|
67
|
-
definitionCount: 0,
|
|
68
|
-
referenceCount: 0,
|
|
69
|
-
durationMs: 0,
|
|
70
|
-
};
|
|
71
|
-
const { edges: enriched } = mergeScipResults(edges, scipResult);
|
|
72
|
-
expect(enriched[0]?.confidence).toBe("structural");
|
|
73
|
-
expect(enriched[0]?.scipVerified).toBe(false);
|
|
74
|
-
});
|
|
75
|
-
it("handles empty edge list", () => {
|
|
76
|
-
const { edges, result } = mergeScipResults([], {
|
|
77
|
-
documents: [],
|
|
78
|
-
symbolCount: 0,
|
|
79
|
-
definitionCount: 0,
|
|
80
|
-
referenceCount: 0,
|
|
81
|
-
durationMs: 0,
|
|
82
|
-
});
|
|
83
|
-
expect(edges).toHaveLength(0);
|
|
84
|
-
expect(result.edgesUpgraded).toBe(0);
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
describe("SCIP Fallback (L2.9)", () => {
|
|
88
|
-
it("applies structural confidence on fallback", () => {
|
|
89
|
-
const edges = [
|
|
90
|
-
{ from_key: "a", to_key: "b", type: "calls", file_path: "f.ts", line: 1 },
|
|
91
|
-
];
|
|
92
|
-
const result = applyScipFallback(edges, "binary not found");
|
|
93
|
-
expect(result.level).toBe("unavailable");
|
|
94
|
-
expect(result.edges[0]?.confidence).toBe("structural");
|
|
95
|
-
expect(result.edges[0]?.scipVerified).toBe(false);
|
|
96
|
-
});
|
|
97
|
-
it("classifies error types correctly", () => {
|
|
98
|
-
expect(classifyScipError("ENOENT: not found")).toBe("unavailable");
|
|
99
|
-
expect(classifyScipError("timeout exceeded")).toBe("partial");
|
|
100
|
-
expect(classifyScipError("protobuf decode failed")).toBe("partial");
|
|
101
|
-
expect(classifyScipError("unknown error")).toBe("unavailable");
|
|
102
|
-
});
|
|
103
|
-
});
|