@polderlabs/bizar 3.16.0 → 3.19.0

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.
@@ -1,218 +0,0 @@
1
- /**
2
- * cli/graph.test.mjs
3
- *
4
- * Tests for the `bizar graph` subcommand.
5
- * Uses Node's built-in node:test (no external test framework).
6
- *
7
- * Covered:
8
- * - findPython() returns a string when Python is on PATH (or null)
9
- * - parseGraphStats() returns null for nonexistent files
10
- * - parseGraphStats() returns correct {nodes, edges, communities} from a fixture
11
- * - GRAPH_DIR constant is '.bizar/graph'
12
- * - help output contains all subcommand names
13
- */
14
-
15
- import { test, describe } from 'node:test';
16
- import assert from 'node:assert/strict';
17
- import { existsSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
18
- import { join, dirname } from 'node:path';
19
- import { fileURLToPath } from 'node:url';
20
-
21
- // Resolve graph.mjs from this test file's location
22
- const __dirname = dirname(fileURLToPath(import.meta.url));
23
- const PROJECT_ROOT = join(__dirname, '..');
24
-
25
- const {
26
- findPython,
27
- parseGraphStats,
28
- showGraphHelp,
29
- GRAPH_DIR,
30
- } = await import('./graph.mjs');
31
-
32
- // ── Constants ─────────────────────────────────────────────────────────────────
33
-
34
- test('GRAPH_DIR equals ".bizar/graph"', () => {
35
- assert.equal(GRAPH_DIR, '.bizar/graph');
36
- });
37
-
38
- // ── findPython ────────────────────────────────────────────────────────────────
39
-
40
- describe('findPython()', () => {
41
- test('returns a string when python3 or python is on PATH', () => {
42
- const result = findPython();
43
- // On most dev machines Python is installed; the test documents the expected shape
44
- if (result !== null) {
45
- assert.equal(typeof result, 'string');
46
- assert.ok(result.length > 0);
47
- }
48
- });
49
-
50
- test('returns null when neither python3 nor python is found', () => {
51
- // We can't easily stub PATH in this test runner without副作用,
52
- // so we verify the function is deterministic and returns the same value
53
- // across two calls (proving it doesn't throw or return garbage).
54
- const first = findPython();
55
- const second = findPython();
56
- assert.equal(first, second, 'findPython should be deterministic');
57
- });
58
- });
59
-
60
- // ── parseGraphStats ────────────────────────────────────────────────────────────
61
-
62
- describe('parseGraphStats()', () => {
63
- test('returns null for a nonexistent path', () => {
64
- const result = parseGraphStats('/nonexistent/path/graph.json');
65
- assert.equal(result, null);
66
- });
67
-
68
- test('returns null for a file that is not valid JSON', () => {
69
- const tmpDir = join(PROJECT_ROOT, '.tmp_graph_test');
70
- mkdirSync(tmpDir, { recursive: true });
71
- try {
72
- const badPath = join(tmpDir, 'graph.json');
73
- writeFileSync(badPath, '{ not json', 'utf8');
74
- const result = parseGraphStats(badPath);
75
- assert.equal(result, null);
76
- } finally {
77
- rmSync(tmpDir, { recursive: true });
78
- }
79
- });
80
-
81
- test('returns zeroed stats when graph.json has null nodes/links arrays', () => {
82
- const tmpDir = join(PROJECT_ROOT, '.tmp_graph_test2');
83
- mkdirSync(tmpDir, { recursive: true });
84
- try {
85
- const graphPath = join(tmpDir, 'graph.json');
86
- writeFileSync(graphPath, JSON.stringify({ graph: {}, nodes: null, links: null }), 'utf8');
87
- const result = parseGraphStats(graphPath);
88
- // null arrays are treated as 0-length — parseGraphStats guards with Array.isArray
89
- assert.notEqual(result, null);
90
- assert.equal(result.nodes, 0);
91
- assert.equal(result.edges, 0);
92
- assert.equal(result.communities, 0);
93
- } finally {
94
- rmSync(tmpDir, { recursive: true });
95
- }
96
- });
97
-
98
- test('returns correct stats from a minimal NetworkX node-link fixture', () => {
99
- const tmpDir = join(PROJECT_ROOT, '.tmp_graph_test3');
100
- mkdirSync(tmpDir, { recursive: true });
101
- try {
102
- const graphPath = join(tmpDir, 'graph.json');
103
-
104
- // NetworkX node-link JSON with 4 nodes, 3 links, 2 communities
105
- const fixture = {
106
- directed: false,
107
- multigraph: false,
108
- graph: {},
109
- nodes: [
110
- { id: 'alpha', community: 0 },
111
- { id: 'beta', community: 0 },
112
- { id: 'gamma', community: 1 },
113
- { id: 'delta', community: 1 },
114
- ],
115
- links: [
116
- { source: 'alpha', target: 'beta' },
117
- { source: 'beta', target: 'gamma' },
118
- { source: 'gamma', target: 'delta' },
119
- ],
120
- };
121
-
122
- writeFileSync(graphPath, JSON.stringify(fixture), 'utf8');
123
-
124
- const stats = parseGraphStats(graphPath);
125
-
126
- assert.notEqual(stats, null);
127
- assert.equal(stats.nodes, 4, 'should count 4 nodes');
128
- assert.equal(stats.edges, 3, 'should count 3 links');
129
- assert.equal(stats.communities, 2, 'should detect 2 unique communities (0 and 1)');
130
- assert.ok(typeof stats.lastModified === 'string', 'lastModified should be ISO string');
131
- assert.ok(typeof stats.sizeBytes === 'number', 'sizeBytes should be a number');
132
- assert.ok(stats.sizeBytes > 0, 'sizeBytes should be > 0 for a real file');
133
- } finally {
134
- rmSync(tmpDir, { recursive: true });
135
- }
136
- });
137
-
138
- test('handles nodes without a community field gracefully', () => {
139
- const tmpDir = join(PROJECT_ROOT, '.tmp_graph_test4');
140
- mkdirSync(tmpDir, { recursive: true });
141
- try {
142
- const graphPath = join(tmpDir, 'graph.json');
143
- const fixture = {
144
- nodes: [
145
- { id: 'orphan' }, // no community field
146
- { id: 'solo', community: 0 },
147
- { id: 'alone', community: 1 },
148
- ],
149
- links: [],
150
- };
151
- writeFileSync(graphPath, JSON.stringify(fixture), 'utf8');
152
- const stats = parseGraphStats(graphPath);
153
- assert.notEqual(stats, null);
154
- assert.equal(stats.communities, 2, 'should count communities 0 and 1 only');
155
- } finally {
156
- rmSync(tmpDir, { recursive: true });
157
- }
158
- });
159
- });
160
-
161
- // ── Help output ───────────────────────────────────────────────────────────────
162
-
163
- describe('showGraphHelp()', () => {
164
- test('outputs all subcommand names', () => {
165
- // Capture stdout
166
- let output = '';
167
- const originalLog = console.log;
168
- console.log = (msg) => { output += msg + '\n'; };
169
-
170
- try {
171
- showGraphHelp();
172
- } finally {
173
- console.log = originalLog;
174
- }
175
-
176
- // Assert each expected subcommand keyword appears in the help text
177
- const subcommands = ['build', 'update', 'query', 'path', 'explain', 'watch', 'status', 'install'];
178
- for (const cmd of subcommands) {
179
- assert.ok(
180
- output.includes(cmd),
181
- `help output should contain subcommand "${cmd}"`
182
- );
183
- }
184
- });
185
-
186
- test('mentions the GRAPH_DIR path', () => {
187
- let output = '';
188
- const originalLog = console.log;
189
- console.log = (msg) => { output += msg + '\n'; };
190
-
191
- try {
192
- showGraphHelp();
193
- } finally {
194
- console.log = originalLog;
195
- }
196
-
197
- assert.ok(output.includes('.bizar/graph'), 'help should mention the graph directory');
198
- });
199
-
200
- test('mentions graphify pip install command', () => {
201
- let output = '';
202
- const originalLog = console.log;
203
- console.log = (msg) => { output += msg + '\n'; };
204
-
205
- try {
206
- showGraphHelp();
207
- } finally {
208
- console.log = originalLog;
209
- }
210
-
211
- assert.ok(
212
- output.includes('pip install graphifyy'),
213
- 'help should mention pip install graphifyy'
214
- );
215
- });
216
- });
217
-
218
- console.log(' graph.mjs tests loaded — run with: node --test cli/graph.test.mjs');