From 9e5c3feeea9223706903ba818b635e33dd2ab4e8 Mon Sep 17 00:00:00 2001 From: Palm Civet Date: Thu, 4 Apr 2024 16:14:21 +0800 Subject: [PATCH] test: test coverage improved --- src/utils/evaluate.ts | 8 +++- src/utils/expression.ts | 36 ++++++++++------ test/policies.test.ts | 11 +++-- test/utils.test.ts | 96 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 127 insertions(+), 24 deletions(-) diff --git a/src/utils/evaluate.ts b/src/utils/evaluate.ts index 73c4a89..fb8f83d 100644 --- a/src/utils/evaluate.ts +++ b/src/utils/evaluate.ts @@ -30,7 +30,9 @@ function compareArray(leftValue: T, operation: ArrayOperation, rightValue: Ar case OperationEnum.NOT_IN: return !rightValue.includes(leftValue); default: - throw new Error(`[spectra] Operation ${operation} is not supported.`); + throw new Error( + `[spectra] Operation is not supported. ${leftValue} ${operation} ${rightValue}` + ); } } @@ -60,7 +62,9 @@ export function compareValue( if (!Array.isArray(leftValue) && Array.isArray(rightValue)) { return compareArray(leftValue, operation as ArrayOperation, rightValue); } else { - throw new Error(`[spectra] Operation ${operation} is not supported.`); + throw new Error( + `[spectra] Operation is not supported. ${leftValue} ${operation} ${rightValue}` + ); } } } diff --git a/src/utils/expression.ts b/src/utils/expression.ts index 8e2a9e9..aef3e91 100644 --- a/src/utils/expression.ts +++ b/src/utils/expression.ts @@ -1,10 +1,10 @@ import { - ExpressionDefinition, BinaryExpressionDefinition, AndExpressionDefinition, OrExpressionDefinition, NotExpressionDefinition, RefValue, + Operation, } from '@getspectra/spectra-typings'; import { BinaryExpression, @@ -12,12 +12,27 @@ import { OrExpression, NotExpression, } from '@/expressions'; -import { ExpressionInterface } from '@/types'; +import { ExpressionInterface, OperationEnum } from '@/types'; export function isRefValue(key: any): key is RefValue { return key !== null && typeof key === 'object' && 'ref' in key; } +export function isValidOperation(operation: any): operation is Operation { + return [ + OperationEnum.EQ, + OperationEnum.NEQ, + OperationEnum.NEQ2, + OperationEnum.GT, + OperationEnum.GTE, + OperationEnum.LT, + OperationEnum.LTE, + OperationEnum.IN, + OperationEnum.NIN, + OperationEnum.NOT_IN, + ].includes(operation); +} + export function isValidExpressionInterface( expression: any ): expression is ExpressionInterface { @@ -46,7 +61,7 @@ export function isValidBinaryExpressionDefinition( return false; } - if (typeof operation !== 'string') { + if (!isValidOperation(operation)) { return false; } @@ -78,6 +93,10 @@ export function isValidAndExpressionDefinition( return false; } + if (expression.and.length <= 1) { + return false; + } + return true; } @@ -101,17 +120,6 @@ export function isValidNotExpressionDefinition( return typeof expression === 'object' && expression.not !== undefined; } -export function isValidExpressionDefine( - expression: any -): expression is ExpressionDefinition { - return ( - isValidBinaryExpressionDefinition(expression) || - isValidAndExpressionDefinition(expression) || - isValidOrExpressionDefinition(expression) || - isValidNotExpressionDefinition(expression) - ); -} - /** * @description Normalize an expression to an expression instance. */ diff --git a/test/policies.test.ts b/test/policies.test.ts index 280bda1..ef6a4e6 100644 --- a/test/policies.test.ts +++ b/test/policies.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from '@jest/globals'; -import { Policy, BinaryExpression } from '@/index'; +import { Policy, BinaryExpression, Spectra } from '@/index'; describe('Policies', () => { test('getter', () => { @@ -25,7 +25,12 @@ describe('Policies', () => { effect: 'DENY', }); - expect(allowPolicy.getEffect()).toBe('ALLOW'); - expect(denyPolicy.getEffect()).toBe('DENY'); + const result = Spectra.validate( + [allowPolicy, denyPolicy], + { load: () => ({ 'user.id': 1 }) }, + 'EDIT_FILE' + ); + + expect(result).toBe(true); }); }); diff --git a/test/utils.test.ts b/test/utils.test.ts index a8300ba..99fd113 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -4,8 +4,15 @@ import { DataType, Policy, and, + or, bisectArray, getValueFromKey, + isRefValue, + isValidAndExpressionDefinition, + isValidBinaryExpressionDefinition, + isDataLoaderClass, + isDataLoaderFunction, + compareValue, } from '@/index'; describe('Policy Utils', () => { @@ -15,9 +22,18 @@ describe('Policy Utils', () => { expect(strings).toEqual(['3', '4', '6']); expect(numbers).toEqual([1, 2, 5, 7]); }); +}); - test('isArgumentRef', () => {}); +describe('DataLoader Utils', () => { + test('isDataLoaderClass', () => { + expect(isDataLoaderClass({ load: () => {} })).toBeTruthy(); + expect(isDataLoaderClass({ load: {} })).toBeFalsy(); + expect(isDataLoaderFunction(() => {})).toBeTruthy(); + expect(isDataLoaderFunction({})).toBeFalsy(); + }); +}); +describe('Evaluate Utils', () => { test('getValueFromKey', () => { const data: DataType = { 'user.id': 1, @@ -30,14 +46,73 @@ describe('Policy Utils', () => { data['user.create_at'] ); }); -}); -describe('Compare Utils', () => { - test('compareValue', () => {}); + test('compareArray', () => { + expect(compareValue(2, 'in', [1, 2, 3])).toBeTruthy(); + expect(compareValue(4, 'nin', [1, 4])).toBeFalsy(); + expect(compareValue(4, 'not_in', [1, 2, 3, 4])).toBeFalsy(); + expect(compareValue('2', 'in', [1, 2, 3])).toBeFalsy(); + + let invalidCompareArray = false; + try { + compareValue(2, 'in', 2); + } catch (error) { + invalidCompareArray = true; + } + expect(invalidCompareArray).toBeTruthy(); + + let invalidOperation = false; + try { + compareValue(2, 'n_in' as any, [2, 3]); + } catch (error) { + invalidOperation = true; + } + expect(invalidOperation).toBeTruthy(); + }); + + test('compareValue', () => { + expect(compareValue(2, '=', 2)).toBeTruthy(); + expect(compareValue(2, '!=', 2)).toBeFalsy(); + expect(compareValue(2, '!=', 3)).toBeTruthy(); + expect(compareValue(2, '<>', 2)).toBeFalsy(); + expect(compareValue(2, '>', 1)).toBeTruthy(); + expect(compareValue(2, '>=', 2)).toBeTruthy(); + expect(compareValue(2, '<', 3)).toBeTruthy(); + expect(compareValue(2, '<=', 2)).toBeTruthy(); + expect(compareValue(2, '!=', '2')).toBeTruthy(); + expect(compareValue(2, '<>', '2')).toBeTruthy(); + }); }); describe('Expression Utils', () => { - test('isValidExpressionDefine', () => {}); + test('isRefValue', () => { + expect(isRefValue({ ref: 'user.id' })).toBeTruthy(); + expect(isRefValue('user.id')).toBeFalsy(); + expect(isRefValue(1)).toBeFalsy(); + expect(isRefValue(true)).toBeFalsy(); + expect(isRefValue(null)).toBeFalsy(); + expect(isRefValue(undefined)).toBeFalsy(); + expect(isRefValue([])).toBeFalsy(); + expect(isRefValue({})).toBeFalsy(); + expect(isRefValue(new Date())).toBeFalsy(); + expect(isRefValue(new Error())).toBeFalsy(); + }); + + test('isValidBinaryExpressionDefinition', () => { + expect(isValidBinaryExpressionDefinition(['user.role', '=', 'admin'])).toBeTruthy(); + expect(isValidBinaryExpressionDefinition([])).toBeFalsy(); + expect(isValidBinaryExpressionDefinition([1, 2, 3, 4])).toBeFalsy(); + expect(isValidBinaryExpressionDefinition([1, 2, 4])).toBeFalsy(); + expect(isValidBinaryExpressionDefinition(['1', '!', 4])).toBeFalsy(); + }); + + test('isValidAndExpressionDefinition', () => { + const isValid = isValidAndExpressionDefinition; + expect(isValid('')).toBeFalsy(); + expect(isValid({ and: [['user.role', '=', 'admin']] })).toBeFalsy(); + expect(isValid({ and: [['user.role', '=', 'admin'], []] })).toBeTruthy(); + expect(isValid({ and: ['user.role', '=', 'admin'] })).toBeTruthy(); + }); test('normalizeExpression', () => { const policy = new Policy({ @@ -51,5 +126,16 @@ describe('Expression Utils', () => { effect: 'DENY', }); expect(policy.getFilter()).toBeTruthy(); + + let invalidDefinition = false; + try { + or([ + { and: [['user.role', '=', 'admin'], []] }, + { a: ['user.role', '=', 'admin', ''] } as any, + ]); + } catch (error) { + invalidDefinition = true; + } + expect(invalidDefinition).toBeTruthy(); }); });