File size: 5,775 Bytes
1dbc34b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
 * Path Utilities Tests
 */

import { describe, it, expect } from 'vitest';
import { normalizePath, pathsEqual, sanitizeFilename } from '../src/path-utils.js';

describe('normalizePath', () => {
  it('should convert backslashes to forward slashes', () => {
    expect(normalizePath('C:\\Users\\foo\\bar')).toBe('C:/Users/foo/bar');
  });

  it('should leave forward slashes unchanged', () => {
    expect(normalizePath('/home/foo/bar')).toBe('/home/foo/bar');
  });

  it('should handle mixed separators', () => {
    expect(normalizePath('C:\\Users/foo\\bar')).toBe('C:/Users/foo/bar');
  });
});

describe('pathsEqual', () => {
  it('should return true for equal paths', () => {
    expect(pathsEqual('/home/user', '/home/user')).toBe(true);
  });

  it('should return true for paths with different separators', () => {
    expect(pathsEqual('C:\\foo\\bar', 'C:/foo/bar')).toBe(true);
  });

  it('should return false for different paths', () => {
    expect(pathsEqual('/home/user', '/home/other')).toBe(false);
  });

  it('should handle null and undefined', () => {
    expect(pathsEqual(null, null)).toBe(true);
    expect(pathsEqual(undefined, undefined)).toBe(true);
    expect(pathsEqual(null, undefined)).toBe(false);
    expect(pathsEqual(null, '/path')).toBe(false);
    expect(pathsEqual('/path', null)).toBe(false);
  });
});

describe('sanitizeFilename', () => {
  describe('Windows reserved names', () => {
    it('should prefix Windows reserved device names', () => {
      expect(sanitizeFilename('nul')).toBe('_nul');
      expect(sanitizeFilename('NUL')).toBe('_NUL');
      expect(sanitizeFilename('con')).toBe('_con');
      expect(sanitizeFilename('CON')).toBe('_CON');
      expect(sanitizeFilename('prn')).toBe('_prn');
      expect(sanitizeFilename('aux')).toBe('_aux');
    });

    it('should prefix COM and LPT port names', () => {
      expect(sanitizeFilename('com1')).toBe('_com1');
      expect(sanitizeFilename('COM5')).toBe('_COM5');
      expect(sanitizeFilename('lpt1')).toBe('_lpt1');
      expect(sanitizeFilename('LPT9')).toBe('_LPT9');
    });

    it('should not prefix reserved names with extensions', () => {
      // After removing extension, baseName might be reserved
      expect(sanitizeFilename('nul')).toBe('_nul');
    });

    it('should not prefix non-reserved names that contain reserved words', () => {
      expect(sanitizeFilename('null')).toBe('null'); // "null" is not reserved, only "nul"
      expect(sanitizeFilename('console')).toBe('console');
      expect(sanitizeFilename('auxiliary')).toBe('auxiliary');
    });
  });

  describe('Invalid characters', () => {
    it('should remove path separators', () => {
      expect(sanitizeFilename('foo/bar')).toBe('foobar');
      expect(sanitizeFilename('foo\\bar')).toBe('foobar');
    });

    it('should remove Windows invalid characters', () => {
      expect(sanitizeFilename('file:name')).toBe('filename');
      expect(sanitizeFilename('file*name')).toBe('filename');
      expect(sanitizeFilename('file?name')).toBe('filename');
      expect(sanitizeFilename('file"name')).toBe('filename');
      expect(sanitizeFilename('file<name>')).toBe('filename');
      expect(sanitizeFilename('file|name')).toBe('filename');
    });

    it('should replace spaces with underscores', () => {
      expect(sanitizeFilename('my file name')).toBe('my_file_name');
      expect(sanitizeFilename('file   name')).toBe('file_name'); // multiple spaces
    });

    it('should remove leading and trailing dots', () => {
      expect(sanitizeFilename('.hidden')).toBe('hidden');
      expect(sanitizeFilename('file...')).toBe('file');
      expect(sanitizeFilename('...file...')).toBe('file');
    });
  });

  describe('Edge cases', () => {
    it('should return fallback for empty strings', () => {
      expect(sanitizeFilename('')).toBe('file');
      expect(sanitizeFilename('', 'default')).toBe('default');
    });

    it('should return fallback for null/undefined', () => {
      expect(sanitizeFilename(null as any)).toBe('file');
      expect(sanitizeFilename(undefined as any)).toBe('file');
      expect(sanitizeFilename(null as any, 'image')).toBe('image');
    });

    it('should return fallback for strings that become empty after sanitization', () => {
      expect(sanitizeFilename('...')).toBe('file');
      expect(sanitizeFilename('///\\\\\\')).toBe('file');
      expect(sanitizeFilename('???')).toBe('file');
    });

    it('should handle non-string inputs', () => {
      expect(sanitizeFilename(123 as any)).toBe('file');
      expect(sanitizeFilename({} as any)).toBe('file');
    });
  });

  describe('Normal filenames', () => {
    it('should preserve normal filenames', () => {
      expect(sanitizeFilename('document')).toBe('document');
      expect(sanitizeFilename('file123')).toBe('file123');
      expect(sanitizeFilename('my-file_name')).toBe('my-file_name');
    });

    it('should handle unicode characters', () => {
      expect(sanitizeFilename('文件')).toBe('文件');
      expect(sanitizeFilename('файл')).toBe('файл');
      expect(sanitizeFilename('café')).toBe('café');
    });
  });

  describe('Real-world examples from bug report', () => {
    it('should handle filename that might become "nul"', () => {
      // If a filename is "null.png", basename would be "null"
      expect(sanitizeFilename('null')).toBe('null'); // "null" is ok
      expect(sanitizeFilename('nul')).toBe('_nul'); // "nul" is reserved
    });

    it('should sanitize typical image filenames', () => {
      expect(sanitizeFilename('screenshot')).toBe('screenshot');
      expect(sanitizeFilename('image 1')).toBe('image_1');
      expect(sanitizeFilename('photo?.jpg')).toBe('photo.jpg'); // ? removed, . is valid
    });
  });
});