Skip to content

Commit 71b8fa2

Browse files
authored
Merge pull request #97 from jamslinger/division-by-zero
Don't panic in filter divided_by on division by zero
2 parents cc7bda4 + 63cddf1 commit 71b8fa2

File tree

2 files changed

+53
-8
lines changed

2 files changed

+53
-8
lines changed

filters/standard_filters.go

+37-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package filters
33

44
import (
55
"encoding/json"
6+
"errors"
67
"fmt"
78
"html"
89
"math"
@@ -17,6 +18,8 @@ import (
1718
"github.com/osteele/tuesday"
1819
)
1920

21+
var errDivisionByZero = errors.New("division by zero")
22+
2023
// A FilterDictionary holds filters.
2124
type FilterDictionary interface {
2225
AddFilter(string, any)
@@ -100,14 +103,42 @@ func AddStandardFilters(fd FilterDictionary) { //nolint: gocyclo
100103
fd.AddFilter("times", func(a, b float64) float64 {
101104
return a * b
102105
})
103-
fd.AddFilter("divided_by", func(a float64, b any) any {
106+
fd.AddFilter("divided_by", func(a float64, b any) (any, error) {
107+
divInt := func(a, b int64) (int64, error) {
108+
if b == 0 {
109+
return 0, errDivisionByZero
110+
}
111+
return a / b, nil
112+
}
113+
divFloat := func(a, b float64) (float64, error) {
114+
if b == 0 {
115+
return 0, errDivisionByZero
116+
}
117+
return a / b, nil
118+
}
104119
switch q := b.(type) {
105-
case int, int16, int32, int64:
106-
return int(a) / q.(int)
107-
case float32, float64:
108-
return a / b.(float64)
120+
case int:
121+
return divInt(int64(a), int64(q))
122+
case int8:
123+
return divInt(int64(a), int64(q))
124+
case int16:
125+
return divInt(int64(a), int64(q))
126+
case int32:
127+
return divInt(int64(a), int64(q))
128+
case int64:
129+
return divInt(int64(a), q)
130+
case uint8:
131+
return divInt(int64(a), int64(q))
132+
case uint16:
133+
return divInt(int64(a), int64(q))
134+
case uint32:
135+
return divInt(int64(a), int64(q))
136+
case float32:
137+
return divFloat(a, float64(q))
138+
case float64:
139+
return divFloat(a, q)
109140
default:
110-
return nil
141+
return nil, fmt.Errorf("invalid divisor: '%v'", b)
111142
}
112143
})
113144
fd.AddFilter("round", func(n float64, places func(int) int) float64 {

filters/standard_filters_test.go

+16-2
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ Liquid" | slice: 2, 4`, "quid"},
184184
{`5 | divided_by: 3`, 1},
185185
{`20 | divided_by: 7`, 2},
186186
{`20 | divided_by: 7.0`, 2.857142857142857},
187-
{`20 | divided_by: 's'`, nil},
188187

189188
{`1.2 | round`, 1.0},
190189
{`2.7 | round`, 3.0},
@@ -197,6 +196,14 @@ Liquid" | slice: 2, 4`, "quid"},
197196
{`"1" | type`, `string`},
198197
}
199198

199+
var filterErrorTests = []struct {
200+
in string
201+
error string
202+
}{
203+
{`20 | divided_by: 's'`, `error applying filter "divided_by" ("invalid divisor: 's'")`},
204+
{`20 | divided_by: 0`, `error applying filter "divided_by" ("division by zero")`},
205+
}
206+
200207
var filterTestBindings = map[string]any{
201208
"empty_array": []any{},
202209
"empty_map": map[string]any{},
@@ -272,7 +279,14 @@ func TestFilters(t *testing.T) {
272279
t.Run(fmt.Sprintf("%02d", i+1), func(t *testing.T) {
273280
actual, err := expressions.EvaluateString(test.in, context)
274281
require.NoErrorf(t, err, test.in)
275-
require.Equalf(t, test.expected, actual, test.in)
282+
require.EqualValuesf(t, test.expected, actual, test.in)
283+
})
284+
}
285+
286+
for i, test := range filterErrorTests {
287+
t.Run(fmt.Sprintf("%02d", i+len(filterTests)+1), func(t *testing.T) {
288+
_, err := expressions.EvaluateString(test.in, context)
289+
require.EqualErrorf(t, err, test.error, test.in)
276290
})
277291
}
278292
}

0 commit comments

Comments
 (0)