diff --git a/jest.config.js b/jest.config.js index 1c72a43..39533fa 100644 --- a/jest.config.js +++ b/jest.config.js @@ -129,7 +129,7 @@ module.exports = { // setupFiles: [], // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], + setupFilesAfterEnv: ['/test/setupTests.ts'], // The number of seconds after which a test is considered as slow and reported as such in the results. // slowTestThreshold: 5, diff --git a/test/jest.d.ts b/test/jest.d.ts new file mode 100644 index 0000000..56a6dca --- /dev/null +++ b/test/jest.d.ts @@ -0,0 +1,17 @@ +namespace jest { + interface Matchers { + /** + * @description + * Check whether two arrays are equal without considering the order of items. + * + * Make sure expected array has no duplicate item. + * + * Every item must be primitive type, like string, number, etc. + * + * @example + * expect(['a', 'b']).toMatchUnorderedArrary(['b', 'a']) // pass + * expect(['b', 'a']).toMatchUnorderedArrary(['c', 'b', 'a']) // not pass, missing item 'c' + */ + toMatchUnorderedArrary(expected: unknown[]): R; + } +} diff --git a/test/matchers.ts b/test/matchers.ts new file mode 100644 index 0000000..66cb5d8 --- /dev/null +++ b/test/matchers.ts @@ -0,0 +1,49 @@ +export const toMatchUnorderedArrary: jest.CustomMatcher = function ( + actual: Array, + expected: Array +) { + if (!Array.isArray(actual) || !Array.isArray(expected)) { + throw new TypeError('These must be of type array!'); + } + + const print = () => + `Expected: ${this.utils.printExpected(expected)}. \n` + + `Received: ${this.utils.printReceived(actual)}. \n`; + + const expectedMap = new Map(expected.map((item) => [item, false])); + const unexpectedItemList = []; + + for (const item of actual) { + if (!expectedMap.has(item) || expectedMap.get(item)) unexpectedItemList.push(item); + else expectedMap.set(item, true); + } + + if (unexpectedItemList.length) { + return { + pass: false, + message: () => + `Receive unexpected items: ${this.utils.printReceived(unexpectedItemList)}. \n` + + print(), + }; + } + + const missingItemList = Array.from(expectedMap) + .filter(([_, isAppeared]) => !isAppeared) + .map(([item]) => item); + + if (missingItemList.length) { + return { + pass: false, + message: () => + `Missing expected items: ${this.utils.printExpected(missingItemList)}. \n` + + print(), + }; + } + + return { + pass: true, + message() { + return 'The received array matches the expected array.'; + }, + }; +}; diff --git a/test/parser/flinksql/suggestion/tokenSuggestion.test.ts b/test/parser/flinksql/suggestion/tokenSuggestion.test.ts index c8a8642..a416dea 100644 --- a/test/parser/flinksql/suggestion/tokenSuggestion.test.ts +++ b/test/parser/flinksql/suggestion/tokenSuggestion.test.ts @@ -19,7 +19,7 @@ describe('Flink SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['MODULES', 'CATALOG']); + expect(suggestion).toMatchUnorderedArrary(['MODULES', 'CATALOG']); }); test('Create Statement ', () => { @@ -32,7 +32,7 @@ describe('Flink SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'CATALOG', 'FUNCTION', 'TEMPORARY', @@ -52,7 +52,7 @@ describe('Flink SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'MODULES', 'FULL', 'FUNCTIONS', diff --git a/test/parser/hive/suggestion/tokenSuggestion.test.ts b/test/parser/hive/suggestion/tokenSuggestion.test.ts index 33d2dbc..90f4776 100644 --- a/test/parser/hive/suggestion/tokenSuggestion.test.ts +++ b/test/parser/hive/suggestion/tokenSuggestion.test.ts @@ -18,7 +18,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'APPLICATION', 'GROUP', 'USER', @@ -45,7 +45,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'CONNECTOR', 'APPLICATION', 'GROUP', @@ -80,7 +80,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual(['FROM']); + expect(suggestion).toMatchUnorderedArrary(['FROM']); }); test('After DESCRIBE', () => { @@ -92,7 +92,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'EXTENDED', 'FORMATTED', 'FUNCTION', @@ -111,7 +111,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'CONNECTOR', 'APPLICATION', 'GROUP', @@ -141,7 +141,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual(['TABLE']); + expect(suggestion).toMatchUnorderedArrary(['TABLE']); }); test('After IMPORT', () => { @@ -153,7 +153,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual(['FROM', 'TABLE', 'EXTERNAL']); + expect(suggestion).toMatchUnorderedArrary(['FROM', 'TABLE', 'EXTERNAL']); }); test('After INSERT', () => { @@ -165,7 +165,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual(['INTO', 'OVERWRITE']); + expect(suggestion).toMatchUnorderedArrary(['INTO', 'OVERWRITE']); }); test('After LOAD', () => { @@ -177,7 +177,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual(['DATA']); + expect(suggestion).toMatchUnorderedArrary(['DATA']); }); test('After SHOW', () => { @@ -189,7 +189,7 @@ describe('Hive SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'CURRENT', 'ROLES', 'PRINCIPALS', diff --git a/test/parser/impala/suggestion/tokenSuggestion.test.ts b/test/parser/impala/suggestion/tokenSuggestion.test.ts index 27be51b..f29c7b6 100644 --- a/test/parser/impala/suggestion/tokenSuggestion.test.ts +++ b/test/parser/impala/suggestion/tokenSuggestion.test.ts @@ -19,7 +19,7 @@ describe('Impala SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['TABLE', 'VIEW', 'DATABASE']); + expect(suggestion).toMatchUnorderedArrary(['TABLE', 'VIEW', 'DATABASE']); }); test('After CREATE', () => { @@ -32,7 +32,7 @@ describe('Impala SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'TABLE', 'EXTERNAL', 'VIEW', @@ -54,7 +54,7 @@ describe('Impala SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'DATABASE', 'SCHEMA', 'TABLE', @@ -77,7 +77,7 @@ describe('Impala SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['INTO', 'OVERWRITE']); + expect(suggestion).toMatchUnorderedArrary(['INTO', 'OVERWRITE']); }); test('After SHOW', () => { @@ -90,7 +90,7 @@ describe('Impala SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'DATABASES', 'SCHEMAS', 'TABLES', diff --git a/test/parser/mysql/suggestion/tokenSuggestion.test.ts b/test/parser/mysql/suggestion/tokenSuggestion.test.ts index 7b576e5..e70462d 100644 --- a/test/parser/mysql/suggestion/tokenSuggestion.test.ts +++ b/test/parser/mysql/suggestion/tokenSuggestion.test.ts @@ -19,7 +19,7 @@ describe('MySQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'RESOURCE', 'USER', 'VIEW', @@ -50,7 +50,7 @@ describe('MySQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'RESOURCE', 'USER', 'ROLE', @@ -91,7 +91,7 @@ describe('MySQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['FROM', 'IGNORE', 'QUICK', 'LOW_PRIORITY']); + expect(suggestion).toMatchUnorderedArrary(['FROM', 'IGNORE', 'QUICK', 'LOW_PRIORITY']); }); test('After DESCRIBE', () => { @@ -104,7 +104,7 @@ describe('MySQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'ANALYZE', 'SELECT', 'DELETE', @@ -128,7 +128,7 @@ describe('MySQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'RESOURCE', 'USER', 'PREPARE', @@ -161,7 +161,13 @@ describe('MySQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['INTO', 'IGNORE', 'DELAYED', 'HIGH_PRIORITY', 'LOW_PRIORITY']); + expect(suggestion).toMatchUnorderedArrary([ + 'INTO', + 'IGNORE', + 'DELAYED', + 'HIGH_PRIORITY', + 'LOW_PRIORITY', + ]); }); test('After LOAD', () => { @@ -174,7 +180,7 @@ describe('MySQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['INDEX', 'XML', 'DATA']); + expect(suggestion).toMatchUnorderedArrary(['INDEX', 'XML', 'DATA']); }); test('After SHOW', () => { @@ -187,7 +193,7 @@ describe('MySQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'REPLICAS', 'REPLICA', 'SLAVE', diff --git a/test/parser/pgsql/suggestion/tokenSuggestion.test.ts b/test/parser/pgsql/suggestion/tokenSuggestion.test.ts index c319de9..e9ad069 100644 --- a/test/parser/pgsql/suggestion/tokenSuggestion.test.ts +++ b/test/parser/pgsql/suggestion/tokenSuggestion.test.ts @@ -17,7 +17,7 @@ describe('Postgres SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'TYPE', 'TEXT', 'STATISTICS', @@ -66,7 +66,7 @@ describe('Postgres SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'RECURSIVE', 'VIEW', 'TEMPORARY', @@ -126,7 +126,7 @@ describe('Postgres SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual(['FROM']); + expect(suggestion).toMatchUnorderedArrary(['FROM']); }); test('After DROP', () => { @@ -138,7 +138,7 @@ describe('Postgres SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'OPERATOR', 'ROUTINE', 'PROCEDURE', @@ -188,6 +188,6 @@ describe('Postgres SQL Token Suggestion', () => { commentOtherLine(tokenSql, pos.lineNumber), pos )?.keywords; - expect(suggestion).toEqual(['INTO']); + expect(suggestion).toMatchUnorderedArrary(['INTO']); }); }); diff --git a/test/parser/spark/suggestion/tokenSuggestion.test.ts b/test/parser/spark/suggestion/tokenSuggestion.test.ts index 01eb23c..c1d36d4 100644 --- a/test/parser/spark/suggestion/tokenSuggestion.test.ts +++ b/test/parser/spark/suggestion/tokenSuggestion.test.ts @@ -19,7 +19,7 @@ describe('Spark SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'TABLE', 'INDEX', 'VIEW', @@ -40,7 +40,7 @@ describe('Spark SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'TEMPORARY', 'INDEX', 'ROLE', @@ -67,7 +67,7 @@ describe('Spark SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['FROM']); + expect(suggestion).toMatchUnorderedArrary(['FROM']); }); test('After DESCRIBE', () => { @@ -80,7 +80,7 @@ describe('Spark SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'WITH', 'SELECT', 'MAP', @@ -106,7 +106,7 @@ describe('Spark SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'TEMPORARY', 'INDEX', 'ROLE', @@ -130,7 +130,7 @@ describe('Spark SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['OVERWRITE', 'INTO']); + expect(suggestion).toMatchUnorderedArrary(['OVERWRITE', 'INTO']); }); test('After LOAD', () => { @@ -143,7 +143,7 @@ describe('Spark SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['DATA']); + expect(suggestion).toMatchUnorderedArrary(['DATA']); }); test('After SHOW', () => { @@ -156,7 +156,7 @@ describe('Spark SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual([ + expect(suggestion).toMatchUnorderedArrary([ 'LOCKS', 'INDEXES', 'TRANSACTIONS', @@ -195,6 +195,6 @@ describe('Spark SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['TABLE']); + expect(suggestion).toMatchUnorderedArrary(['TABLE']); }); }); diff --git a/test/parser/trinosql/suggestion/tokenSuggestion.test.ts b/test/parser/trinosql/suggestion/tokenSuggestion.test.ts index abff7bf..41f5780 100644 --- a/test/parser/trinosql/suggestion/tokenSuggestion.test.ts +++ b/test/parser/trinosql/suggestion/tokenSuggestion.test.ts @@ -19,7 +19,7 @@ describe('Trino SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['VIEW', 'MATERIALIZED', 'TABLE', 'SCHEMA']); + expect(suggestion).toMatchUnorderedArrary(['VIEW', 'MATERIALIZED', 'TABLE', 'SCHEMA']); }); test('After CREATE', () => { @@ -32,7 +32,14 @@ describe('Trino SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['ROLE', 'VIEW', 'OR', 'MATERIALIZED', 'TABLE', 'SCHEMA']); + expect(suggestion).toMatchUnorderedArrary([ + 'ROLE', + 'VIEW', + 'OR', + 'MATERIALIZED', + 'TABLE', + 'SCHEMA', + ]); }); test('After DEALLOCATE', () => { @@ -45,7 +52,7 @@ describe('Trino SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['PREPARE']); + expect(suggestion).toMatchUnorderedArrary(['PREPARE']); }); test('After DELETE', () => { @@ -58,7 +65,7 @@ describe('Trino SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['FROM']); + expect(suggestion).toMatchUnorderedArrary(['FROM']); }); test('After DESCRIBE', () => { @@ -71,7 +78,7 @@ describe('Trino SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['OUTPUT', 'INPUT']); + expect(suggestion).toMatchUnorderedArrary(['OUTPUT', 'INPUT']); }); test('After DROP', () => { @@ -84,7 +91,13 @@ describe('Trino SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['ROLE', 'VIEW', 'MATERIALIZED', 'TABLE', 'SCHEMA']); + expect(suggestion).toMatchUnorderedArrary([ + 'ROLE', + 'VIEW', + 'MATERIALIZED', + 'TABLE', + 'SCHEMA', + ]); }); test('After INSERT', () => { @@ -97,6 +110,6 @@ describe('Trino SQL Token Suggestion', () => { pos )?.keywords; - expect(suggestion).toEqual(['INTO']); + expect(suggestion).toMatchUnorderedArrary(['INTO']); }); }); diff --git a/test/setupTests.ts b/test/setupTests.ts new file mode 100644 index 0000000..96a90e5 --- /dev/null +++ b/test/setupTests.ts @@ -0,0 +1,3 @@ +import { toMatchUnorderedArrary } from './matchers'; + +expect.extend({ toMatchUnorderedArrary });