mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Creates a test that aims to assert that the Equals and Clone functions for our three entity structs actually work. The bulk of the code is spent creating gopter generators for the entities. See information of generative or property based testing for explainations on that topic, but basically it's an object that is capable of creating a stream of unique instances of the given struct. With the generator we then make three assertions: 1) Entities are always equal to themselves. 2) A .Clone() of an entity is Equal to the original entity. 3) A .Clone() of an entity that has a field modified is not equal to the orignal. The third property is the worse for implementation, as it does not generate the field to modify, it simply loops all fields for each generated entity, and checks Equals always breaks. Break testing shows that this would have caught earlier bugs in Equals due to field addition. It will add to the work to add further fields, generators have to be manually specified for each field, but that seems a worthy cost.
150 lines
4.0 KiB
Go
150 lines
4.0 KiB
Go
package models
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/leanovate/gopter"
|
|
"github.com/leanovate/gopter/gen"
|
|
"github.com/leanovate/gopter/prop"
|
|
)
|
|
|
|
var openEmptyJSON = `{"id":"","name":"","app_id":"","fn_id":"","created_at":"0001-01-01T00:00:00.000Z","updated_at":"0001-01-01T00:00:00.000Z","type":"","source":""`
|
|
|
|
var triggerJSONCases = []struct {
|
|
val *Trigger
|
|
valString string
|
|
}{
|
|
{val: &Trigger{}, valString: openEmptyJSON + "}"},
|
|
}
|
|
|
|
func TestTriggerJsonMarshalling(t *testing.T) {
|
|
for _, tc := range triggerJSONCases {
|
|
v, err := json.Marshal(tc.val)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal json into %s: %v", tc.valString, err)
|
|
}
|
|
if string(v) != tc.valString {
|
|
t.Errorf("Invalid trigger value, expected %s, got %s", tc.valString, string(v))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTriggerListJsonMarshalling(t *testing.T) {
|
|
emptyList := &TriggerList{Items: []*Trigger{}}
|
|
expected := "{\"items\":[]}"
|
|
|
|
v, err := json.Marshal(emptyList)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal json into %s: %v", expected, err)
|
|
}
|
|
if string(v) != expected {
|
|
t.Errorf("Invalid trigger value, expected %s, got %s", expected, string(v))
|
|
}
|
|
}
|
|
|
|
var httpTrigger = &Trigger{Name: "name", AppID: "foo", FnID: "bar", Type: "http", Source: "baz"}
|
|
var invalidTrigger = &Trigger{Name: "name", AppID: "foo", FnID: "bar", Type: "error", Source: "baz"}
|
|
|
|
var triggerValidateCases = []struct {
|
|
val *Trigger
|
|
valid bool
|
|
}{
|
|
{val: &Trigger{}, valid: false},
|
|
{val: invalidTrigger, valid: false},
|
|
{val: httpTrigger, valid: true},
|
|
}
|
|
|
|
func TestTriggerValidate(t *testing.T) {
|
|
for _, tc := range triggerValidateCases {
|
|
v := tc.val.Validate()
|
|
if v != nil && tc.valid {
|
|
t.Errorf("Expected Trigger to be valid, but err (%s) returned. Trigger: %#v", v, tc.val)
|
|
}
|
|
if v == nil && !tc.valid {
|
|
t.Errorf("Expected Trigger to be invalid, but no err returned. Trigger: %#v", tc.val)
|
|
}
|
|
}
|
|
}
|
|
|
|
func triggerReflectType() reflect.Type {
|
|
trigger := Trigger{}
|
|
return reflect.TypeOf(trigger)
|
|
}
|
|
|
|
func triggerFieldGenerators(t *testing.T) map[string]gopter.Gen {
|
|
fieldGens := make(map[string]gopter.Gen)
|
|
fieldGens["ID"] = gen.AlphaString()
|
|
fieldGens["Name"] = gen.AlphaString()
|
|
fieldGens["AppID"] = gen.AlphaString()
|
|
fieldGens["FnID"] = gen.AlphaString()
|
|
fieldGens["CreatedAt"] = datetimeGenerator()
|
|
fieldGens["UpdatedAt"] = datetimeGenerator()
|
|
fieldGens["Type"] = gen.AlphaString()
|
|
fieldGens["Source"] = gen.AlphaString()
|
|
fieldGens["Annotations"] = annotationGenerator()
|
|
|
|
triggerFieldCount := triggerReflectType().NumField()
|
|
|
|
if triggerFieldCount != len(fieldGens) {
|
|
t.Fatalf("Trigger struct field count, %d, does not match trigger generator field count, %d", triggerFieldCount, len(fieldGens))
|
|
}
|
|
|
|
return fieldGens
|
|
}
|
|
|
|
func triggerGenerator(t *testing.T) gopter.Gen {
|
|
return gen.Struct(triggerReflectType(), triggerFieldGenerators(t))
|
|
}
|
|
|
|
func TestTriggerEquality(t *testing.T) {
|
|
properties := gopter.NewProperties(nil)
|
|
|
|
properties.Property("A trigger should always equal itself", prop.ForAll(
|
|
func(trigger Trigger) bool {
|
|
return trigger.Equals(&trigger)
|
|
},
|
|
triggerGenerator(t),
|
|
))
|
|
|
|
properties.Property("A trigger should always equal a clone of itself", prop.ForAll(
|
|
func(trigger Trigger) bool {
|
|
clone := trigger.Clone()
|
|
return trigger.Equals(clone)
|
|
},
|
|
triggerGenerator(t),
|
|
))
|
|
|
|
triggerFieldGens := triggerFieldGenerators(t)
|
|
|
|
properties.Property("A trigger should never match a modified version of itself", prop.ForAll(
|
|
func(trigger Trigger) bool {
|
|
for fieldName, fieldGen := range triggerFieldGens {
|
|
|
|
if fieldName == "CreatedAt" ||
|
|
fieldName == "UpdatedAt" {
|
|
continue
|
|
}
|
|
|
|
currentValue, newValue := novelValue(t, reflect.ValueOf(trigger), fieldName, fieldGen)
|
|
|
|
clone := trigger.Clone()
|
|
s := reflect.ValueOf(clone).Elem()
|
|
field := s.FieldByName(fieldName)
|
|
|
|
field.Set(newValue)
|
|
|
|
if trigger.Equals(clone) {
|
|
t.Errorf("Changed field, %s, from {%v} to {%v}, but still equal.", fieldName, currentValue, newValue)
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
},
|
|
triggerGenerator(t),
|
|
))
|
|
|
|
properties.TestingRun(t)
|
|
}
|