Skip to content

Commit 58fca51

Browse files
committed
feat: add test cases for handling empty arrays and non-array input in functions sum, prod, min, max, average, and, and or
1 parent f329054 commit 58fca51

File tree

4 files changed

+137
-30
lines changed

4 files changed

+137
-30
lines changed

src/compile.test.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ describe('error handling', () => {
9797
actualErr = err
9898
}
9999

100-
expect(actualErr?.message).toBe("Cannot read properties of null (reading 'reduce')")
100+
expect(actualErr?.message).toBe('Array expected')
101101
expect(actualErr?.jsonquery).toEqual([
102102
{ data: scoreData, query },
103103
{
@@ -118,18 +118,6 @@ describe('error handling', () => {
118118
expect(go([[3], [7], [4]], ['sort'])).toEqual([[3], [4], [7]])
119119
expect(go([[], [], []], ['sort'])).toEqual([[], [], []])
120120
})
121-
122-
test('should throw an error when calculating the sum of an empty array', () => {
123-
expect(() => go([], ['sum'])).toThrow('Reduce of empty array with no initial value')
124-
})
125-
126-
test('should throw an error when calculating the prod of an empty array', () => {
127-
expect(() => go([], ['prod'])).toThrow('Reduce of empty array with no initial value')
128-
})
129-
130-
test('should throw an error when calculating the average of an empty array', () => {
131-
expect(() => go([], ['average'])).toThrow('Reduce of empty array with no initial value')
132-
})
133121
})
134122

135123
describe('customization', () => {

src/compile.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { functions } from './functions'
1+
import { functions, throwTypeError } from './functions'
22
import { isArray, isObject } from './is'
33
import type {
44
Fun,
@@ -48,7 +48,3 @@ function compileFunction(query: JSONQueryFunction, functions: FunctionBuildersMa
4848

4949
return fnBuilder(...args)
5050
}
51-
52-
function throwTypeError(message: string): () => void {
53-
throw new Error(message)
54-
}

src/functions.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -234,21 +234,16 @@ export const functions: FunctionBuildersMap = {
234234
data.length,
235235

236236
keys: () => Object.keys,
237-
238237
values: () => Object.values,
239238

240-
prod: () => (data: number[]) => data.reduce((a, b) => a * b),
241-
242-
sum: () => (data: number[]) => data.reduce((a, b) => a + b),
243-
244-
average: () => (data: number[]) => (functions.sum()(data) as number) / data.length,
245-
246-
min: () => (data: number[]) => Math.min(...data),
239+
prod: () => (data: number[]) => reduce(data, (a, b) => a * b),
240+
sum: () => (data: number[]) => reduce(data, (a, b) => a + b),
241+
average: () => (data: number[]) => reduce(data, (a, b) => a + b) / data.length,
242+
min: () => (data: number[]) => reduce(data, (a, b) => Math.min(a, b)),
243+
max: () => (data: number[]) => reduce(data, (a, b) => Math.max(a, b)),
247244

248-
max: () => (data: number[]) => Math.max(...data),
249-
250-
and: buildFunction((...args) => args.reduce((a, b) => !!(a && b))),
251-
or: buildFunction((...args) => args.reduce((a, b) => !!(a || b))),
245+
and: buildFunction((...args: unknown[]) => reduce(args, (a, b) => !!(a && b))),
246+
or: buildFunction((...args: unknown[]) => reduce(args, (a, b) => !!(a || b))),
252247
not: buildFunction((a: unknown) => !a),
253248

254249
exists: (queryGet: JSONQueryFunction) => {
@@ -314,3 +309,19 @@ export const functions: FunctionBuildersMap = {
314309
}
315310

316311
const truthy = (x: unknown) => x !== null && x !== 0 && x !== false
312+
313+
const reduce = <T>(data: T[], callback: (previousValue: T, currentValue: T) => T): T => {
314+
if (!isArray(data)) {
315+
throwTypeError('Array expected')
316+
}
317+
318+
if (data.length === 0) {
319+
throwTypeError('Non-empty array expected')
320+
}
321+
322+
return data.reduce(callback)
323+
}
324+
325+
export const throwTypeError = (message: string) => {
326+
throw new TypeError(message)
327+
}

test-suite/compile.test.json

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,20 @@
685685
"query": ["sum"],
686686
"output": 8.1
687687
},
688+
{
689+
"category": "sum",
690+
"description": "should throw an error when calculating the sum of an empty array",
691+
"input": [],
692+
"query": ["sum"],
693+
"throws": "Non-empty array expected"
694+
},
695+
{
696+
"category": "sum",
697+
"description": "should throw an error when calculating the sum a string",
698+
"input": "abc",
699+
"query": ["sum"],
700+
"throws": "Array expected"
701+
},
688702

689703
{
690704
"category": "min",
@@ -693,6 +707,20 @@
693707
"query": ["min"],
694708
"output": -7
695709
},
710+
{
711+
"category": "min",
712+
"description": "should throw an error when calculating min on an empty array",
713+
"input": [],
714+
"query": ["min"],
715+
"throws": "Non-empty array expected"
716+
},
717+
{
718+
"category": "min",
719+
"description": "should throw an error when calculating min on a string",
720+
"input": "abc",
721+
"query": ["min"],
722+
"throws": "Array expected"
723+
},
696724

697725
{
698726
"category": "max",
@@ -701,6 +729,20 @@
701729
"query": ["max"],
702730
"output": 3
703731
},
732+
{
733+
"category": "max",
734+
"description": "should throw an error when calculating max on an empty array",
735+
"input": [],
736+
"query": ["max"],
737+
"throws": "Non-empty array expected"
738+
},
739+
{
740+
"category": "max",
741+
"description": "should throw an error when calculating max on a string",
742+
"input": "abc",
743+
"query": ["max"],
744+
"throws": "Array expected"
745+
},
704746

705747
{
706748
"category": "prod",
@@ -709,6 +751,20 @@
709751
"query": ["prod"],
710752
"output": 30
711753
},
754+
{
755+
"category": "prod",
756+
"description": "should throw an error when calculating the prod of an empty array",
757+
"input": [],
758+
"query": ["prod"],
759+
"throws": "Non-empty array expected"
760+
},
761+
{
762+
"category": "prod",
763+
"description": "should throw an error when calculating the prod a string",
764+
"input": "abc",
765+
"query": ["prod"],
766+
"throws": "Array expected"
767+
},
712768

713769
{
714770
"category": "average",
@@ -724,6 +780,20 @@
724780
"query": ["average"],
725781
"output": 3
726782
},
783+
{
784+
"category": "average",
785+
"description": "should throw an error when calculating the average of an empty array",
786+
"input": [],
787+
"query": ["average"],
788+
"throws": "Non-empty array expected"
789+
},
790+
{
791+
"category": "average",
792+
"description": "should throw an error when calculating the average a string",
793+
"input": "abc",
794+
"query": ["average"],
795+
"throws": "Array expected"
796+
},
727797

728798
{
729799
"category": "eq",
@@ -955,6 +1025,27 @@
9551025
"query": ["and", true, true, false],
9561026
"output": false
9571027
},
1028+
{
1029+
"category": "and",
1030+
"description": "should calculate and with one argument (1)",
1031+
"input": null,
1032+
"query": ["and", false],
1033+
"output": false
1034+
},
1035+
{
1036+
"category": "and",
1037+
"description": "should calculate and with one argument (2)",
1038+
"input": null,
1039+
"query": ["and", true],
1040+
"output": true
1041+
},
1042+
{
1043+
"category": "and",
1044+
"description": "should throw when calculating and with no arguments",
1045+
"input": null,
1046+
"query": ["and"],
1047+
"throws": "Non-empty array expected"
1048+
},
9581049

9591050
{
9601051
"category": "or",
@@ -1012,6 +1103,27 @@
10121103
"query": ["or", false, false, true],
10131104
"output": true
10141105
},
1106+
{
1107+
"category": "or",
1108+
"description": "should calculate or with one argument (1)",
1109+
"input": null,
1110+
"query": ["or", false],
1111+
"output": false
1112+
},
1113+
{
1114+
"category": "or",
1115+
"description": "should calculate or with one argument (2)",
1116+
"input": null,
1117+
"query": ["or", true],
1118+
"output": true
1119+
},
1120+
{
1121+
"category": "or",
1122+
"description": "should throw when calculating or with no arguments",
1123+
"input": null,
1124+
"query": ["or"],
1125+
"throws": "Non-empty array expected"
1126+
},
10151127

10161128
{
10171129
"category": "not",

0 commit comments

Comments
 (0)