| /* | 
 | * 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'); | 
 |     }); | 
 |  | 
 | }); | 
 |  |