package binary import ( "bytes" "reflect" "testing" "time" ) type SimpleStruct struct { String string Bytes []byte Time time.Time } //------------------------------------- type Animal interface{} const ( AnimalTypeCat = byte(0x01) AnimalTypeDog = byte(0x02) AnimalTypeSnake = byte(0x03) AnimalTypeViper = byte(0x04) ) // Implements Animal type Cat struct { SimpleStruct } func (cat Cat) TypeByte() byte { return AnimalTypeCat } // Implements Animal type Dog struct { SimpleStruct } func (dog Dog) TypeByte() byte { return AnimalTypeDog } // Implements Animal type Snake []byte func (snake Snake) TypeByte() byte { return AnimalTypeSnake } // Implements Animal type Viper struct { Bytes []byte } func (viper *Viper) TypeByte() byte { return AnimalTypeViper } var _ = RegisterInterface( struct{ Animal }{}, ConcreteType{Cat{}}, ConcreteType{Dog{}}, ConcreteType{Snake{}}, ConcreteType{&Viper{}}, ) //------------------------------------- type Constructor func() interface{} type Instantiator func() (o interface{}, ptr interface{}) type Validator func(o interface{}, t *testing.T) type TestCase struct { Constructor Instantiator Validator } //------------------------------------- func constructBasic() interface{} { cat := Cat{ SimpleStruct{ String: "String", Bytes: []byte("Bytes"), Time: time.Unix(123, 0), }, } return cat } func instantiateBasic() (interface{}, interface{}) { return Cat{}, &Cat{} } func validateBasic(o interface{}, t *testing.T) { cat := o.(Cat) if cat.String != "String" { t.Errorf("Expected cat2.String == 'String', got %v", cat.String) } if string(cat.Bytes) != "Bytes" { t.Errorf("Expected cat2.Bytes == 'Bytes', got %X", cat.Bytes) } if cat.Time.Unix() != 123 { t.Errorf("Expected cat2.Time == 'Unix(123)', got %v", cat.Time) } } //------------------------------------- type ComplexStruct struct { Name string Animal Animal } func constructComplex() interface{} { c := ComplexStruct{ Name: "Complex", Animal: constructBasic(), } return c } func instantiateComplex() (interface{}, interface{}) { return ComplexStruct{}, &ComplexStruct{} } func validateComplex(o interface{}, t *testing.T) { c2 := o.(ComplexStruct) if cat, ok := c2.Animal.(Cat); ok { validateBasic(cat, t) } else { t.Errorf("Expected c2.Animal to be of type cat, got %v", reflect.ValueOf(c2.Animal).Elem().Type()) } } //------------------------------------- type ComplexStruct2 struct { Cat Cat Dog *Dog Snake Snake Snake2 *Snake Viper Viper Viper2 *Viper } func constructComplex2() interface{} { snake_ := Snake([]byte("hiss")) snakePtr_ := &snake_ c := ComplexStruct2{ Cat: Cat{ SimpleStruct{ String: "String", Bytes: []byte("Bytes"), }, }, Dog: &Dog{ SimpleStruct{ String: "Woof", Bytes: []byte("Bark"), }, }, Snake: Snake([]byte("hiss")), Snake2: snakePtr_, Viper: Viper{Bytes: []byte("hizz")}, Viper2: &Viper{Bytes: []byte("hizz")}, } return c } func instantiateComplex2() (interface{}, interface{}) { return ComplexStruct2{}, &ComplexStruct2{} } func validateComplex2(o interface{}, t *testing.T) { c2 := o.(ComplexStruct2) cat := c2.Cat if cat.String != "String" { t.Errorf("Expected cat.String == 'String', got %v", cat.String) } if string(cat.Bytes) != "Bytes" { t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes) } dog := c2.Dog if dog.String != "Woof" { t.Errorf("Expected dog.String == 'Woof', got %v", dog.String) } if string(dog.Bytes) != "Bark" { t.Errorf("Expected dog.Bytes == 'Bark', got %X", dog.Bytes) } snake := c2.Snake if string(snake) != "hiss" { t.Errorf("Expected string(snake) == 'hiss', got %v", string(snake)) } snake2 := c2.Snake2 if string(*snake2) != "hiss" { t.Errorf("Expected string(snake2) == 'hiss', got %v", string(*snake2)) } viper := c2.Viper if string(viper.Bytes) != "hizz" { t.Errorf("Expected string(viper.Bytes) == 'hizz', got %v", string(viper.Bytes)) } viper2 := c2.Viper2 if string(viper2.Bytes) != "hizz" { t.Errorf("Expected string(viper2.Bytes) == 'hizz', got %v", string(viper2.Bytes)) } } //------------------------------------- type ComplexStructArray struct { Animals []Animal } func constructComplexArray() interface{} { c := ComplexStructArray{ Animals: []Animal{ Cat{ SimpleStruct{ String: "String", Bytes: []byte("Bytes"), }, }, &Dog{ // Even though it's a *Dog, we'll get a Dog{} back. SimpleStruct{ String: "Woof", Bytes: []byte("Bark"), }, }, Snake([]byte("hiss")), &Viper{ Bytes: []byte("hizz"), }, }, } return c } func instantiateComplexArray() (interface{}, interface{}) { return ComplexStructArray{}, &ComplexStructArray{} } func validateComplexArray(o interface{}, t *testing.T) { c2 := o.(ComplexStructArray) if cat, ok := c2.Animals[0].(Cat); ok { if cat.String != "String" { t.Errorf("Expected cat.String == 'String', got %v", cat.String) } if string(cat.Bytes) != "Bytes" { t.Errorf("Expected cat.Bytes == 'Bytes', got %X", cat.Bytes) } } else { t.Errorf("Expected c2.Animals[0] to be of type cat, got %v", reflect.ValueOf(c2.Animals[0]).Elem().Type()) } if dog, ok := c2.Animals[1].(Dog); ok { if dog.String != "Woof" { t.Errorf("Expected dog.String == 'Woof', got %v", dog.String) } if string(dog.Bytes) != "Bark" { t.Errorf("Expected dog.Bytes == 'Bark', got %X", dog.Bytes) } } else { t.Errorf("Expected c2.Animals[1] to be of type dog, got %v", reflect.ValueOf(c2.Animals[1]).Elem().Type()) } if snake, ok := c2.Animals[2].(Snake); ok { if string(snake) != "hiss" { t.Errorf("Expected string(snake) == 'hiss', got %v", string(snake)) } } else { t.Errorf("Expected c2.Animals[2] to be of type Snake, got %v", reflect.ValueOf(c2.Animals[2]).Elem().Type()) } if viper, ok := c2.Animals[3].(*Viper); ok { if string(viper.Bytes) != "hizz" { t.Errorf("Expected string(viper.Bytes) == 'hizz', got %v", string(viper.Bytes)) } } else { t.Errorf("Expected c2.Animals[3] to be of type *Viper, got %v", reflect.ValueOf(c2.Animals[3]).Elem().Type()) } } //----------------------------------------------------------------------------- var testCases = []TestCase{} func init() { testCases = append(testCases, TestCase{constructBasic, instantiateBasic, validateBasic}) testCases = append(testCases, TestCase{constructComplex, instantiateComplex, validateComplex}) testCases = append(testCases, TestCase{constructComplex2, instantiateComplex2, validateComplex2}) testCases = append(testCases, TestCase{constructComplexArray, instantiateComplexArray, validateComplexArray}) } func TestBinary(t *testing.T) { for _, testCase := range testCases { // Construct an object o := testCase.Constructor() // Write the object data := BinaryBytes(o) t.Logf("Binary: %X", data) instance, instancePtr := testCase.Instantiator() // Read onto a struct n, err := new(int64), new(error) res := ReadBinary(instance, bytes.NewReader(data), n, err) if *err != nil { t.Fatalf("Failed to read cat: %v", *err) } // Validate object testCase.Validator(res, t) // Read onto a pointer n, err = new(int64), new(error) res = ReadBinary(instancePtr, bytes.NewReader(data), n, err) if *err != nil { t.Fatalf("Failed to read cat: %v", *err) } if res != instancePtr { t.Errorf("Expected pointer to pass through") } // Validate object testCase.Validator(reflect.ValueOf(res).Elem().Interface(), t) } } func TestJSON(t *testing.T) { for _, testCase := range testCases { // Construct an object o := testCase.Constructor() // Write the object data := JSONBytes(o) t.Logf("JSON: %v", string(data)) instance, instancePtr := testCase.Instantiator() // Read onto a struct err := new(error) res := ReadJSON(instance, data, err) if *err != nil { t.Fatalf("Failed to read cat: %v", *err) } // Validate object testCase.Validator(res, t) // Read onto a pointer res = ReadJSON(instancePtr, data, err) if *err != nil { t.Fatalf("Failed to read cat: %v", *err) } if res != instancePtr { t.Errorf("Expected pointer to pass through") } // Validate object testCase.Validator(reflect.ValueOf(res).Elem().Interface(), t) } }