1'use strict'; 2const { isWindows } = require('../common'); 3const assert = require('assert'); 4const url = require('url'); 5 6{ 7 const fileURL = url.pathToFileURL('test/').href; 8 assert.ok(fileURL.startsWith('file:///')); 9 assert.ok(fileURL.endsWith('/')); 10} 11 12{ 13 const fileURL = url.pathToFileURL('test\\').href; 14 assert.ok(fileURL.startsWith('file:///')); 15 if (isWindows) 16 assert.ok(fileURL.endsWith('/')); 17 else 18 assert.ok(fileURL.endsWith('%5C')); 19} 20 21{ 22 const fileURL = url.pathToFileURL('test/%').href; 23 assert.ok(fileURL.includes('%25')); 24} 25 26{ 27 if (isWindows) { 28 // UNC path: \\server\share\resource 29 30 // Missing server: 31 assert.throws(() => url.pathToFileURL('\\\\\\no-server'), { 32 code: 'ERR_INVALID_ARG_VALUE' 33 }); 34 35 // Missing share or resource: 36 assert.throws(() => url.pathToFileURL('\\\\host'), { 37 code: 'ERR_INVALID_ARG_VALUE' 38 }); 39 } else { 40 // UNC paths on posix are considered a single path that has backslashes: 41 const fileURL = url.pathToFileURL('\\\\nas\\share\\path.txt').href; 42 assert.match(fileURL, /file:\/\/.+%5C%5Cnas%5Cshare%5Cpath\.txt$/); 43 } 44} 45 46{ 47 let testCases; 48 if (isWindows) { 49 testCases = [ 50 // Lowercase ascii alpha 51 { path: 'C:\\foo', expected: 'file:///C:/foo' }, 52 // Uppercase ascii alpha 53 { path: 'C:\\FOO', expected: 'file:///C:/FOO' }, 54 // dir 55 { path: 'C:\\dir\\foo', expected: 'file:///C:/dir/foo' }, 56 // trailing separator 57 { path: 'C:\\dir\\', expected: 'file:///C:/dir/' }, 58 // dot 59 { path: 'C:\\foo.mjs', expected: 'file:///C:/foo.mjs' }, 60 // space 61 { path: 'C:\\foo bar', expected: 'file:///C:/foo%20bar' }, 62 // question mark 63 { path: 'C:\\foo?bar', expected: 'file:///C:/foo%3Fbar' }, 64 // number sign 65 { path: 'C:\\foo#bar', expected: 'file:///C:/foo%23bar' }, 66 // ampersand 67 { path: 'C:\\foo&bar', expected: 'file:///C:/foo&bar' }, 68 // equals 69 { path: 'C:\\foo=bar', expected: 'file:///C:/foo=bar' }, 70 // colon 71 { path: 'C:\\foo:bar', expected: 'file:///C:/foo:bar' }, 72 // semicolon 73 { path: 'C:\\foo;bar', expected: 'file:///C:/foo;bar' }, 74 // percent 75 { path: 'C:\\foo%bar', expected: 'file:///C:/foo%25bar' }, 76 // backslash 77 { path: 'C:\\foo\\bar', expected: 'file:///C:/foo/bar' }, 78 // backspace 79 { path: 'C:\\foo\bbar', expected: 'file:///C:/foo%08bar' }, 80 // tab 81 { path: 'C:\\foo\tbar', expected: 'file:///C:/foo%09bar' }, 82 // newline 83 { path: 'C:\\foo\nbar', expected: 'file:///C:/foo%0Abar' }, 84 // carriage return 85 { path: 'C:\\foo\rbar', expected: 'file:///C:/foo%0Dbar' }, 86 // latin1 87 { path: 'C:\\fóóbàr', expected: 'file:///C:/f%C3%B3%C3%B3b%C3%A0r' }, 88 // Euro sign (BMP code point) 89 { path: 'C:\\€', expected: 'file:///C:/%E2%82%AC' }, 90 // Rocket emoji (non-BMP code point) 91 { path: 'C:\\', expected: 'file:///C:/%F0%9F%9A%80' }, 92 // UNC path (see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows) 93 { path: '\\\\nas\\My Docs\\File.doc', expected: 'file://nas/My%20Docs/File.doc' } 94 ]; 95 } else { 96 testCases = [ 97 // Lowercase ascii alpha 98 { path: '/foo', expected: 'file:///foo' }, 99 // Uppercase ascii alpha 100 { path: '/FOO', expected: 'file:///FOO' }, 101 // dir 102 { path: '/dir/foo', expected: 'file:///dir/foo' }, 103 // trailing separator 104 { path: '/dir/', expected: 'file:///dir/' }, 105 // dot 106 { path: '/foo.mjs', expected: 'file:///foo.mjs' }, 107 // space 108 { path: '/foo bar', expected: 'file:///foo%20bar' }, 109 // question mark 110 { path: '/foo?bar', expected: 'file:///foo%3Fbar' }, 111 // number sign 112 { path: '/foo#bar', expected: 'file:///foo%23bar' }, 113 // ampersand 114 { path: '/foo&bar', expected: 'file:///foo&bar' }, 115 // equals 116 { path: '/foo=bar', expected: 'file:///foo=bar' }, 117 // colon 118 { path: '/foo:bar', expected: 'file:///foo:bar' }, 119 // semicolon 120 { path: '/foo;bar', expected: 'file:///foo;bar' }, 121 // percent 122 { path: '/foo%bar', expected: 'file:///foo%25bar' }, 123 // backslash 124 { path: '/foo\\bar', expected: 'file:///foo%5Cbar' }, 125 // backspace 126 { path: '/foo\bbar', expected: 'file:///foo%08bar' }, 127 // tab 128 { path: '/foo\tbar', expected: 'file:///foo%09bar' }, 129 // newline 130 { path: '/foo\nbar', expected: 'file:///foo%0Abar' }, 131 // carriage return 132 { path: '/foo\rbar', expected: 'file:///foo%0Dbar' }, 133 // latin1 134 { path: '/fóóbàr', expected: 'file:///f%C3%B3%C3%B3b%C3%A0r' }, 135 // Euro sign (BMP code point) 136 { path: '/€', expected: 'file:///%E2%82%AC' }, 137 // Rocket emoji (non-BMP code point) 138 { path: '/', expected: 'file:///%F0%9F%9A%80' }, 139 ]; 140 } 141 142 for (const { path, expected } of testCases) { 143 const actual = url.pathToFileURL(path).href; 144 assert.strictEqual(actual, expected); 145 } 146} 147