Skip to content

Commit 1eb9946

Browse files
authored
Implement multi-level glob patterns (#51)
Fixes #50
1 parent beb095a commit 1eb9946

File tree

3 files changed

+397
-19
lines changed

3 files changed

+397
-19
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
{
2+
"1aa828f0cab48e15": {
3+
"command": "echo */*/test.ts",
4+
"files": {
5+
"src/a/test.ts": "test a",
6+
"src/b/test.ts": "test b",
7+
"lib/c/test.ts": "test c"
8+
},
9+
"stdout": "lib/c/test.ts src/a/test.ts src/b/test.ts\n",
10+
"stderr": "",
11+
"exitCode": 0
12+
},
13+
"34061471e21f2f7b": {
14+
"command": "cat data/*/config.json",
15+
"files": {
16+
"data/v1/config.json": "v1 config",
17+
"data/v2/config.json": "v2 config",
18+
"data/v1/settings.json": "v1 settings"
19+
},
20+
"stdout": "v1 configv2 config",
21+
"stderr": "",
22+
"exitCode": 0
23+
},
24+
"36e1a6fc5c546c4a": {
25+
"command": "grep hello */*.txt",
26+
"files": {
27+
"dir1/file.txt": "hello world",
28+
"dir2/file.txt": "hello there",
29+
"dir3/other.txt": "goodbye"
30+
},
31+
"stdout": "dir1/file.txt:hello world\ndir2/file.txt:hello there\n",
32+
"stderr": "",
33+
"exitCode": 0
34+
},
35+
"63d9a4a8524ef1c5": {
36+
"command": "cat dm/*/*.json",
37+
"files": {
38+
"dm/folder1/data.json": "{\"a\":1}",
39+
"dm/folder2/data.json": "{\"b\":2}",
40+
"dm/folder3/other.txt": "text"
41+
},
42+
"stdout": "{\"a\":1}{\"b\":2}",
43+
"stderr": "",
44+
"exitCode": 0
45+
},
46+
"71ed22308ca718e0": {
47+
"command": "echo */*/*/*.txt",
48+
"files": {
49+
"a/b/c/file.txt": "abc",
50+
"a/d/e/file.txt": "ade",
51+
"x/y/z/file.txt": "xyz"
52+
},
53+
"stdout": "a/b/c/file.txt a/d/e/file.txt x/y/z/file.txt\n",
54+
"stderr": "",
55+
"exitCode": 0
56+
},
57+
"78341dea8687b9df": {
58+
"command": "echo file?.txt",
59+
"files": {
60+
"file1.txt": "1",
61+
"file2.txt": "2",
62+
"file10.txt": "10"
63+
},
64+
"stdout": "file1.txt file2.txt\n",
65+
"stderr": "",
66+
"exitCode": 0
67+
},
68+
"bfa75a70c606b65d": {
69+
"command": "echo *.txt",
70+
"files": {
71+
"file1.txt": "content 1",
72+
"file2.txt": "content 2",
73+
"file3.json": "{}"
74+
},
75+
"stdout": "file1.txt file2.txt\n",
76+
"stderr": "",
77+
"exitCode": 0
78+
},
79+
"e71d5efd2763b87f": {
80+
"command": "echo *.xyz",
81+
"files": {
82+
"file.txt": "content"
83+
},
84+
"stdout": "*.xyz\n",
85+
"stderr": "",
86+
"exitCode": 0
87+
},
88+
"f21fa1e2a2f364fd": {
89+
"command": "echo */*.json",
90+
"files": {
91+
"folder1/data.json": "{\"a\":1}",
92+
"folder2/data.json": "{\"b\":2}",
93+
"folder3/other.txt": "text"
94+
},
95+
"stdout": "folder1/data.json folder2/data.json\n",
96+
"stderr": "",
97+
"exitCode": 0
98+
},
99+
"f39742739256f25c": {
100+
"command": "echo file[12].txt",
101+
"files": {
102+
"file1.txt": "1",
103+
"file2.txt": "2",
104+
"file3.txt": "3",
105+
"filea.txt": "a"
106+
},
107+
"stdout": "file1.txt file2.txt\n",
108+
"stderr": "",
109+
"exitCode": 0
110+
}
111+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { afterEach, beforeEach, describe, it } from "vitest";
2+
import {
3+
cleanupTestDir,
4+
compareOutputs,
5+
createTestDir,
6+
setupFiles,
7+
} from "./test-helpers.js";
8+
9+
describe("glob expansion - Real Bash Comparison", () => {
10+
let testDir: string;
11+
12+
beforeEach(async () => {
13+
testDir = await createTestDir();
14+
});
15+
16+
afterEach(async () => {
17+
await cleanupTestDir(testDir);
18+
});
19+
20+
it("should expand single-level glob pattern", async () => {
21+
const env = await setupFiles(testDir, {
22+
"file1.txt": "content 1",
23+
"file2.txt": "content 2",
24+
"file3.json": "{}",
25+
});
26+
await compareOutputs(env, testDir, "echo *.txt");
27+
});
28+
29+
it("should expand multi-level glob pattern with wildcard directory", async () => {
30+
const env = await setupFiles(testDir, {
31+
"folder1/data.json": '{"a":1}',
32+
"folder2/data.json": '{"b":2}',
33+
"folder3/other.txt": "text",
34+
});
35+
await compareOutputs(env, testDir, "echo */*.json");
36+
});
37+
38+
it("should expand multi-level glob pattern with absolute path", async () => {
39+
const env = await setupFiles(testDir, {
40+
"dm/folder1/data.json": '{"a":1}',
41+
"dm/folder2/data.json": '{"b":2}',
42+
"dm/folder3/other.txt": "text",
43+
});
44+
await compareOutputs(env, testDir, "cat dm/*/*.json");
45+
});
46+
47+
it("should expand triple-level glob pattern", async () => {
48+
const env = await setupFiles(testDir, {
49+
"a/b/c/file.txt": "abc",
50+
"a/d/e/file.txt": "ade",
51+
"x/y/z/file.txt": "xyz",
52+
});
53+
await compareOutputs(env, testDir, "echo */*/*/*.txt");
54+
});
55+
56+
it("should expand glob with question mark", async () => {
57+
const env = await setupFiles(testDir, {
58+
"file1.txt": "1",
59+
"file2.txt": "2",
60+
"file10.txt": "10",
61+
});
62+
await compareOutputs(env, testDir, "echo file?.txt");
63+
});
64+
65+
it("should expand glob with character class", async () => {
66+
const env = await setupFiles(testDir, {
67+
"file1.txt": "1",
68+
"file2.txt": "2",
69+
"file3.txt": "3",
70+
"filea.txt": "a",
71+
});
72+
await compareOutputs(env, testDir, "echo file[12].txt");
73+
});
74+
75+
it("should return pattern when no matches", async () => {
76+
const env = await setupFiles(testDir, {
77+
"file.txt": "content",
78+
});
79+
await compareOutputs(env, testDir, "echo *.xyz");
80+
});
81+
82+
it("should expand glob with grep command", async () => {
83+
const env = await setupFiles(testDir, {
84+
"dir1/file.txt": "hello world",
85+
"dir2/file.txt": "hello there",
86+
"dir3/other.txt": "goodbye",
87+
});
88+
await compareOutputs(env, testDir, "grep hello */*.txt");
89+
});
90+
91+
it("should expand glob at root level with subdirectory pattern", async () => {
92+
const env = await setupFiles(testDir, {
93+
"src/a/test.ts": "test a",
94+
"src/b/test.ts": "test b",
95+
"lib/c/test.ts": "test c",
96+
});
97+
await compareOutputs(env, testDir, "echo */*/test.ts");
98+
});
99+
100+
it("should handle mixed glob and literal segments", async () => {
101+
const env = await setupFiles(testDir, {
102+
"data/v1/config.json": "v1 config",
103+
"data/v2/config.json": "v2 config",
104+
"data/v1/settings.json": "v1 settings",
105+
});
106+
await compareOutputs(env, testDir, "cat data/*/config.json");
107+
});
108+
});

0 commit comments

Comments
 (0)