github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/encoding/marshal_test.go (about)

     1  package encoding
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"os"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/NebulousLabs/Sia/build"
    12  )
    13  
    14  // dummy types to test encoding
    15  type (
    16  	// basic
    17  	test0 struct {
    18  		B bool
    19  		I int32
    20  		U uint16
    21  		S string
    22  	}
    23  	// slice/array
    24  	test1 struct {
    25  		Is []int32
    26  		Bs []byte
    27  		Sa [3]string
    28  		Ba [3]byte
    29  	}
    30  	// nested
    31  	test2 struct {
    32  		T test0
    33  	}
    34  	// embedded
    35  	test3 struct {
    36  		test2
    37  	}
    38  	// pointer
    39  	test4 struct {
    40  		P *test1
    41  	}
    42  	// private field -- need to implement MarshalSia/UnmarshalSia
    43  	test5 struct {
    44  		s string
    45  	}
    46  	// private field with pointer receiver
    47  	test6 struct {
    48  		s string
    49  	}
    50  )
    51  
    52  func (t test5) MarshalSia(w io.Writer) error {
    53  	return WritePrefix(w, []byte(t.s))
    54  }
    55  
    56  func (t *test5) UnmarshalSia(r io.Reader) error {
    57  	b, err := ReadPrefix(r, 256)
    58  	t.s = string(b)
    59  	return err
    60  }
    61  
    62  // same as above methods, but with a pointer receiver
    63  func (t *test6) MarshalSia(w io.Writer) error {
    64  	return WritePrefix(w, []byte(t.s))
    65  }
    66  
    67  func (t *test6) UnmarshalSia(r io.Reader) error {
    68  	b, err := ReadPrefix(r, 256)
    69  	t.s = string(b)
    70  	return err
    71  }
    72  
    73  var testStructs = []interface{}{
    74  	test0{false, 65537, 256, "foo"},
    75  	test1{[]int32{1, 2, 3}, []byte("foo"), [3]string{"foo", "bar", "baz"}, [3]byte{'f', 'o', 'o'}},
    76  	test2{test0{false, 65537, 256, "foo"}},
    77  	test3{test2{test0{false, 65537, 256, "foo"}}},
    78  	test4{&test1{[]int32{1, 2, 3}, []byte("foo"), [3]string{"foo", "bar", "baz"}, [3]byte{'f', 'o', 'o'}}},
    79  	test5{"foo"},
    80  	&test6{"foo"},
    81  }
    82  
    83  var testEncodings = [][]byte{
    84  	{0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
    85  	{3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
    86  		0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 3,
    87  		0, 0, 0, 0, 0, 0, 0, 'b', 'a', 'r', 3, 0, 0, 0, 0, 0, 0, 0, 'b', 'a', 'z', 'f', 'o', 'o'},
    88  	{0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
    89  	{0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
    90  	{1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
    91  		0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 3,
    92  		0, 0, 0, 0, 0, 0, 0, 'b', 'a', 'r', 3, 0, 0, 0, 0, 0, 0, 0, 'b', 'a', 'z', 'f', 'o', 'o'},
    93  	{3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
    94  	{3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
    95  }
    96  
    97  // TestEncode tests the Encode function.
    98  func TestEncode(t *testing.T) {
    99  	// use Marshal for convenience
   100  	for i := range testStructs {
   101  		b := Marshal(testStructs[i])
   102  		if !bytes.Equal(b, testEncodings[i]) {
   103  			t.Errorf("bad encoding of testStructs[%d]: \nexp:\t%v\ngot:\t%v", i, testEncodings[i], b)
   104  		}
   105  	}
   106  
   107  	// badWriter should fail on every encode
   108  	enc := NewEncoder(new(badWriter))
   109  	for i := range testStructs {
   110  		err := enc.Encode(testStructs[i])
   111  		if err != io.ErrShortWrite {
   112  			t.Errorf("testStructs[%d]: expected ErrShortWrite, got %v", i, err)
   113  		}
   114  	}
   115  	// special case, not covered by testStructs
   116  	err := enc.Encode(struct{ U [3]uint16 }{[3]uint16{1, 2, 3}})
   117  	if err != io.ErrShortWrite {
   118  		t.Error("expected ErrShortWrite, got", err)
   119  	}
   120  
   121  	// bad type
   122  	defer func() {
   123  		if recover() == nil {
   124  			t.Error("expected panic, got nil")
   125  		}
   126  	}()
   127  	enc.Encode(map[int]int{})
   128  }
   129  
   130  // TestDecode tests the Decode function.
   131  func TestDecode(t *testing.T) {
   132  	if testing.Short() {
   133  		t.SkipNow()
   134  	}
   135  	// use Unmarshal for convenience
   136  	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
   137  	for i := range testEncodings {
   138  		err := Unmarshal(testEncodings[i], emptyStructs[i])
   139  		if err != nil {
   140  			t.Error(err)
   141  		}
   142  	}
   143  
   144  	// bad boolean
   145  	err := Unmarshal([]byte{3}, new(bool))
   146  	if err == nil || err.Error() != "could not decode type bool: boolean value was not 0 or 1" {
   147  		t.Error("expected bool error, got", err)
   148  	}
   149  
   150  	// non-pointer
   151  	err = Unmarshal([]byte{1, 2, 3}, "foo")
   152  	if err != errBadPointer {
   153  		t.Error("expected errBadPointer, got", err)
   154  	}
   155  
   156  	// unknown type
   157  	err = Unmarshal([]byte{1, 2, 3}, new(map[int]int))
   158  	if err == nil || err.Error() != "could not decode type map[int]int: unknown type" {
   159  		t.Error("expected unknown type error, got", err)
   160  	}
   161  
   162  	// big slice (larger than maxSliceLen)
   163  	err = Unmarshal(EncUint64(maxSliceLen+1), new([]byte))
   164  	if err == nil || err.Error() != "could not decode type []uint8: slice is too large" {
   165  		t.Error("expected large slice error, got", err)
   166  	}
   167  
   168  	// massive slice (larger than MaxInt32)
   169  	err = Unmarshal(EncUint64(1<<32), new([]byte))
   170  	if err == nil || err.Error() != "could not decode type []uint8: slice is too large" {
   171  		t.Error("expected large slice error, got", err)
   172  	}
   173  
   174  	// many small slices (total larger than maxDecodeLen)
   175  	bigSlice := strings.Split(strings.Repeat("0123456789abcdefghijklmnopqrstuvwxyz", (maxSliceLen/16)-1), "0")
   176  	err = Unmarshal(Marshal(bigSlice), new([]string))
   177  	if err == nil || err.Error() != "could not decode type []string: encoded type exceeds size limit" {
   178  		t.Error("expected size limit error, got", err)
   179  	}
   180  
   181  	// badReader should fail on every decode
   182  	dec := NewDecoder(new(badReader))
   183  	for i := range testEncodings {
   184  		err := dec.Decode(emptyStructs[i])
   185  		if err == nil {
   186  			t.Error("expected error, got nil")
   187  		}
   188  	}
   189  	// special case, not covered by testStructs
   190  	err = dec.Decode(new([3]byte))
   191  	if err == nil || err.Error() != "could not decode type [3]uint8: EOF" {
   192  		t.Error("expected EOF error, got", err)
   193  	}
   194  
   195  }
   196  
   197  // TestMarshalUnmarshal tests the Marshal and Unmarshal functions, which are
   198  // inverses of each other.
   199  func TestMarshalUnmarshal(t *testing.T) {
   200  	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
   201  	for i := range testStructs {
   202  		b := Marshal(testStructs[i])
   203  		err := Unmarshal(b, emptyStructs[i])
   204  		if err != nil {
   205  			t.Error(err)
   206  		}
   207  	}
   208  }
   209  
   210  // TestEncodeDecode tests the Encode and Decode functions, which are inverses
   211  // of each other.
   212  func TestEncodeDecode(t *testing.T) {
   213  	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
   214  	b := new(bytes.Buffer)
   215  	enc := NewEncoder(b)
   216  	dec := NewDecoder(b)
   217  	for i := range testStructs {
   218  		enc.Encode(testStructs[i])
   219  		err := dec.Decode(emptyStructs[i])
   220  		if err != nil {
   221  			t.Error(err)
   222  		}
   223  	}
   224  }
   225  
   226  // TestEncodeAll tests the EncodeAll function.
   227  func TestEncodeAll(t *testing.T) {
   228  	// EncodeAll should produce the same result as individually encoding each
   229  	// object
   230  	exp := new(bytes.Buffer)
   231  	enc := NewEncoder(exp)
   232  	for i := range testStructs {
   233  		enc.Encode(testStructs[i])
   234  	}
   235  
   236  	b := new(bytes.Buffer)
   237  	NewEncoder(b).EncodeAll(testStructs...)
   238  	if !bytes.Equal(b.Bytes(), exp.Bytes()) {
   239  		t.Errorf("expected %v, got %v", exp.Bytes(), b.Bytes())
   240  	}
   241  
   242  	// hardcoded check
   243  	exp.Reset()
   244  	exp.Write([]byte{1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 1})
   245  
   246  	b.Reset()
   247  	NewEncoder(b).EncodeAll(1, 2, "foo", true)
   248  	if !bytes.Equal(b.Bytes(), exp.Bytes()) {
   249  		t.Errorf("expected %v, got %v", exp.Bytes(), b.Bytes())
   250  	}
   251  }
   252  
   253  // TestDecodeAll tests the DecodeAll function.
   254  func TestDecodeAll(t *testing.T) {
   255  	b := new(bytes.Buffer)
   256  	NewEncoder(b).EncodeAll(testStructs...)
   257  
   258  	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
   259  	err := NewDecoder(b).DecodeAll(emptyStructs...)
   260  	if err != nil {
   261  		t.Error(err)
   262  	}
   263  	empty0 := *emptyStructs[0].(*test0)
   264  	if !reflect.DeepEqual(empty0, testStructs[0]) {
   265  		t.Error("deep equal:", empty0, testStructs[0])
   266  	}
   267  	empty6 := emptyStructs[6].(*test6)
   268  	if !reflect.DeepEqual(empty6, testStructs[6]) {
   269  		t.Error("deep equal:", empty6, testStructs[6])
   270  	}
   271  
   272  	// hardcoded check
   273  	b.Reset()
   274  	b.Write([]byte{1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 1})
   275  
   276  	var (
   277  		one, two uint64
   278  		foo      string
   279  		tru      bool
   280  	)
   281  	err = NewDecoder(b).DecodeAll(&one, &two, &foo, &tru)
   282  	if err != nil {
   283  		t.Fatal(err)
   284  	} else if one != 1 || two != 2 || foo != "foo" || tru != true {
   285  		t.Error("values were not decoded correctly:", one, two, foo, tru)
   286  	}
   287  }
   288  
   289  // TestMarshalAll tests the MarshalAll function.
   290  func TestMarshalAll(t *testing.T) {
   291  	// MarshalAll should produce the same result as individually marshalling
   292  	// each object
   293  	var expected []byte
   294  	for i := range testStructs {
   295  		expected = append(expected, Marshal(testStructs[i])...)
   296  	}
   297  
   298  	b := MarshalAll(testStructs...)
   299  	if !bytes.Equal(b, expected) {
   300  		t.Errorf("expected %v, got %v", expected, b)
   301  	}
   302  
   303  	// hardcoded check
   304  	exp := []byte{1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 1}
   305  	b = MarshalAll(1, 2, "foo", true)
   306  	if !bytes.Equal(b, exp) {
   307  		t.Errorf("expected %v, got %v", exp, b)
   308  	}
   309  }
   310  
   311  // TestUnmarshalAll tests the UnmarshalAll function.
   312  func TestUnmarshalAll(t *testing.T) {
   313  	b := MarshalAll(testStructs...)
   314  
   315  	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
   316  	err := UnmarshalAll(b, emptyStructs...)
   317  	if err != nil {
   318  		t.Error(err)
   319  	}
   320  	empty1 := *emptyStructs[1].(*test1)
   321  	if !reflect.DeepEqual(empty1, testStructs[1]) {
   322  		t.Error("deep equal:", empty1, testStructs[1])
   323  	}
   324  	empty5 := *emptyStructs[5].(*test5)
   325  	if !reflect.DeepEqual(empty5, testStructs[5]) {
   326  		t.Error("deep equal:", empty5, testStructs[5])
   327  	}
   328  
   329  	// hardcoded check
   330  	b = []byte{1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 1}
   331  	var (
   332  		one, two uint64
   333  		foo      string
   334  		tru      bool
   335  	)
   336  	err = UnmarshalAll(b, &one, &two, &foo, &tru)
   337  	if err != nil {
   338  		t.Fatal(err)
   339  	} else if one != 1 || two != 2 || foo != "foo" || tru != true {
   340  		t.Error("values were not decoded correctly:", one, two, foo, tru)
   341  	}
   342  }
   343  
   344  // TestReadWriteFile tests the ReadFiles and WriteFile functions, which are
   345  // inverses of each other.
   346  func TestReadWriteFile(t *testing.T) {
   347  	// standard
   348  	os.MkdirAll(build.TempDir("encoding"), 0777)
   349  	path := build.TempDir("encoding", "TestReadWriteFile")
   350  	err := WriteFile(path, testStructs[3])
   351  	if err != nil {
   352  		t.Fatal(err)
   353  	}
   354  
   355  	var obj test4
   356  	err = ReadFile(path, &obj)
   357  	if err != nil {
   358  		t.Error(err)
   359  	}
   360  
   361  	// bad paths
   362  	err = WriteFile("/foo/bar", "baz")
   363  	if err == nil {
   364  		t.Error("expected error, got nil")
   365  	}
   366  	err = ReadFile("/foo/bar", nil)
   367  	if err == nil {
   368  		t.Error("expected error, got nil")
   369  	}
   370  }
   371  
   372  // i5-4670K, 9a90f86: 33 MB/s
   373  func BenchmarkEncode(b *testing.B) {
   374  	buf := new(bytes.Buffer)
   375  	enc := NewEncoder(buf)
   376  	for i := 0; i < b.N; i++ {
   377  		buf.Reset()
   378  		for i := range testStructs {
   379  			err := enc.Encode(testStructs[i])
   380  			if err != nil {
   381  				b.Fatal(err)
   382  			}
   383  		}
   384  	}
   385  	b.SetBytes(int64(buf.Len()))
   386  }
   387  
   388  // i5-4670K, 9a90f86: 26 MB/s
   389  func BenchmarkDecode(b *testing.B) {
   390  	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
   391  	var numBytes int64
   392  	for i := 0; i < b.N; i++ {
   393  		numBytes = 0
   394  		for i := range testEncodings {
   395  			err := Unmarshal(testEncodings[i], emptyStructs[i])
   396  			if err != nil {
   397  				b.Fatal(err)
   398  			}
   399  			numBytes += int64(len(testEncodings[i]))
   400  		}
   401  	}
   402  	b.SetBytes(numBytes)
   403  }