/* NAME amf_test.go DESCRIPTION AMF test suite. AUTHORS Saxon Nelson-Milton Dan Kortschak Alan Noble LICENSE amf_test.go is Copyright (C) 2017-2019 the Australian Ocean Lab (AusOcean) It is free software: you can redistribute it and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with revid in gpl.txt. If not, see http://www.gnu.org/licenses. */ package amf import ( "testing" ) // Test data. var testStrings = [...]string{ "", "foo", "bar", "bazz", } var testNumbers = [...]int32{ 0, 1, 0xababab, 0xffffff, } // TestSanity checks that we haven't accidentally changed constants. func TestSanity(t *testing.T) { if TypeObjectEnd != 0x09 { t.Errorf("TypeObjectEnd has wrong value; got %d, expected %d", TypeObjectEnd, 0x09) } } // TestStrings tests string encoding and decoding. func TestStrings(t *testing.T) { for _, s := range testStrings { // Short string encoding is as follows: // enc[0] = data type (typeString) // end[1:3] = size // enc[3:] = data buf := make([]byte, len(s)+5) _, err := EncodeString(buf, s) if err != nil { t.Errorf("EncodeString failed") } if buf[0] != typeString { t.Errorf("Expected typeString, got %v", buf[0]) } ds := DecodeString(buf[1:]) if s != ds { t.Errorf("DecodeString did not produce original string, got %v", ds) } } } // TestNumbers tests 24-bit encoding and encoding. // We don't test the others as they are just wrappers for standard functions in encoding/binary. func TestNumbers(t *testing.T) { for _, n := range testNumbers { buf := make([]byte, 4) // NB: encoder requires an extra byte for some reason _, err := EncodeInt24(buf, n) if err != nil { t.Errorf("EncodeInt24 failed") } dn := int32(DecodeInt24(buf)) if n != dn { t.Errorf("DecodeInt24 did not produce original Number, got %v", dn) } } } // TestProperties tests encoding and decoding of properties. func TestProperties(t *testing.T) { var buf [1024]byte // Encode/decode Number properties. enc := buf[:] var err error for i, _ := range testNumbers { enc, err = EncodeProperty(&Property{Type: typeNumber, Number: float64(testNumbers[i])}, enc) if err != nil { t.Errorf("EncodeProperty of Number failed") } } prop := Property{} dec := buf[:] for i, _ := range testNumbers { n, err := DecodeProperty(&prop, dec, false) if err != nil { t.Errorf("DecodeProperty of Number failed") } if int32(prop.Number) != testNumbers[i] { t.Errorf("EncodeProperty/DecodeProperty returned wrong Number; got %v, expected %v", int32(prop.Number), testNumbers[i]) } dec = dec[n:] } // Encode/decode string properties. enc = buf[:] for i, _ := range testStrings { enc, err = EncodeProperty(&Property{Type: typeString, String: testStrings[i]}, enc) if err != nil { t.Errorf("EncodeProperty of string failed") } } prop = Property{} dec = buf[:] for i, _ := range testStrings { n, err := DecodeProperty(&prop, dec, false) if err != nil { t.Errorf("DecodeProperty of string failed") } if prop.String != testStrings[i] { t.Errorf("EncodeProperty/DecodeProperty returned wrong string; got %s, expected %s", prop.String, testStrings[i]) } dec = dec[n:] } } // TestObject tests encoding and decoding of objects. func TestObject(t *testing.T) { var buf [1024]byte // Construct a simple object that has one property, the Number 42. prop1 := Property{Type: typeNumber, Number: 42} obj1 := Object{} obj1.Properties = append(obj1.Properties, prop1) // Encode it enc := buf[:] var err error enc, err = Encode(&obj1, enc) if err != nil { t.Errorf("Encode of object failed") } // Check the encoding if uint8(buf[0]) != TypeObject { t.Errorf("Encoded wrong type; expected %d, got %v", TypeObject, uint8(buf[0])) } if uint8(buf[1]) != typeNumber { t.Errorf("Encoded wrong type; expected %d, got %v", typeNumber, uint8(buf[0])) } num := DecodeNumber(buf[2:10]) if num != 42 { t.Errorf("Encoded wrong Number") } end := int32(DecodeInt24(buf[10:13])) if end != TypeObjectEnd { t.Errorf("Did not encode TypeObjectEnd") } // Decode it dec := buf[1:] var dobj1 Object _, err = Decode(&dobj1, dec, false) if err != nil { t.Errorf("Decode of object failed") } // Change the object's property to a boolean. obj1.Properties[0].Type = typeBoolean obj1.Properties[0].Number = 1 // Re-encode it enc = buf[:] enc, err = Encode(&obj1, enc) if err != nil { t.Errorf("Encode of object failed") } // Re-decode it. dec = buf[1:] _, err = Decode(&dobj1, dec, false) if err != nil { t.Errorf("Decode of object failed with error: %v", err) } if dobj1.Properties[0].Number != 1 { t.Errorf("Decoded wrong boolean value") } // Construct a more complicated object that includes a nested object. var obj2 Object for i, _ := range testStrings { obj2.Properties = append(obj2.Properties, Property{Type: typeString, String: testStrings[i]}) obj2.Properties = append(obj2.Properties, Property{Type: typeNumber, Number: float64(testNumbers[i])}) } obj2.Properties = append(obj2.Properties, Property{Type: TypeObject, Object: obj1}) obj2.Properties = append(obj2.Properties, Property{Type: typeBoolean, Number: 1}) // Retrieve nested object obj, err := obj2.ObjectProperty("", 8) if err != err { t.Errorf("Failed to retrieve object") } if len(obj.Properties) < 1 { t.Errorf("Properties missing for nested object") } if obj.Properties[0].Type != typeBoolean { t.Errorf("Wrong property type for nested object") } // Encode it. enc = buf[:] enc, err = Encode(&obj2, enc) if err != nil { t.Errorf("Encode of object failed") } // Decode it. dec = buf[1:] var dobj2 Object _, err = Decode(&dobj2, dec, false) if err != nil { t.Errorf("Decode of object failed with error: %v", err) } // Find some properties that exist. s, err := obj2.StringProperty("", 2) if err != nil { t.Errorf("StringProperty failed") } if s != "foo" { t.Errorf("StringProperty returned wrong String") } n, err := obj2.NumberProperty("", 3) if err != nil { t.Errorf("NumberProperty failed") } if n != 1 { t.Errorf("NumberProperty returned wrong Number") } obj, err = obj2.ObjectProperty("", 8) if err != nil { t.Errorf("ObjectProperty failed") return } if obj.Properties[0].Type != typeBoolean { t.Errorf("ObjectProperty returned object with wrong property") } prop, err := obj2.Property("", 9, typeBoolean) if err != nil { t.Errorf("Property failed") return } if prop.Number != 1 { t.Errorf("Property returned wrong Property") } // Try to find one that doesn't exist. prop, err = obj2.Property("", 10, TypeObject) if err != ErrPropertyNotFound { t.Errorf("Property(10) failed") } }