406 lines
15 KiB
TypeScript
Generated
406 lines
15 KiB
TypeScript
Generated
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
|
|
import * as dataValueHelper from '@/src/data/helper/dataValueHelper';
|
|
|
|
|
|
const NO_SUCH_CASE = 'NO_SUCH_CASE';
|
|
|
|
// Tags for relational comparison cases.
|
|
// LT: less than, GT: greater than, INCMPR: incomparable
|
|
const TAG = {
|
|
BothNumeric_AtLeastOneNumber_L_LT_R: 'BothNumeric_AtLeastOneNumber_L_LT_R',
|
|
BothNumeric_AtLeastOneNumber_L_GT_R: 'BothNumeric_AtLeastOneNumber_L_GT_R',
|
|
BothString_L_LT_R: 'BothString_L_LT_R',
|
|
BothString_L_GT_R: 'BothString_L_GT_R',
|
|
BothNumericString_NotStrictEQ_BeNumericEQ: 'BothNumericString_NotStrictEQ_BeNumericEQ',
|
|
Strict_EQ: 'Strict_EQ',
|
|
BothNumeric_OneNumber_NumericEQ: 'BothNumeric_OneNumber_NumericEQ',
|
|
BothIncmpr_NotEQ: 'BothIncmpr_NotEQ',
|
|
L_Incmpr_R_NumberOrString: 'L_Incmpr_R_NumberOrString',
|
|
R_Incmpr_L_NumberOrString: 'R_Incmpr_L_NumberOrString'
|
|
} as const;
|
|
|
|
type CaseTag = typeof TAG[keyof typeof TAG];
|
|
|
|
type Operation = 'lt' | 'lte' | 'gt' | 'gte' | 'eq' | 'ne';
|
|
type Order = 'asc' | 'desc';
|
|
type Incomparable = 'min' | 'max';
|
|
|
|
|
|
const tagRevertPairs = [
|
|
['BothNumeric_AtLeastOneNumber_L_LT_R', 'BothNumeric_AtLeastOneNumber_L_GT_R'],
|
|
['BothString_L_LT_R', 'BothString_L_GT_R'],
|
|
['BothNumericString_NotStrictEQ_BeNumericEQ', 'BothNumericString_NotStrictEQ_BeNumericEQ'],
|
|
['Strict_EQ', 'Strict_EQ'],
|
|
['BothNumeric_OneNumber_NumericEQ', 'BothNumeric_OneNumber_NumericEQ'],
|
|
['BothIncmpr_NotEQ', 'BothIncmpr_NotEQ'],
|
|
['L_Incmpr_R_NumberOrString', 'R_Incmpr_L_NumberOrString']
|
|
] as const;
|
|
|
|
const filterResultMap = {
|
|
BothNumeric_AtLeastOneNumber_L_LT_R: {
|
|
lt: true,
|
|
lte: true,
|
|
gt: false,
|
|
gte: false,
|
|
eq: false,
|
|
ne: true
|
|
},
|
|
BothNumeric_AtLeastOneNumber_L_GT_R: {
|
|
lt: false,
|
|
lte: false,
|
|
gt: true,
|
|
gte: true,
|
|
eq: false,
|
|
ne: true
|
|
},
|
|
BothString_L_LT_R: {
|
|
lt: NO_SUCH_CASE,
|
|
lte: NO_SUCH_CASE,
|
|
gt: NO_SUCH_CASE,
|
|
gte: NO_SUCH_CASE,
|
|
eq: false,
|
|
ne: true
|
|
},
|
|
BothString_L_GT_R: {
|
|
lt: NO_SUCH_CASE,
|
|
lte: NO_SUCH_CASE,
|
|
gt: NO_SUCH_CASE,
|
|
gte: NO_SUCH_CASE,
|
|
eq: false,
|
|
ne: true
|
|
},
|
|
BothNumericString_NotStrictEQ_BeNumericEQ: {
|
|
lt: NO_SUCH_CASE,
|
|
lte: NO_SUCH_CASE,
|
|
gt: NO_SUCH_CASE,
|
|
gte: NO_SUCH_CASE,
|
|
eq: false,
|
|
ne: true
|
|
},
|
|
Strict_EQ: {
|
|
lt: false,
|
|
lte: true,
|
|
gt: false,
|
|
gte: true,
|
|
eq: true,
|
|
ne: false
|
|
},
|
|
BothNumeric_OneNumber_NumericEQ: {
|
|
lt: false,
|
|
lte: true,
|
|
gt: false,
|
|
gte: true,
|
|
eq: true,
|
|
ne: false
|
|
},
|
|
BothIncmpr_NotEQ: {
|
|
lt: false,
|
|
lte: false,
|
|
gt: false,
|
|
gte: false,
|
|
eq: false,
|
|
ne: true
|
|
},
|
|
L_Incmpr_R_NumberOrString: {
|
|
lt: false,
|
|
lte: false,
|
|
gt: false,
|
|
gte: false,
|
|
eq: false,
|
|
ne: true
|
|
},
|
|
R_Incmpr_L_NumberOrString: {
|
|
lt: false,
|
|
lte: false,
|
|
gt: false,
|
|
gte: false,
|
|
eq: false,
|
|
ne: true
|
|
}
|
|
} as const;
|
|
|
|
const sortResultMap = {
|
|
BothNumeric_AtLeastOneNumber_L_LT_R: {
|
|
asc_incmprmin: -1,
|
|
asc_incmprmax: -1,
|
|
desc_incmprmin: 1,
|
|
desc_incmprmax: 1
|
|
},
|
|
BothNumeric_AtLeastOneNumber_L_GT_R: {
|
|
asc_incmprmin: 1,
|
|
asc_incmprmax: 1,
|
|
desc_incmprmin: -1,
|
|
desc_incmprmax: -1
|
|
},
|
|
BothString_L_LT_R: {
|
|
asc_incmprmin: -1,
|
|
asc_incmprmax: -1,
|
|
desc_incmprmin: 1,
|
|
desc_incmprmax: 1
|
|
},
|
|
BothString_L_GT_R: {
|
|
asc_incmprmin: 1,
|
|
asc_incmprmax: 1,
|
|
desc_incmprmin: -1,
|
|
desc_incmprmax: -1
|
|
},
|
|
BothNumericString_NotStrictEQ_BeNumericEQ: {
|
|
asc_incmprmin: 0,
|
|
asc_incmprmax: 0,
|
|
desc_incmprmin: 0,
|
|
desc_incmprmax: 0
|
|
},
|
|
Strict_EQ: {
|
|
asc_incmprmin: 0,
|
|
asc_incmprmax: 0,
|
|
desc_incmprmin: 0,
|
|
desc_incmprmax: 0
|
|
},
|
|
BothNumeric_OneNumber_NumericEQ: {
|
|
asc_incmprmin: 0,
|
|
asc_incmprmax: 0,
|
|
desc_incmprmin: 0,
|
|
desc_incmprmax: 0
|
|
},
|
|
BothIncmpr_NotEQ: {
|
|
asc_incmprmin: 0,
|
|
asc_incmprmax: 0,
|
|
desc_incmprmin: 0,
|
|
desc_incmprmax: 0
|
|
},
|
|
L_Incmpr_R_NumberOrString: {
|
|
asc_incmprmin: -1,
|
|
asc_incmprmax: 1,
|
|
desc_incmprmin: 1,
|
|
desc_incmprmax: -1
|
|
},
|
|
R_Incmpr_L_NumberOrString: {
|
|
asc_incmprmin: 1,
|
|
asc_incmprmax: -1,
|
|
desc_incmprmin: -1,
|
|
desc_incmprmax: 1
|
|
}
|
|
} as const;
|
|
|
|
type EvaluateFunction = (lval: unknown, rval: unknown, caseTag: CaseTag) => void;
|
|
|
|
function eachRelationalComparisonCase(evalFn: EvaluateFunction) {
|
|
|
|
const FULL_WIDTH_SPACE = String.fromCharCode(12288);
|
|
|
|
const testerMap = {
|
|
notEqualAndHasOrder: function () {
|
|
expectDual(123, 555, TAG.BothNumeric_AtLeastOneNumber_L_LT_R);
|
|
expectDual(-123, -555, TAG.BothNumeric_AtLeastOneNumber_L_GT_R);
|
|
expectDual(-123, 123, TAG.BothNumeric_AtLeastOneNumber_L_LT_R);
|
|
|
|
expectDual(Infinity, 123, TAG.BothNumeric_AtLeastOneNumber_L_GT_R);
|
|
expectDual(-Infinity, -123, TAG.BothNumeric_AtLeastOneNumber_L_LT_R);
|
|
expectDual('Infinity', 123, TAG.BothNumeric_AtLeastOneNumber_L_GT_R);
|
|
expectDual('-Infinity', 123, TAG.BothNumeric_AtLeastOneNumber_L_LT_R);
|
|
expectDual(123, '555', TAG.BothNumeric_AtLeastOneNumber_L_LT_R);
|
|
expectDual(555, '555.6', TAG.BothNumeric_AtLeastOneNumber_L_LT_R);
|
|
expectDual('-555', -555.6, TAG.BothNumeric_AtLeastOneNumber_L_GT_R);
|
|
expectDual(123, ' 555 ', TAG.BothNumeric_AtLeastOneNumber_L_LT_R);
|
|
expectDual(' -555 ', 123, TAG.BothNumeric_AtLeastOneNumber_L_LT_R);
|
|
expectDual(123, ' \r \n 555 \t ' + FULL_WIDTH_SPACE, TAG.BothNumeric_AtLeastOneNumber_L_LT_R);
|
|
},
|
|
|
|
notEqualAndNoOrder: function () {
|
|
const makeDate = () => new Date(2012, 5, 12);
|
|
const makeFn = () => function () {};
|
|
|
|
expectDual(NaN, NaN, TAG.BothIncmpr_NotEQ);
|
|
expectDual(NaN, -NaN, TAG.BothIncmpr_NotEQ);
|
|
expectDual(NaN, 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(NaN, 2, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('NaN', NaN, TAG.R_Incmpr_L_NumberOrString);
|
|
expectDual('NaN', 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('NaN', 2, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('-NaN', -NaN, TAG.R_Incmpr_L_NumberOrString);
|
|
expectDual('-NaN', 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('-NaN', 2, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(true, 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(false, 1, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('true', 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('false', 1, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(undefined, 2, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(undefined, 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(null, 2, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(null, 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(makeDate(), 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(makeDate(), makeDate(), TAG.BothIncmpr_NotEQ);
|
|
expectDual(makeDate(), +makeDate(), TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual([], 1, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual([], 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual({}, 1, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual([], '0', TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual({}, '1', TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual({}, 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual({}, '1', TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual({}, '0', TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(/1/, 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(/0/, 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('555a', 123, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('abc', 123, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('abc', null, TAG.R_Incmpr_L_NumberOrString); // See [SORT_COMPARISON_RULE]
|
|
expectDual('abc', '123', TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('abc', 'abcde', TAG.BothString_L_LT_R);
|
|
expectDual('abc', 'abc', TAG.Strict_EQ);
|
|
expectDual('2', '12', TAG.BothString_L_LT_R); // '2' > '12' in JS but should not happen here.
|
|
expectDual(' ', '', TAG.BothString_L_GT_R);
|
|
expectDual(0.5, '0. 5', TAG.R_Incmpr_L_NumberOrString);
|
|
expectDual('0.5', '0. 5', TAG.R_Incmpr_L_NumberOrString);
|
|
expectDual('- 5', -5, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('-123.5', ' -123.5 ', TAG.BothNumericString_NotStrictEQ_BeNumericEQ);
|
|
expectDual('0x11', 17, TAG.L_Incmpr_R_NumberOrString); // not 17 in int16.
|
|
expectDual('0x11', 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('0x0', 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('0. 5', 0.5, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('0 .5', 0.5, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('', 2, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('', 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(' ', 2, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(' ', 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(' \n', '\n', TAG.BothString_L_GT_R);
|
|
expectDual('\n', 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual('\n', 2, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual({}, {}, TAG.BothIncmpr_NotEQ);
|
|
expectDual({}, [], TAG.BothIncmpr_NotEQ);
|
|
expectDual(makeFn(), makeFn(), TAG.BothIncmpr_NotEQ);
|
|
expectDual(makeFn(), 0, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(makeFn(), 1, TAG.L_Incmpr_R_NumberOrString);
|
|
expectDual(makeFn(), makeFn().toString(), TAG.L_Incmpr_R_NumberOrString);
|
|
},
|
|
|
|
equalNumeric: function () {
|
|
expectDual(123, 123, TAG.Strict_EQ);
|
|
expectDual(1e3, 1000, TAG.Strict_EQ);
|
|
expectDual(-1e3, -1000, TAG.Strict_EQ);
|
|
expectDual('1e3', 1000, TAG.BothNumeric_OneNumber_NumericEQ);
|
|
expectDual('-1e3', -1000, TAG.BothNumeric_OneNumber_NumericEQ);
|
|
expectDual(123, '123', TAG.BothNumeric_OneNumber_NumericEQ);
|
|
expectDual(123, ' 123 ', TAG.BothNumeric_OneNumber_NumericEQ);
|
|
expectDual(123.5, ' \n \r 123.5 \t ', TAG.BothNumeric_OneNumber_NumericEQ);
|
|
expectDual(123.5, 123.5 + FULL_WIDTH_SPACE, TAG.BothNumeric_OneNumber_NumericEQ);
|
|
expectDual(' -123.5 ', -123.5, TAG.BothNumeric_OneNumber_NumericEQ);
|
|
expectDual('011', 11, TAG.BothNumeric_OneNumber_NumericEQ); // not 9 in int8.
|
|
},
|
|
|
|
equalOtherTypes: function () {
|
|
const emptyObj = {};
|
|
const emptyArr = [] as unknown[];
|
|
const date = new Date(2012, 5, 12);
|
|
const fn = function () {};
|
|
expectDual(emptyObj, emptyObj, TAG.Strict_EQ);
|
|
expectDual(emptyArr, emptyArr, TAG.Strict_EQ);
|
|
expectDual(date, date, TAG.Strict_EQ);
|
|
expectDual(fn, fn, TAG.Strict_EQ);
|
|
}
|
|
};
|
|
|
|
function expectDual(lval: unknown, rval: unknown, caseTag: CaseTag) {
|
|
validateCaseTag(caseTag);
|
|
evalFn(lval, rval, caseTag);
|
|
|
|
const revertedCaseTag = findRevertTag(caseTag);
|
|
validateCaseTag(revertedCaseTag);
|
|
evalFn(rval, lval, revertedCaseTag);
|
|
}
|
|
|
|
function validateCaseTag(caseTag: CaseTag) {
|
|
expect(TAG.hasOwnProperty(caseTag)).toEqual(true);
|
|
}
|
|
|
|
function findRevertTag(caseTag: CaseTag) {
|
|
for (let i = 0; i < tagRevertPairs.length; i++) {
|
|
const item = tagRevertPairs[i];
|
|
if (item[0] === caseTag) {
|
|
return item[1];
|
|
}
|
|
else if (item[1] === caseTag) {
|
|
return item[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
Object.keys(testerMap).forEach((name: keyof typeof testerMap) => testerMap[name]());
|
|
}
|
|
|
|
|
|
describe('data/helper/dataValueHelper', function () {
|
|
|
|
describe('filter_relational_comparison', function () {
|
|
|
|
function testFilterComparator(op: Operation) {
|
|
it(op + '_filter_comparator', () => {
|
|
eachRelationalComparisonCase((lval, rval, caseTag) => {
|
|
expect(filterResultMap.hasOwnProperty(caseTag));
|
|
expect(filterResultMap[caseTag].hasOwnProperty(op));
|
|
const expectedResult = filterResultMap[caseTag][op];
|
|
|
|
if ((op === 'lt' || op === 'lte' || op === 'gt' || op === 'gte')
|
|
&& typeof rval !== 'number'
|
|
) {
|
|
expect(() => {
|
|
dataValueHelper.createFilterComparator(op, rval);
|
|
}).toThrow();
|
|
}
|
|
else {
|
|
const comparator = dataValueHelper.createFilterComparator(op, rval);
|
|
expect(comparator.evaluate(lval)).toEqual(expectedResult);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
testFilterComparator('lt');
|
|
testFilterComparator('lte');
|
|
testFilterComparator('gt');
|
|
testFilterComparator('gte');
|
|
testFilterComparator('eq');
|
|
testFilterComparator('ne');
|
|
});
|
|
|
|
describe('sort_relational_comparison', function () {
|
|
|
|
function testSortComparator(order: Order, incomparable: Incomparable) {
|
|
const key = order + '_incmpr' + incomparable;
|
|
const SortOrderComparator = dataValueHelper.SortOrderComparator;
|
|
const sortOrderComparator = new SortOrderComparator(order, incomparable);
|
|
it(key + '_sort_comparator', () => {
|
|
eachRelationalComparisonCase((lval, rval, caseTag) => {
|
|
expect(sortResultMap.hasOwnProperty(caseTag));
|
|
expect(sortResultMap[caseTag].hasOwnProperty(key));
|
|
const expectedResult = (sortResultMap[caseTag] as any)[key];
|
|
expect(sortOrderComparator.evaluate(lval, rval)).toEqual(expectedResult);
|
|
});
|
|
});
|
|
}
|
|
testSortComparator('asc', 'min');
|
|
testSortComparator('asc', 'max');
|
|
testSortComparator('desc', 'min');
|
|
testSortComparator('desc', 'max');
|
|
});
|
|
|
|
});
|
|
|