wip library to store cold objects in s3, warm objects on disk, and hot objects in memory
nodejs
typescript
1import { describe, it, expect } from 'vitest';
2import { matchGlob } from '../src/utils/glob.js';
3
4describe('matchGlob', () => {
5 describe('exact matches', () => {
6 it('should match exact strings', () => {
7 expect(matchGlob('index.html', 'index.html')).toBe(true);
8 expect(matchGlob('index.html', 'about.html')).toBe(false);
9 });
10
11 it('should match paths exactly', () => {
12 expect(matchGlob('site/index.html', 'site/index.html')).toBe(true);
13 expect(matchGlob('site/index.html', 'other/index.html')).toBe(false);
14 });
15 });
16
17 describe('* wildcard', () => {
18 it('should match any characters except /', () => {
19 expect(matchGlob('*.html', 'index.html')).toBe(true);
20 expect(matchGlob('*.html', 'about.html')).toBe(true);
21 expect(matchGlob('*.html', 'style.css')).toBe(false);
22 });
23
24 it('should not match across path separators', () => {
25 expect(matchGlob('*.html', 'dir/index.html')).toBe(false);
26 });
27
28 it('should work with prefix and suffix', () => {
29 expect(matchGlob('index.*', 'index.html')).toBe(true);
30 expect(matchGlob('index.*', 'index.css')).toBe(true);
31 expect(matchGlob('index.*', 'about.html')).toBe(false);
32 });
33 });
34
35 describe('** wildcard', () => {
36 it('should match any characters including /', () => {
37 expect(matchGlob('**', 'anything')).toBe(true);
38 expect(matchGlob('**', 'path/to/file.txt')).toBe(true);
39 });
40
41 it('should match deeply nested paths', () => {
42 expect(matchGlob('**/index.html', 'index.html')).toBe(true);
43 expect(matchGlob('**/index.html', 'site/index.html')).toBe(true);
44 expect(matchGlob('**/index.html', 'a/b/c/index.html')).toBe(true);
45 expect(matchGlob('**/index.html', 'a/b/c/about.html')).toBe(false);
46 });
47
48 it('should match directory prefixes', () => {
49 expect(matchGlob('assets/**', 'assets/style.css')).toBe(true);
50 expect(matchGlob('assets/**', 'assets/images/logo.png')).toBe(true);
51 expect(matchGlob('assets/**', 'other/style.css')).toBe(false);
52 });
53
54 it('should match in the middle of a path', () => {
55 expect(matchGlob('site/**/index.html', 'site/index.html')).toBe(true);
56 expect(matchGlob('site/**/index.html', 'site/pages/index.html')).toBe(true);
57 expect(matchGlob('site/**/index.html', 'site/a/b/c/index.html')).toBe(true);
58 });
59 });
60
61 describe('{a,b,c} alternation', () => {
62 it('should match any of the alternatives', () => {
63 expect(matchGlob('*.{html,css,js}', 'index.html')).toBe(true);
64 expect(matchGlob('*.{html,css,js}', 'style.css')).toBe(true);
65 expect(matchGlob('*.{html,css,js}', 'app.js')).toBe(true);
66 expect(matchGlob('*.{html,css,js}', 'image.png')).toBe(false);
67 });
68
69 it('should work with ** and alternation', () => {
70 expect(matchGlob('**/*.{jpg,png,gif}', 'logo.png')).toBe(true);
71 expect(matchGlob('**/*.{jpg,png,gif}', 'images/logo.png')).toBe(true);
72 expect(matchGlob('**/*.{jpg,png,gif}', 'a/b/photo.jpg')).toBe(true);
73 expect(matchGlob('**/*.{jpg,png,gif}', 'style.css')).toBe(false);
74 });
75 });
76
77 describe('edge cases', () => {
78 it('should handle empty strings', () => {
79 expect(matchGlob('', '')).toBe(true);
80 expect(matchGlob('', 'something')).toBe(false);
81 expect(matchGlob('**', '')).toBe(true);
82 });
83
84 it('should escape regex special characters', () => {
85 expect(matchGlob('file.txt', 'file.txt')).toBe(true);
86 expect(matchGlob('file.txt', 'filextxt')).toBe(false);
87 expect(matchGlob('file[1].txt', 'file[1].txt')).toBe(true);
88 });
89
90 it('should handle keys with colons (common in storage)', () => {
91 expect(matchGlob('site:*/index.html', 'site:abc/index.html')).toBe(true);
92 expect(matchGlob('site:**/index.html', 'site:abc/pages/index.html')).toBe(true);
93 });
94 });
95});