Files
go-enum/example/example_test.go

275 lines
6.8 KiB
Go

//go:build example
// +build example
package example
import (
"encoding/json"
"errors"
"flag"
"fmt"
"strings"
"testing"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type makeTest struct {
M Make `json:"make"`
}
func TestMake(t *testing.T) {
assert.Equal(t, "Ford", MakeFord.String())
assert.Equal(t, "Make(99)", Make(99).String())
ford := MakeFord
assert.Implements(t, (*flag.Value)(nil), &ford)
assert.Implements(t, (*flag.Getter)(nil), &ford)
assert.Implements(t, (*pflag.Value)(nil), &ford)
names := MakeNames()
assert.Len(t, names, 11)
}
var makeTests = []struct {
name string
input string
output *makeTest
errorExpected bool
err error
caseChanged bool
}{
{
name: "toyota",
input: `{"make":"Toyota"}`,
output: &makeTest{M: MakeToyota},
errorExpected: false,
err: nil,
},
{
name: "chevy",
input: `{"make":"Chevy"}`,
output: &makeTest{M: MakeChevy},
errorExpected: false,
err: nil,
},
{
name: "ford",
input: `{"make":"Ford"}`,
output: &makeTest{M: MakeFord},
errorExpected: false,
err: nil,
},
{
name: "tesla",
input: `{"make":"Tesla"}`,
output: &makeTest{M: MakeTesla},
errorExpected: false,
err: nil,
},
{
name: "hyundai",
input: `{"make":"Hyundai"}`,
output: &makeTest{M: MakeHyundai},
errorExpected: false,
err: nil,
},
{
name: "nissan",
input: `{"make":"Nissan"}`,
output: &makeTest{M: MakeNissan},
errorExpected: false,
err: nil,
},
{
name: "jaguar",
input: `{"make":"Jaguar"}`,
output: &makeTest{M: MakeJaguar},
errorExpected: false,
err: nil,
},
{
name: "audi",
input: `{"make":"Audi"}`,
output: &makeTest{M: MakeAudi},
errorExpected: false,
err: nil,
},
{
name: "AUDI",
input: `{"make":"AUDI"}`,
output: &makeTest{M: MakeAudi},
errorExpected: false,
err: nil,
caseChanged: true,
},
{
name: "bmw",
input: `{"make":"BMW"}`,
output: &makeTest{M: MakeBMW},
errorExpected: false,
err: nil,
},
{
name: "mercedes",
input: `{"make":"Mercedes-Benz"}`,
output: &makeTest{M: MakeMercedesBenz},
errorExpected: false,
err: nil,
},
{
name: "volkswagon",
input: `{"make":"Volkswagon"}`,
output: &makeTest{M: MakeVolkswagon},
errorExpected: false,
err: nil,
},
{
name: "porsche",
input: `{"make":"Porsche"}`,
output: &makeTest{M: MakeVolkswagon},
errorExpected: true,
err: errors.New("Porsche is not a valid Make, try [Toyota, Chevy, Ford, Tesla, Hyundai, Nissan, Jaguar, Audi, BMW, Mercedes-Benz, Volkswagon]"),
},
}
func TestMakeUnmarshal(t *testing.T) {
for _, test := range makeTests {
t.Run(test.name, func(tt *testing.T) {
x := &makeTest{}
err := json.Unmarshal([]byte(test.input), x)
if !test.errorExpected {
require.NoError(tt, err, "failed unmarshalling the json.")
assert.Equal(tt, test.output.M, x.M)
// Values won't be exactly the same, so we just validate that it was unmarshalled correctly.
if !test.caseChanged {
// Marshal back
raw, err := json.Marshal(test.output)
require.NoError(tt, err, "failed marshalling back to json")
require.JSONEq(tt, test.input, string(raw), "json didn't match")
}
} else {
require.Error(tt, err)
assert.EqualError(tt, err, test.err.Error())
}
})
}
}
func TestFlagInterface(t *testing.T) {
for _, test := range makeTests {
t.Run(test.name, func(tt *testing.T) {
if test.output != nil {
var tmp Make
m := &tmp
require.Equal(tt, m.Type(), "Make")
require.Equal(tt, Make(0), m.Get(), "Unset value should be default")
require.NoError(tt, m.Set(test.output.M.String()), "failed setting flag value")
}
})
}
}
func TestNoZeroValues(t *testing.T) {
t.Run("base", func(tt *testing.T) {
assert.Equal(tt, 20, int(NoZerosStart))
assert.Equal(tt, 21, int(NoZerosMiddle))
assert.Equal(tt, 22, int(NoZerosEnd))
assert.Equal(tt, 23, int(NoZerosPs))
assert.Equal(tt, 24, int(NoZerosPps))
assert.Equal(tt, 25, int(NoZerosPpps))
assert.Equal(tt, "ppps", NoZerosPpps.String())
assert.Equal(tt, "NoZeros(4)", NoZeros(4).String())
assert.Len(tt, NoZerosNames(), 6)
_, err := ParseNoZeros("pppps")
assert.EqualError(tt, err, "pppps is not a valid NoZeros, try [start, middle, end, ps, pps, ppps]")
tmp, _ := ParseNoZeros("ppps")
assert.Equal(tt, NoZerosPpps, tmp)
tmp, _ = ParseNoZeros("PppS")
assert.Equal(tt, NoZerosPpps, tmp)
val := map[string]*NoZeros{}
err = json.Unmarshal([]byte(`{"nz":"pppps"}`), &val)
assert.EqualError(tt, err, "pppps is not a valid NoZeros, try [start, middle, end, ps, pps, ppps]")
})
for _, name := range NoZerosNames() {
t.Run(name, func(tt *testing.T) {
val := map[string]*NoZeros{}
rawJSON := fmt.Sprintf(`{"val":"%s"}`, name)
require.NoError(tt, json.Unmarshal([]byte(rawJSON), &val), "Failed unmarshalling no zero")
marshalled, err := json.Marshal(val)
require.NoError(tt, err, "failed marshalling back to json")
require.JSONEq(tt, rawJSON, string(marshalled), "marshalled json did not match")
// Flag
var tmp NoZeros
nz := &tmp
require.Equal(tt, nz.Type(), "NoZeros")
require.Equal(tt, NoZeros(0), nz.Get(), "Unset value should be default")
require.NoError(tt, nz.Set(name), "failed setting flag value")
})
}
}
func BenchmarkMakeParse(b *testing.B) {
knownItems := map[string]struct {
input string
output Make
err error
}{
"cased lookup": {
input: MakeAudi.String(),
output: MakeAudi,
},
"lowercase lookup": {
input: strings.ToLower(MakeVolkswagon.String()),
output: MakeVolkswagon,
},
"hyphenated upper": {
input: strings.ToUpper(MakeMercedesBenz.String()),
output: MakeMercedesBenz,
},
// Leave this in to add an int as string parsing option in future.
// "numeric": {
// input: "2",
// output: MakeChevy,
// },
// "last numeric": {
// input: "20",
// output: MakeVolkswagon,
// },
"failure": {
input: "xyz",
output: MakeToyota,
err: errors.New("xyz is not a valid Make, try [Toyota, Chevy, Ford, Tesla, Hyundai, Nissan, Jaguar, Audi, BMW, Mercedes-Benz, Volkswagon]"),
},
}
for name, tc := range knownItems {
b.Run(name, func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
out, err := ParseMake(tc.input)
assert.Equal(b, tc.output, out)
if tc.err != nil {
assert.Error(b, err)
} else {
assert.NoError(b, err)
}
}
})
}
}