|
1 | 1 | import '@exodus/bytes/encoding.js' |
2 | 2 | import { percentEncodeAfterEncoding } from '@exodus/bytes/whatwg.js' |
3 | | -import { test } from 'node:test' |
| 3 | +import { describe, test } from 'node:test' |
| 4 | +import { labels } from './encoding/fixtures/encodings.cjs' |
4 | 5 |
|
5 | | -// https://url.spec.whatwg.org/#example-percent-encode-operations |
6 | | -test('percent-encode after encoding', (t) => { |
7 | | - const userinfo = ' "#/:;<=>?@[\\]^`{|}' // https://url.spec.whatwg.org/#userinfo-percent-encode-set |
| 6 | +const userinfo = ' "#/:;<=>?@[\\]^`{|}' // https://url.spec.whatwg.org/#userinfo-percent-encode-set |
| 7 | +const jsuri = ' "%<>[\\]^`{|}' // https://tc39.es/ecma262/#sec-encodeuri-uri |
| 8 | +const jsuricomponent = ' "#$%&+,/:;<=>?@[\\]^`{|}' // https://tc39.es/ecma262/#sec-encodeuricomponent-uricomponent |
| 9 | + |
| 10 | +const sets = ['', userinfo, jsuri, jsuricomponent] |
| 11 | +const invalid = ['replacement', 'utf-16le', 'utf-16be'] // https://encoding.spec.whatwg.org/#get-an-encoder |
| 12 | + |
| 13 | +const slowEngine = |
| 14 | + process.env.EXODUS_TEST_PLATFORM === 'quickjs' || |
| 15 | + process.env.EXODUS_TEST_PLATFORM === 'xs' || |
| 16 | + process.env.EXODUS_TEST_PLATFORM === 'engine262' |
| 17 | + |
| 18 | +describe('percent-encode after encoding', () => { |
8 | 19 | const f = percentEncodeAfterEncoding |
9 | | - t.assert.strictEqual(f('Shift_JIS', ' ', userinfo), '%20') |
10 | | - t.assert.strictEqual(f('Shift_JIS', '≡', userinfo), '%81%DF') |
11 | | - t.assert.strictEqual(f('Shift_JIS', '‽', userinfo), '%26%238253%3B') |
12 | | - // t.assert.strictEqual(f('ISO-2022-JP', '¥', userinfo), "%1B(J\\%1B(B") // https://github.com/whatwg/url/issues/895 |
13 | | - t.assert.strictEqual( |
14 | | - f('Shift_JIS', '1+1 ≡ 2%20‽', userinfo, true), |
15 | | - '1+1+%81%DF+2%20%26%238253%3B' |
16 | | - ) |
17 | | - t.assert.strictEqual(f('UTF-8', '≡', userinfo), '%E2%89%A1') |
18 | | - t.assert.strictEqual(f('UTF-8', '‽', userinfo), '%E2%80%BD') |
19 | | - t.assert.strictEqual(f('UTF-8', 'Say what‽', userinfo), 'Say%20what%E2%80%BD') |
| 20 | + |
| 21 | + // https://url.spec.whatwg.org/#example-percent-encode-operations |
| 22 | + test('examples from spec', (t) => { |
| 23 | + t.assert.strictEqual(f('Shift_JIS', ' ', userinfo), '%20') |
| 24 | + t.assert.strictEqual(f('Shift_JIS', '≡', userinfo), '%81%DF') |
| 25 | + t.assert.strictEqual(f('Shift_JIS', '‽', userinfo), '%26%238253%3B') |
| 26 | + // t.assert.strictEqual(f('ISO-2022-JP', '¥', userinfo), "%1B(J\\%1B(B") // https://github.com/whatwg/url/issues/895 |
| 27 | + t.assert.strictEqual( |
| 28 | + f('Shift_JIS', '1+1 ≡ 2%20‽', userinfo, true), |
| 29 | + '1+1+%81%DF+2%20%26%238253%3B' |
| 30 | + ) |
| 31 | + t.assert.strictEqual(f('UTF-8', '≡', userinfo), '%E2%89%A1') |
| 32 | + t.assert.strictEqual(f('UTF-8', '‽', userinfo), '%E2%80%BD') |
| 33 | + t.assert.strictEqual(f('UTF-8', 'Say what‽', userinfo), 'Say%20what%E2%80%BD') |
| 34 | + }) |
| 35 | + |
| 36 | + // https://encoding.spec.whatwg.org/#get-an-encoder |
| 37 | + describe('throws on unkown, utf-16 and replacement', () => { |
| 38 | + for (const encoding of [...invalid, 'what', 'UTF-16', 'unicode']) { |
| 39 | + test(encoding, (t) => { |
| 40 | + for (const set of sets) { |
| 41 | + t.assert.throws(() => f(encoding, '', set), /encoding/) |
| 42 | + t.assert.throws(() => f(encoding, ' ', set), /encoding/) |
| 43 | + t.assert.throws(() => f(encoding, ' ', set, true), /encoding/) |
| 44 | + t.assert.throws(() => f(encoding, '\uFFFD', set, true), /encoding/) |
| 45 | + } |
| 46 | + }) |
| 47 | + } |
| 48 | + }) |
| 49 | + |
| 50 | + describe('all valid encodings are recognized', () => { |
| 51 | + for (const encoding of labels) { |
| 52 | + if (encoding.includes(encoding)) continue |
| 53 | + test(encoding, (t) => { |
| 54 | + for (const set of sets) { |
| 55 | + t.assert.strictEqual(f(encoding, '', set), '') |
| 56 | + // Even non-ASCII encodings passthrough on a lone space |
| 57 | + t.assert.strictEqual(f(encoding, ' ', set), set.includes(' ') ? '%20' : ' ') |
| 58 | + t.assert.strictEqual(f(encoding, ' ', set, true), '+') |
| 59 | + } |
| 60 | + }) |
| 61 | + } |
| 62 | + }) |
| 63 | + |
| 64 | + describe('throws on non-scalarvalue', () => { |
| 65 | + for (const encoding of labels) { |
| 66 | + test(encoding, (t) => { |
| 67 | + for (let cp = 0xd8_00; cp < 0xe0_00; cp++) { |
| 68 | + const s = String.fromCodePoint(cp) |
| 69 | + t.assert.throws(() => f(encoding, s, userinfo)) |
| 70 | + t.assert.throws(() => f(encoding, s, jsuri)) |
| 71 | + } |
| 72 | + }) |
| 73 | + } |
| 74 | + }) |
| 75 | + |
| 76 | + test('encodeURI / encodeURIComponent', (t) => { |
| 77 | + // https://tc39.es/ecma262/#sec-encodeuri-uri step 2, coherence check |
| 78 | + t.assert.deepStrictEqual([...(jsuri + ';/?:@&=+$,#')].sort(), [...jsuricomponent].sort()) |
| 79 | + |
| 80 | + const MAX = slowEngine ? 0x1_ff_ff : 0x10_ff_ff // Max Unicode codepoint |
| 81 | + for (let cp = 0; cp <= MAX; cp++) { |
| 82 | + if (cp >= 0xd8_00 && cp < 0xe0_00) continue |
| 83 | + const s = String.fromCodePoint(cp) |
| 84 | + t.assert.strictEqual(f('utf8', s, jsuricomponent), encodeURIComponent(s)) |
| 85 | + t.assert.strictEqual(f('utf8', s, jsuri), encodeURI(s)) |
| 86 | + } |
| 87 | + }) |
20 | 88 | }) |
0 commit comments