Skip to content

Commit

Permalink
Add arithematic templating functions
Browse files Browse the repository at this point in the history
  • Loading branch information
tommysitu committed Mar 12, 2024
1 parent 8764a3c commit e8ce758
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 0 deletions.
66 changes: 66 additions & 0 deletions core/templating/template_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package templating
import (
"fmt"
"github.com/SpectoLabs/hoverfly/core/journal"
"math"
"reflect"
"strconv"
"strings"
Expand Down Expand Up @@ -183,6 +184,71 @@ func (t templateHelpers) parseJournalBasedOnIndex(indexName, keyValue, dataSourc
return getEvaluationString("journal", options)
}

func (t templateHelpers) sum(numbers []string, format string) string {
return sumNumbers(numbers, format)
}

func (t templateHelpers) add(val1 string, val2 string, format string) string {
return sumNumbers([]string{val1, val2}, format)
}

func (t templateHelpers) subtract(val1 string, val2 string, format string) string {
f1, err1 := strconv.ParseFloat(val1, 64)
f2, err2 := strconv.ParseFloat(val2, 64)
if err1 != nil || err2 != nil {
return "NaN"
}
return formatNumber(f1-f2, format)
}

func (t templateHelpers) multiply(val1 string, val2 string, format string) string {
f1, err1 := strconv.ParseFloat(val1, 64)
f2, err2 := strconv.ParseFloat(val2, 64)
if err1 != nil || err2 != nil {
return "NaN"
}
return formatNumber(f1*f2, format)
}

func (t templateHelpers) divide(val1 string, val2 string, format string) string {
f1, err1 := strconv.ParseFloat(val1, 64)
f2, err2 := strconv.ParseFloat(val2, 64)
if err1 != nil || err2 != nil {
return "NaN"
}
return formatNumber(f1/f2, format)
}

func sumNumbers(numbers []string, format string) string {
var sum float64 = 0
for _, number := range numbers {
value, err := strconv.ParseFloat(number, 64)
if err != nil {
log.Error(err)
return "NaN"
}
sum += value
}

return formatNumber(sum, format)
}

func formatNumber(number float64, format string) string {
if format == "" {
return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%f", number), "0"), ".")
}

decimalPlaces := 0
parts := strings.Split(format, ".")
if len(parts) == 2 {
decimalPlaces = len(parts[1])
}

multiplier := math.Pow(10, float64(decimalPlaces))
rounded := math.Round(number*multiplier) / multiplier
return fmt.Sprintf("%."+strconv.Itoa(decimalPlaces)+"f", rounded)
}

func getIndexEntry(journalIndexDetails Journal, indexName, indexValue string) (*JournalEntry, error) {

for _, index := range journalIndexDetails.indexes {
Expand Down
5 changes: 5 additions & 0 deletions core/templating/templating.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ func NewTemplator() *Templator {
helperMethodMap["requestBody"] = t.requestBody
helperMethodMap["csv"] = t.parseCsv
helperMethodMap["journal"] = t.parseJournalBasedOnIndex
helperMethodMap["sum"] = t.sum
helperMethodMap["add"] = t.add
helperMethodMap["subtract"] = t.subtract
helperMethodMap["multiply"] = t.multiply
helperMethodMap["divide"] = t.divide
if !helpersRegistered {
raymond.RegisterHelpers(helperMethodMap)
helpersRegistered = true
Expand Down
80 changes: 80 additions & 0 deletions core/templating/templating_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,86 @@ func Test_VarSetToProperValueInCaseOfRequestDetailsPassedAsArgument(t *testing.T

}

func Test_ApplyTemplate_add_integers(t *testing.T) {
RegisterTestingT(t)

template, err := ApplyTemplate(&models.RequestDetails{}, make(map[string]string), `{{ add '1' '2' '0'}}`)

Expect(err).To(BeNil())

Expect(template).To(Equal("3"))
}

func Test_ApplyTemplate_add_floats(t *testing.T) {
RegisterTestingT(t)

template, err := ApplyTemplate(&models.RequestDetails{}, make(map[string]string), `{{ add '0.1' '1.34' '0.00'}}`)

Expect(err).To(BeNil())

Expect(template).To(Equal("1.44"))
}

func Test_ApplyTemplate_add_floats_withRoundUp(t *testing.T) {
RegisterTestingT(t)

template, err := ApplyTemplate(&models.RequestDetails{}, make(map[string]string), `{{ add '0.1' '1.34' '0.0'}} and {{ add '0.1' '1.56' '0.0'}}`)

Expect(err).To(BeNil())

Expect(template).To(Equal("1.4 and 1.7"))
}

func Test_ApplyTemplate_add_number_without_format(t *testing.T) {
RegisterTestingT(t)

template, err := ApplyTemplate(&models.RequestDetails{}, make(map[string]string), `{{ add '0.1' '1.34' ''}} and {{ add '1' '2' ''}} and {{ add '0' '0' ''}}`)

Expect(err).To(BeNil())

Expect(template).To(Equal("1.44 and 3 and 0"))
}

func Test_ApplyTemplate_add_NotNumber(t *testing.T) {
RegisterTestingT(t)

template, err := ApplyTemplate(&models.RequestDetails{}, make(map[string]string), `{{ add 'a' 'b' '0.00'}}`)

Expect(err).To(BeNil())

Expect(template).To(Equal("NaN"))
}

func Test_ApplyTemplate_subtract_numbers(t *testing.T) {
RegisterTestingT(t)

template, err := ApplyTemplate(&models.RequestDetails{}, make(map[string]string), `{{ subtract '10' '0.99' ''}}`)

Expect(err).To(BeNil())

Expect(template).To(Equal("9.01"))
}

func Test_ApplyTemplate_mutiply_numbers(t *testing.T) {
RegisterTestingT(t)

template, err := ApplyTemplate(&models.RequestDetails{}, make(map[string]string), `{{ multiply '10' '0.99' ''}}`)

Expect(err).To(BeNil())

Expect(template).To(Equal("9.9"))
}

func Test_ApplyTemplate_divide_numbers(t *testing.T) {
RegisterTestingT(t)

template, err := ApplyTemplate(&models.RequestDetails{}, make(map[string]string), `{{ divide '10' '2.5' ''}}`)

Expect(err).To(BeNil())

Expect(template).To(Equal("4"))
}

func toInterfaceSlice(arguments []string) []interface{} {
argumentsArray := make([]interface{}, len(arguments))

Expand Down

0 comments on commit e8ce758

Please sign in to comment.