From 14a6bb92e12682aff387cf49e427e0dcf493c2cf Mon Sep 17 00:00:00 2001 From: Ryc O'Chet Date: Sun, 14 Jan 2024 21:54:56 +0000 Subject: [PATCH] Cleanup tests part 1 --- src/UTF16/UTF16.test.ts | 11 ++ src/UTF16/compressToUTF16.ts | 2 +- src/UTF16/decompressFromUTF16.ts | 2 +- src/Uint8Array/Uint8Array.test.ts | 38 +++++ src/Uint8Array/compressToUint8Array.ts | 2 +- src/Uint8Array/decompressFromUint8Array.ts | 2 +- src/__tests__/testFunctions.ts | 164 +++++++++++++++++++++ src/base64/base64.test.ts | 11 ++ src/base64/compressToBase64.ts | 13 +- src/base64/decompressFromBase64.ts | 2 +- src/encodedURI/compressToEncodedURI.ts | 6 +- src/encodedURI/decompressFromEncodedURI.ts | 4 +- src/encodedURI/encodedURI.test.ts | 28 ++++ src/stock/compress.ts | 6 +- src/stock/decompress.ts | 2 +- src/stock/stock.test.ts | 7 + tests/src.main.test.ts | 7 - tests/testFunctions.ts | 4 +- tsconfig.json | 21 +-- 19 files changed, 289 insertions(+), 43 deletions(-) create mode 100644 src/UTF16/UTF16.test.ts create mode 100644 src/Uint8Array/Uint8Array.test.ts create mode 100644 src/__tests__/testFunctions.ts create mode 100644 src/base64/base64.test.ts create mode 100644 src/encodedURI/encodedURI.test.ts create mode 100644 src/stock/stock.test.ts delete mode 100644 tests/src.main.test.ts diff --git a/src/UTF16/UTF16.test.ts b/src/UTF16/UTF16.test.ts new file mode 100644 index 0000000..f97354a --- /dev/null +++ b/src/UTF16/UTF16.test.ts @@ -0,0 +1,11 @@ +import { describe } from "vitest"; +import { compressToUTF16, decompressFromUTF16 } from "."; +import { runTestSet } from "../__tests__/testFunctions"; + +describe("UTF16", () => { + /** Known output for UTF16 compression */ + const test_tattooUTF16 = + "\u0462\u5C33\u414C\u0780\u7320\u1025\u6063\u0230\u3DBB\u51A0\u3496\u40F6\u3C26\u3A05K\u00C6\u01AC\u0870\u04F4\u7AA8\u00D0\u5731\u7DC5\u6D24\u0441\u25AE\u0934\u1E20\u5B71\u1070\u6CE0\u2930\u0093\u22A4\u2177\u1863\u152AV\u4D44\u54B3\u37F3\u4024\u2534\u456C\u0D3C\u7344\u18D2\u4702\u45C0\u0393\u36A4\u60B5\u486C\u5241\u282C\u4648\u2890\u1059\u3DA7\u55EA\u0FA0\u03C3\u4020\u555D\u2706\u4B8B\u2DCE\u492C\u0620\u0517\u31C2\u44F8\u6820\u3336\u0481\u1DF3\u6024\u3363\u5284\u01E8\u24BA\u4CF1\u15BC\u0A2A\u5B4B\u4749@\u7312\u2C61\u74D6\u0164\u00E1\u402E\u7606\u32B2\u08A9\u48F9\u394E\u6E25\u147C\u5F67\u2456\u4337\u5958\u5051\u78B4\u1D7C\u149A\u6DFA\u37E5\u4A8F\u1170\u1890\u2728\u1124\u1CD3\u26E9\u137B\u028C\u39C0\u31E0\u7D86\u1A28\u1F0D\u4022\u5440\u1738\u0F90\u218A\u1220\u0844\u7970\u7020\u0C7F\u2359\u20F6\u28B8\u43A1\u564E\u26B2\u6430\u7D08\u1CA2\u03F2\u3490\u39B0\u1364\u3C61\u28ED\u0323\u7044\u397B\u1661\u40D6\u1F36\u04FA\u1236\u15A6\u6758\u29FD\u35A5\u63A0\u64C6\u3430\u622B\u430C\u2F3F\u1249\u45B7\u3A2D\u01A8\u0092\u0A48\u6103\u1859\u14D9\u6907\u7256\u2635\u08C2\u1060\u5EB8\u5741\u498E\u3FB1\u00F3\u4029\u183E\u2520\u2020\u5A41\u4482\u5545\u1CF4\u57E0\u63A4\u2271\u0223\u01A0\u2856\u0CC6\u6054\u4D69\u55C6\u5931\u0B37\u16F2\u0408\u1704\u1B8F\u02E7\u1B8A\u4DAE\u1899\u4571\u0644\u3021\u6ACC\u08B7\u2A8B\u52A2\u2F31\u0361\u60BA\u1239\u2321\u6E05\u2590\u61B7\u2EA2\u73BF\u2700\u4467\u2152\u34E9\u7F0C\u0520\u18CB\u406A\u2E2C\u2A41\u7439\u1628\u38CA\u3497\u2D2C\u0D8C\u5897\u094E\u5DE2\u4634\u0D7F\u4F2C\u7D72\u0327\u63C1\u4040\u3C27\u48E5\u50D2\u1426\u570B\u3CFA\u366F\u4B80\u2474\u24F0\u5049\u6DAC\u734E\u00C0\u0A25\u3521\u06E3\u6CBE\u1129\u00A1\u684C\u6DBA\u5739\u02F1\u508E\u4D18\u2836\u28B9\u208C\u4872\u3676\u4622\u4C82\u2213\u734D\u03C2\u7042\u0679\u3B30\u0892\u1453\u63F9\u583F\u0DAB\u3A98\u1D20\u0A2A\u6E40\u0465\u0330i\u08A0\u28EC\u1807\u018B\u32A0\u6134\u26EC\u34F0\u06A4\u2068\u2202\u5C8A\u2834\u6283\u260C\u0A0E\u2C2C\u5CF8\u1D2F\u4240\u7320\u21AA\u283E\u19D4\u0B34\u2380\u6921\u22B0\u1537\u6058\u7F6C\u52F4\u1E2D\u68C9\u0829\u51D7\u0D22\u124D\u0AEB\u7118\u1DCE\u2348\u69AE\u40D2\u1464\u0020\u0020"; + + runTestSet(compressToUTF16, decompressFromUTF16, test_tattooUTF16); +}); diff --git a/src/UTF16/compressToUTF16.ts b/src/UTF16/compressToUTF16.ts index 5d7ac23..8e56c86 100644 --- a/src/UTF16/compressToUTF16.ts +++ b/src/UTF16/compressToUTF16.ts @@ -1,6 +1,6 @@ import { _compress } from "../_compress"; -export function compressToUTF16(input: string): string { +export function compressToUTF16(input: string | null) { if (input == null) return ""; return _compress(input, 15, (a) => String.fromCharCode(a + 32)) + " "; diff --git a/src/UTF16/decompressFromUTF16.ts b/src/UTF16/decompressFromUTF16.ts index d0c421c..9297b84 100644 --- a/src/UTF16/decompressFromUTF16.ts +++ b/src/UTF16/decompressFromUTF16.ts @@ -1,6 +1,6 @@ import { _decompress } from "../_decompress"; -export function decompressFromUTF16(compressed: string): string | null { +export function decompressFromUTF16(compressed: string | null) { if (compressed == null) return ""; if (compressed == "") return null; diff --git a/src/Uint8Array/Uint8Array.test.ts b/src/Uint8Array/Uint8Array.test.ts new file mode 100644 index 0000000..990565b --- /dev/null +++ b/src/Uint8Array/Uint8Array.test.ts @@ -0,0 +1,38 @@ +import { describe } from "vitest"; +import { compressToUint8Array, decompressFromUint8Array } from "."; +import { runTestSet } from "../__tests__/testFunctions"; + +describe("Uint8Array", () => { + /** Known output for Uint8 compression */ + const test_tattooUint8Array = new Uint8Array([ + 8, 133, 112, 78, 9, 96, 118, 14, 96, 4, 1, 112, 33, 130, 16, 123, 55, 70, 1, 163, 180, 13, 103, 128, 206, 121, + 64, 21, 128, 166, 3, 24, 33, 64, 38, 167, 168, 128, 22, 21, 196, 126, 210, 237, 4, 8, 66, 150, 56, 72, 161, 224, + 11, 106, 36, 20, 54, 96, 41, 16, 0, 230, 138, 17, 10, 185, 132, 50, 161, 64, 13, 166, 146, 84, 147, 111, 167, 0, + 17, 40, 164, 84, 193, 163, 156, 201, 12, 89, 70, 226, 139, 64, 13, 205, 180, 38, 9, 89, 9, 148, 136, 84, 6, 70, + 40, 80, 224, 64, 229, 236, 61, 92, 161, 240, 0, 232, 224, 0, 85, 61, 77, 205, 45, 173, 109, 116, 144, 192, 192, + 1, 61, 216, 209, 68, 216, 208, 0, 204, 88, 35, 9, 221, 60, 0, 140, 208, 233, 50, 1, 200, 73, 53, 51, 68, 172, + 224, 160, 171, 101, 113, 202, 64, 16, 114, 242, 88, 131, 210, 216, 10, 32, 12, 24, 1, 221, 121, 153, 73, 8, 137, + 145, 178, 228, 187, 112, 41, 69, 203, 232, 233, 13, 161, 139, 217, 56, 160, 99, 226, 80, 234, 225, 71, 173, 187, + 77, 241, 101, 55, 145, 80, 48, 224, 156, 32, 136, 33, 203, 52, 217, 36, 214, 193, 54, 57, 160, 99, 129, 245, + 152, 208, 65, 238, 216, 0, 85, 8, 11, 140, 15, 112, 66, 212, 72, 0, 65, 39, 149, 14, 0, 3, 23, 209, 156, 160, + 214, 81, 49, 14, 6, 177, 114, 105, 44, 130, 31, 58, 14, 65, 3, 210, 104, 224, 230, 64, 154, 35, 196, 21, 25, + 160, 192, 248, 18, 57, 91, 44, 131, 2, 216, 248, 176, 77, 162, 66, 197, 97, 179, 156, 41, 221, 107, 11, 142, 3, + 37, 51, 65, 12, 65, 112, 187, 23, 143, 146, 41, 139, 46, 232, 52, 12, 64, 7, 33, 69, 24, 56, 204, 28, 148, 185, + 209, 207, 200, 217, 48, 168, 138, 34, 8, 23, 166, 43, 144, 201, 110, 127, 34, 3, 78, 0, 73, 129, 228, 160, 8, 0, + 45, 16, 196, 98, 170, 74, 115, 82, 190, 6, 56, 68, 74, 32, 128, 192, 192, 40, 54, 25, 77, 128, 210, 106, 77, 90, + 107, 34, 34, 197, 203, 105, 3, 232, 45, 200, 109, 188, 22, 57, 182, 169, 177, 198, 30, 98, 168, 134, 36, 96, 3, + 170, 176, 68, 186, 166, 186, 80, 75, 196, 65, 160, 224, 154, 36, 50, 140, 7, 111, 42, 87, 12, 50, 235, 160, 185, + 207, 166, 224, 136, 142, 132, 201, 166, 79, 238, 192, 160, 6, 42, 224, 37, 46, 12, 84, 67, 208, 100, 176, 67, + 138, 166, 142, 235, 67, 6, 182, 88, 119, 18, 93, 119, 10, 48, 160, 213, 249, 225, 159, 84, 129, 131, 227, 161, + 128, 64, 240, 30, 70, 45, 11, 34, 128, 213, 186, 222, 109, 54, 79, 150, 192, 145, 81, 38, 133, 2, 157, 177, 156, + 203, 128, 80, 10, 5, 106, 2, 27, 15, 100, 241, 16, 144, 16, 58, 11, 54, 205, 87, 25, 5, 163, 65, 186, 103, 194, + 129, 101, 19, 40, 27, 36, 41, 54, 86, 140, 5, 49, 137, 15, 159, 50, 208, 116, 92, 8, 131, 44, 187, 16, 16, 228, + 80, 207, 30, 205, 129, 241, 177, 110, 158, 14, 128, 10, 10, 220, 64, 17, 20, 24, 128, 4, 145, 16, 10, 51, 11, + 243, 129, 107, 101, 1, 132, 81, 54, 99, 77, 0, 208, 136, 18, 16, 241, 92, 106, 80, 41, 137, 141, 47, 96, 158, + 229, 129, 151, 54, 14, 135, 194, 32, 230, 0, 134, 41, 64, 241, 155, 65, 98, 136, 216, 52, 128, 162, 144, 42, 47, + 128, 227, 250, 101, 45, 67, 193, 186, 42, 68, 4, 209, 183, 26, 4, 72, 180, 86, 95, 15, 131, 181, 200, 202, 52, + 199, 64, 178, 40, 136, 0, 0, + ]); + + runTestSet(compressToUint8Array, decompressFromUint8Array, test_tattooUint8Array); +}); diff --git a/src/Uint8Array/compressToUint8Array.ts b/src/Uint8Array/compressToUint8Array.ts index 4ec023d..7db37fb 100644 --- a/src/Uint8Array/compressToUint8Array.ts +++ b/src/Uint8Array/compressToUint8Array.ts @@ -1,6 +1,6 @@ import { compress } from "../stock/compress"; -export function compressToUint8Array(uncompressed: string): Uint8Array { +export function compressToUint8Array(uncompressed: string | null): Uint8Array { const compressed: string = compress(uncompressed); const buf: Uint8Array = new Uint8Array(compressed.length * 2); // 2 bytes per character diff --git a/src/Uint8Array/decompressFromUint8Array.ts b/src/Uint8Array/decompressFromUint8Array.ts index 20459ca..e61ee78 100644 --- a/src/Uint8Array/decompressFromUint8Array.ts +++ b/src/Uint8Array/decompressFromUint8Array.ts @@ -1,6 +1,6 @@ import { decompress } from "../stock/decompress"; -export function decompressFromUint8Array(compressed: Uint8Array): string | null { +export function decompressFromUint8Array(compressed: Uint8Array | null): string | null { if (compressed === null || compressed === undefined) { return decompress(compressed); } else { diff --git a/src/__tests__/testFunctions.ts b/src/__tests__/testFunctions.ts new file mode 100644 index 0000000..1d3c203 --- /dev/null +++ b/src/__tests__/testFunctions.ts @@ -0,0 +1,164 @@ +/* eslint-disable @typescript-eslint/ban-ts-comment */ +import { test, expect } from "vitest"; + +/** A known long text source, eaxh set of tests must have a compressed version to compare to */ +export const test_tattooSource = + "During tattooing, ink is injected into the skin, initiating an immune response, and cells called \"macrophages\" move into the area and \"eat up\" the ink. The macrophages carry some of the ink to the body's lymph nodes, but some that are filled with ink stay put, embedded in the skin. That's what makes the tattoo visible under the skin. Dalhousie Uiversity's Alec Falkenham is developing a topical cream that works by targeting the macrophages that have remained at the site of the tattoo. New macrophages move in to consume the previously pigment-filled macrophages and then migrate to the lymph nodes, eventually taking all the dye with them. \"When comparing it to laser-based tattoo removal, in which you see the burns, the scarring, the blisters, in this case, we've designed a drug that doesn't really have much off-target effect,\" he said. \"We're not targeting any of the normal skin cells, so you won't see a lot of inflammation. In fact, based on the process that we're actually using, we don't think there will be any inflammation at all and it would actually be anti-inflammatory."; + +/** All printable ascii characters */ +export const test_allAscii = (() => { + const testValue: string[] = []; + + for (let i = 32; i < 127; i++) { + testValue.push(String.fromCharCode(i)); + } + + return testValue.join(""); +})(); + +/** All printable unicode characters */ +export const test_allUtf16 = (() => { + const testValue = [test_allAscii]; + + for (let i = 160; i < 55296; i++) { + testValue.push(String.fromCharCode(i)); + } + for (let i = 63744; i < 65536; i++) { + testValue.push(String.fromCharCode(i)); + } + + return testValue.join(""); +})(); + +/** Random (rarely compressable) string, important to be different for every test */ +export const test_randomString_fn = () => { + const testValue: string[] = []; + const randomAscii = test_allAscii.split(""); + + while (testValue.length < 1000) { + // eslint-disable-next-line prefer-spread + testValue.push.apply(testValue, randomAscii); + } + testValue.sort(() => Math.random() - 0.5); + + return testValue.join(""); +}; + +/** Over 10k random numbers, important to be different for every test */ +export const test_longString_fn = () => { + const testValue: string[] = []; + + while (testValue.length < 10000) { + testValue.push(String(Math.random())); + } + + return testValue.join(" "); +}; + + +/** + * This will run a series of tests against each compress / decompress pair. + * + * All tests must (where possible): + * - Check that it doesn't output null unless expected + * - Check that the compression is deterministic + * - Check that it changes the input string + * - Check that it can decompress again + * - Compression makes thing smaller + * - Check against a known good value + */ +export function runTestSet( + compressFunc: (input: string | null) => T | null, + decompressFunc: (input: T | null) => string | null, + compressedTattoo?: T, +) { + test(`"Hello World"`, () => { + const test_hw = "Hello world!"; + const compressedHw = compressFunc(test_hw); + + expect(compressedHw).toEqual(compressFunc(test_hw)); + expect(compressedHw).not.toEqual(test_hw); + expect(decompressFunc(compressedHw)).toEqual(test_hw); + }); + + test(`null`, () => { + const test_null = null; + const compressedNull = compressFunc(test_null); + + compressedNull instanceof Uint8Array + ? expect(compressedNull.length).toBe(0) + : expect(compressedNull).toEqual(""); + }); + + test(`"" (empty string)`, () => { + const test_empty = ""; + const compressedEmpty = compressFunc(test_empty); + + expect(compressedEmpty).toEqual(compressFunc(test_empty)); + expect(compressedEmpty).not.toEqual(""); + compressedEmpty instanceof Uint8Array + ? expect(compressedEmpty.length).not.toBe(0) + : expect(typeof compressedEmpty).toBe("string"); + expect(decompressFunc(compressedEmpty)).toEqual(test_empty); + }); + + test(`undefined`, () => { + const test_undefined = undefined; + // @ts-expect-error + const compressedUndefined = compressFunc(test_undefined); + + compressedUndefined instanceof Uint8Array + ? expect(compressedUndefined.length).toBe(0) + : expect(compressedUndefined).toBe(""); + }); + + test(`utf16`, () => { + const compressedUtf16 = compressFunc(test_allUtf16); + + expect(compressedUtf16).not.toEqual(null); + expect(compressedUtf16).toEqual(compressFunc(test_allUtf16)); + expect(compressedUtf16).not.toEqual(test_allUtf16); + expect(decompressFunc(compressedUtf16)).toEqual(test_allUtf16); + }); + + test(`Repeating String`, () => { + const test_repeat = "aaaaabaaaaacaaaaadaaaaaeaaaaa"; + const compressedRepeat = compressFunc(test_repeat)!; + + expect(compressedRepeat).not.toEqual(null); + expect(compressedRepeat).toEqual(compressFunc(test_repeat)); + expect(compressedRepeat).not.toEqual(test_repeat); + expect(compressedRepeat.length).toBeLessThan(test_repeat.length); + expect(decompressFunc(compressedRepeat)).toEqual(test_repeat); + }); + + // Note that this is designed to be uncompressible + test(`Random String`, () => { + const test_randomString = test_randomString_fn(); // Unique per test + const compressedRandomString = compressFunc(test_randomString); + + expect(compressedRandomString).toEqual(compressFunc(test_randomString)); + expect(compressedRandomString).not.toEqual(test_randomString); + expect(decompressFunc(compressedRandomString)).toEqual(test_randomString); + }); + + test(`Long String`, () => { + const test_longString = test_longString_fn(); // Unique per run + const compressedLongString = compressFunc(test_longString)!; + + expect(compressedLongString).toEqual(compressFunc(test_longString)); + expect(compressedLongString).not.toEqual(test_longString); + expect(compressedLongString.length).toBeLessThan(test_longString.length); + expect(decompressFunc(compressedLongString)).toEqual(test_longString); + }); + + if (compressedTattoo) { + test(`expected compression result`, () => { + expect(compressFunc(test_tattooSource)).toEqual(compressedTattoo); + }); + + test(`expected decompression result`, () => { + expect(decompressFunc(compressedTattoo)).toEqual(test_tattooSource); + }); + } +} diff --git a/src/base64/base64.test.ts b/src/base64/base64.test.ts new file mode 100644 index 0000000..1e9cb98 --- /dev/null +++ b/src/base64/base64.test.ts @@ -0,0 +1,11 @@ +import { describe } from "vitest"; +import { compressToBase64, decompressFromBase64 } from "."; +import { runTestSet } from "../__tests__/testFunctions"; + +describe("base64", () => { + /** Known output for Base64 compression */ + const test_tattooBase64 = + "CIVwTglgdg5gBAFwIYIQezdGAaO0DWeAznlAFYCmAxghQCanqIAWFcR+0u0ECEKWOEih4AtqJBQ2YCkQAOaKEQq5hDKhQA2mklSTb6cAESikVMGjnMkMWUbii0ANzbQmCVkJlIhUBkYoUOBA5ew9XKHwAOjgAFU9Tc0trW10kMDAAT3Y0UTY0ADMWCMJ3TwAjNDpMgHISTUzRKzgoKtlccpAEHLyWIPS2AogDBgB3XmZSQiJkbLku3ApRcvo6Q2hi9k4oGPiUOrhR627TfFlN5FQMOCcIIghyzTZJNbBNjmgY4H1mNBB7tgAVQgLjA9wQtRIAEEnlQ4AAxfRnKDWUTEOBrFyaSyCHzoOQQPSaODmQJojxBUZoMD4EjlbLIMC2PiwTaJCxWGznCndawuOAyUzQQxBcLsXj5Ipiy7oNAxAByFFGDjMHJS50c/I2TCoiiIIF6YrkMlufyIDTgBJgeSgCAAtEMRiqkpzUr4GOERKIIDAwCg2GU2A0mpNWmsiIsXLaQPoLchtvBY5tqmxxh5iqIYkYAOqsES6prpQS8RBoOCaJDKMB28qVwwy66C5z6bgiI6EyaZP7sCgBirgJS4MVEPQZLBDiqaO60MGtlh3El13CjCg1fnhn1SBg+OhgEDwHkYtCyKA1brebTZPlsCRUSaFAp2xnMuAUAoFagIbD2TxEJAQOgs2zVcZBaNBumfCgWUTKBskKTZWjAUxiQ+fMtB0XAiDLLsQEORQzx7NgfGxbp4OgAoK3EARFBiABJEQCjML84FrZQGEUTZjTQDQiBIQ8VxqUCmJjS9gnuWBlzYOh8Ig5gCGKUDxm0FiiNg0gKKQKi+A4/plLUPBuipEBNG3GgRItFZfD4O1yMo0x0CyKIgA"; + + runTestSet(compressToBase64, decompressFromBase64, test_tattooBase64); +}); diff --git a/src/base64/compressToBase64.ts b/src/base64/compressToBase64.ts index 091922f..61c4ac4 100644 --- a/src/base64/compressToBase64.ts +++ b/src/base64/compressToBase64.ts @@ -1,14 +1,15 @@ import { _compress } from "../_compress"; import keyStrBase64 from "./keyStrBase64"; -export function compressToBase64(input: string): string { - if (input == null) return ""; +export function compressToBase64(input: string | null): string { + if (input == null) { + return ""; + } - const res: string = _compress(input, 6, (a) => keyStrBase64.charAt(a)); + const res = _compress(input, 6, (a) => keyStrBase64.charAt(a)); - switch ( - res.length % 4 // To produce valid Base64 - ) { + // To produce valid Base64 + switch (res.length % 4) { default: // When could this happen ? case 0: return res; diff --git a/src/base64/decompressFromBase64.ts b/src/base64/decompressFromBase64.ts index 52f5fb7..40cc5ce 100644 --- a/src/base64/decompressFromBase64.ts +++ b/src/base64/decompressFromBase64.ts @@ -2,7 +2,7 @@ import { _decompress } from "../_decompress"; import { getBaseValue } from "../getBaseValue"; import keyStrBase64 from "./keyStrBase64"; -export function decompressFromBase64(input: string): string | null { +export function decompressFromBase64(input: string | null) { if (input == null) return ""; if (input == "") return null; diff --git a/src/encodedURI/compressToEncodedURI.ts b/src/encodedURI/compressToEncodedURI.ts index 371cb4f..5408df6 100644 --- a/src/encodedURI/compressToEncodedURI.ts +++ b/src/encodedURI/compressToEncodedURI.ts @@ -1,10 +1,8 @@ import { _compress } from "../_compress"; import keyStrUriSafe from "./keyStrUriSafe"; -export function compressToEncodedURIComponent(input: string): string { +export function compressToEncodedURIComponent(input: string | null) { if (input == null) return ""; - return _compress(input, 6, function (a) { - return keyStrUriSafe.charAt(a); - }); + return _compress(input, 6, (a) => keyStrUriSafe.charAt(a)); } diff --git a/src/encodedURI/decompressFromEncodedURI.ts b/src/encodedURI/decompressFromEncodedURI.ts index ac0ab62..3bb3e70 100644 --- a/src/encodedURI/decompressFromEncodedURI.ts +++ b/src/encodedURI/decompressFromEncodedURI.ts @@ -2,11 +2,11 @@ import keyStrUriSafe from "./keyStrUriSafe"; import { _decompress } from "../_decompress"; import { getBaseValue } from "../getBaseValue"; -export function decompressFromEncodedURIComponent(input: string): string | null { +export function decompressFromEncodedURIComponent(input: string | null) { if (input == null) return ""; if (input == "") return null; input = input.replace(/ /g, "+"); - return _decompress(input.length, 32, (index) => getBaseValue(keyStrUriSafe, input.charAt(index))); + return _decompress(input.length, 32, (index) => getBaseValue(keyStrUriSafe, input!.charAt(index))); } diff --git a/src/encodedURI/encodedURI.test.ts b/src/encodedURI/encodedURI.test.ts new file mode 100644 index 0000000..2918d89 --- /dev/null +++ b/src/encodedURI/encodedURI.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, test } from "vitest"; +import { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from "."; +import { runTestSet, test_longString_fn, test_tattooSource } from "../__tests__/testFunctions"; + +describe("encodedURI", () => { + /** Known output for URI compression */ + const test_tattooEncodedURIComponent = + "CIVwTglgdg5gBAFwIYIQezdGAaO0DWeAznlAFYCmAxghQCanqIAWFcR 0u0ECEKWOEih4AtqJBQ2YCkQAOaKEQq5hDKhQA2mklSTb6cAESikVMGjnMkMWUbii0ANzbQmCVkJlIhUBkYoUOBA5ew9XKHwAOjgAFU9Tc0trW10kMDAAT3Y0UTY0ADMWCMJ3TwAjNDpMgHISTUzRKzgoKtlccpAEHLyWIPS2AogDBgB3XmZSQiJkbLku3ApRcvo6Q2hi9k4oGPiUOrhR627TfFlN5FQMOCcIIghyzTZJNbBNjmgY4H1mNBB7tgAVQgLjA9wQtRIAEEnlQ4AAxfRnKDWUTEOBrFyaSyCHzoOQQPSaODmQJojxBUZoMD4EjlbLIMC2PiwTaJCxWGznCndawuOAyUzQQxBcLsXj5Ipiy7oNAxAByFFGDjMHJS50c-I2TCoiiIIF6YrkMlufyIDTgBJgeSgCAAtEMRiqkpzUr4GOERKIIDAwCg2GU2A0mpNWmsiIsXLaQPoLchtvBY5tqmxxh5iqIYkYAOqsES6prpQS8RBoOCaJDKMB28qVwwy66C5z6bgiI6EyaZP7sCgBirgJS4MVEPQZLBDiqaO60MGtlh3El13CjCg1fnhn1SBg OhgEDwHkYtCyKA1brebTZPlsCRUSaFAp2xnMuAUAoFagIbD2TxEJAQOgs2zVcZBaNBumfCgWUTKBskKTZWjAUxiQ fMtB0XAiDLLsQEORQzx7NgfGxbp4OgAoK3EARFBiABJEQCjML84FrZQGEUTZjTQDQiBIQ8VxqUCmJjS9gnuWBlzYOh8Ig5gCGKUDxm0FiiNg0gKKQKi A4-plLUPBuipEBNG3GgRItFZfD4O1yMo0x0CyKIgAAA$$"; + + /** Known output for URI compression with different (valid) input */ + const test_tattooEncodedURIComponentPlus = + "CIVwTglgdg5gBAFwIYIQezdGAaO0DWeAznlAFYCmAxghQCanqIAWFcR+0u0ECEKWOEih4AtqJBQ2YCkQAOaKEQq5hDKhQA2mklSTb6cAESikVMGjnMkMWUbii0ANzbQmCVkJlIhUBkYoUOBA5ew9XKHwAOjgAFU9Tc0trW10kMDAAT3Y0UTY0ADMWCMJ3TwAjNDpMgHISTUzRKzgoKtlccpAEHLyWIPS2AogDBgB3XmZSQiJkbLku3ApRcvo6Q2hi9k4oGPiUOrhR627TfFlN5FQMOCcIIghyzTZJNbBNjmgY4H1mNBB7tgAVQgLjA9wQtRIAEEnlQ4AAxfRnKDWUTEOBrFyaSyCHzoOQQPSaODmQJojxBUZoMD4EjlbLIMC2PiwTaJCxWGznCndawuOAyUzQQxBcLsXj5Ipiy7oNAxAByFFGDjMHJS50c-I2TCoiiIIF6YrkMlufyIDTgBJgeSgCAAtEMRiqkpzUr4GOERKIIDAwCg2GU2A0mpNWmsiIsXLaQPoLchtvBY5tqmxxh5iqIYkYAOqsES6prpQS8RBoOCaJDKMB28qVwwy66C5z6bgiI6EyaZP7sCgBirgJS4MVEPQZLBDiqaO60MGtlh3El13CjCg1fnhn1SBg+OhgEDwHkYtCyKA1brebTZPlsCRUSaFAp2xnMuAUAoFagIbD2TxEJAQOgs2zVcZBaNBumfCgWUTKBskKTZWjAUxiQ+fMtB0XAiDLLsQEORQzx7NgfGxbp4OgAoK3EARFBiABJEQCjML84FrZQGEUTZjTQDQiBIQ8VxqUCmJjS9gnuWBlzYOh8Ig5gCGKUDxm0FiiNg0gKKQKi+A4-plLUPBuipEBNG3GgRItFZfD4O1yMo0x0CyKIgA"; + + runTestSet(compressToEncodedURIComponent, decompressFromEncodedURIComponent, test_tattooEncodedURIComponentPlus); + + const test_longString = test_longString_fn(); // Unique per run + const compressedLongString = compressToEncodedURIComponent(test_longString)!; + + test(`All chars are URL safe`, () => { + expect(compressedLongString.indexOf("=")).toBe(-1); + expect(compressedLongString.indexOf("/")).toBe(-1); + expect(decompressFromEncodedURIComponent(compressedLongString)).toBe(test_longString); + }); + + test(`+ and ' ' are interchangeable in decompression`, () => { + expect(test_tattooSource).toEqual(decompressFromEncodedURIComponent(test_tattooEncodedURIComponent)); + }); +}); diff --git a/src/stock/compress.ts b/src/stock/compress.ts index 39cb9c9..27fa233 100644 --- a/src/stock/compress.ts +++ b/src/stock/compress.ts @@ -1,5 +1,7 @@ import { _compress } from "../_compress"; -export function compress(uncompressed: string): string { - return _compress(uncompressed, 16, (a: number) => String.fromCharCode(a)); +export function compress(input: string | null) { + if (input == null) return ""; + + return _compress(input, 16, (a: number) => String.fromCharCode(a)); } diff --git a/src/stock/decompress.ts b/src/stock/decompress.ts index e95326b..c9c116a 100644 --- a/src/stock/decompress.ts +++ b/src/stock/decompress.ts @@ -1,6 +1,6 @@ import { _decompress } from "../_decompress"; -export function decompress(compressed: string): string | null { +export function decompress(compressed: string | null) { if (compressed == null) return ""; if (compressed == "") return null; diff --git a/src/stock/stock.test.ts b/src/stock/stock.test.ts new file mode 100644 index 0000000..4d3702f --- /dev/null +++ b/src/stock/stock.test.ts @@ -0,0 +1,7 @@ +import { describe } from "vitest"; +import { compress, decompress } from "."; +import { runTestSet } from "../__tests__/testFunctions"; + +describe("base64", () => { + runTestSet(compress, decompress, ""); +}); diff --git a/tests/src.main.test.ts b/tests/src.main.test.ts deleted file mode 100644 index 54fcb4a..0000000 --- a/tests/src.main.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { describe } from "vitest"; -import LZString from "../src"; -import { runAllTests } from "./testFunctions"; - -describe("src/ (uncompiled)", () => { - runAllTests(LZString); -}); diff --git a/tests/testFunctions.ts b/tests/testFunctions.ts index eb5a36c..c7500ca 100644 --- a/tests/testFunctions.ts +++ b/tests/testFunctions.ts @@ -15,14 +15,14 @@ import { test_tattooUTF16, test_undefined, } from "./testValues"; -import type { LZString } from "../src/main"; +import LZString from "../src"; /** * Expected to be called from within a `describe`. This will pass the name and * compress / decompress pair, as well as a "known good" value for all output * methods. */ -export function runAllTests(implementation: LZString) { +export function runAllTests(implementation: typeof LZString) { runTestSet("Stock Compression and Decompression", implementation.compress, implementation.decompress); runTestSet( diff --git a/tsconfig.json b/tsconfig.json index 9fb7eb2..6f419c0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,24 +1,17 @@ { "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "lib": ["ESNext"], - "skipLibCheck": true, - - /* Bundler mode */ - "outDir": "dist", - "sourceMap": true, "declaration": true, - "declarationMap": true, + "lib": ["ESNext"], + "module": "ESNext", "moduleResolution": "Node", "noEmit": true, - - /* Linting */ - "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - - "baseUrl": "." + "outDir": "dist", + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "target": "ESNext" }, "include": ["src"] }