package msgpack_test

import (
	. "msgpack"
	"testing"
	"bytes"
	"reflect"
	"math"
)

func equal(lhs reflect.Value, rhs reflect.Value) bool {
	{
		_rhs := rhs
		if _rhs.Kind() == reflect.Interface {
			return equal(lhs, _rhs.Elem())
		}
	}
	switch _lhs := lhs; _lhs.Kind() {
	case reflect.Interface:
		return equal(_lhs.Elem(), rhs)
	case reflect.Bool:
		_rhs := rhs
		return _rhs.Kind() == reflect.Bool &&
			_lhs.Bool() == _rhs.Bool()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		_rhs := rhs
		return (_rhs.Kind() == reflect.Uint || _rhs.Kind() == reflect.Uint8 || _rhs.Kind() == reflect.Uint16 || _rhs.Kind() == reflect.Uint32 || _rhs.Kind() == reflect.Uint64 || _rhs.Kind() == reflect.Uintptr) &&
			_lhs.Uint() == _rhs.Uint()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		_rhs := rhs
		return (_rhs.Kind() == reflect.Int || _rhs.Kind() == reflect.Int8 || _rhs.Kind() == reflect.Int16 || _rhs.Kind() == reflect.Int32 || _rhs.Kind() == reflect.Int64) &&
			_lhs.Int() == _rhs.Int()
	case reflect.Float32, reflect.Float64:
		_rhs := rhs
		return (_rhs.Kind() == reflect.Float32 || _rhs.Kind() == reflect.Float64) &&
			_lhs.Float() == _rhs.Float()
	case reflect.Array, reflect.Slice:
		_rhs := rhs
		if _lhs.Len() != _rhs.Len() {
			return false
		}
		for i := 0; i < _lhs.Len(); i++ {
			if !equal(_lhs.Index(i), _rhs.Index(i)) {
				return false
			}
		}
		return true
	case reflect.Map:
		_rhs := rhs
		if _lhs.Len() != _rhs.Len() {
			return false
		}
		for _, k := range _lhs.MapKeys() {
			lv, rv := _lhs.MapIndex(k), _rhs.MapIndex(k)
			if !lv.IsValid() || !rv.IsValid() || !equal(lv, rv) {
				return false
			}
		}
		return true
	}
	return false
}

func TestPackUint8(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range []uint8{0, 1, 2, 125, 126, 127, 128, 253, 254, 255} {
		_, err := PackUint8(b, i)
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackUint16(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range []uint16{0, 1, 2, 125, 126, 127, 128, 253, 254, 255, 256, 65533, 65534, 65535} {
		_, err := PackUint16(b, i)
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff, 0xcd, 0x01, 0x00, 0xcd, 0xff, 0xfd, 0xcd, 0xff, 0xfe, 0xcd, 0xff, 0xff}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackUint32(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range []uint32{0, 1, 2, 125, 126, 127, 128, 253, 254, 255, 256, 65533, 65534, 65535, 65536, 4294967293, 4294967294, 4294967295} {
		_, err := PackUint32(b, i)
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff, 0xcd, 0x01, 0x00, 0xcd, 0xff, 0xfd, 0xcd, 0xff, 0xfe, 0xcd, 0xff, 0xff, 0xce, 0x00, 0x01, 0x00, 0x00, 0xce, 0xff, 0xff, 0xff, 0xfd, 0xce, 0xff, 0xff, 0xff, 0xfe, 0xce, 0xff, 0xff, 0xff, 0xff}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackUint64(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range []uint64{0, 1, 2, 125, 126, 127, 128, 253, 254, 255, 256, 65533, 65534, 65535, 65536, 4294967293, 4294967294, 4294967295, 4294967296, 18446744073709551613, 18446744073709551614, 18446744073709551615} {
		_, err := PackUint64(b, i)
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff, 0xcd, 0x01, 0x00, 0xcd, 0xff, 0xfd, 0xcd, 0xff, 0xfe, 0xcd, 0xff, 0xff, 0xce, 0x00, 0x01, 0x00, 0x00, 0xce, 0xff, 0xff, 0xff, 0xfd, 0xce, 0xff, 0xff, 0xff, 0xfe, 0xce, 0xff, 0xff, 0xff, 0xff, 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackInt8(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range []int8{-128, -127, -34, -33, -32, -31, 0, 1, 126, 127} {
		_, err := PackInt8(b, i)
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0xd0, 0x80, 0xd0, 0x81, 0xd0, 0xde, 0xd0, 0xdf, 0xe0, 0xe1, 0x00, 0x01, 0x7e, 0x7f}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackInt16(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range []int16{-32768, -32767, -131, -130, -129, -128, -127, -34, -33, -32, -31, 0, 1, 126, 127, 128, 129, 130, 32765, 32766, 32767} {
		_, err := PackInt16(b, i)
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0xd1, 0x80, 0x00, 0xd1, 0x80, 0x01, 0xd1, 0xff, 0x7d, 0xd1, 0xff, 0x7e, 0xd1, 0xff, 0x7f, 0xd0, 0x80, 0xd0, 0x81, 0xd0, 0xde, 0xd0, 0xdf, 0xe0, 0xe1, 0x00, 0x01, 0x7e, 0x7f, 0xd1, 0x00, 0x80, 0xd1, 0x00, 0x81, 0xd1, 0x00, 0x82, 0xd1, 0x7f, 0xfd, 0xd1, 0x7f, 0xfe, 0xd1, 0x7f, 0xff}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackInt32(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range []int32{-2147483648, -2147483647, -2147483646, -32771, -32770, -32769, -32768, -32767, -131, -130, -129, -128, -127, -34, -33, -32, -31, 0, 1, 126, 127, 128, 129, 130, 32765, 32766, 32767, 32768, 32769, 32770, 2147483645, 2147483646, 2147483647} {
		_, err := PackInt32(b, i)
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0xd2, 0x80, 0x00, 0x00, 0x00, 0xd2, 0x80, 0x00, 0x00, 0x01, 0xd2, 0x80, 0x00, 0x00, 0x02, 0xd2, 0xff, 0xff, 0x7f, 0xfd, 0xd2, 0xff, 0xff, 0x7f, 0xfe, 0xd2, 0xff, 0xff, 0x7f, 0xff, 0xd1, 0x80, 0x00, 0xd1, 0x80, 0x01, 0xd1, 0xff, 0x7d, 0xd1, 0xff, 0x7e, 0xd1, 0xff, 0x7f, 0xd0, 0x80, 0xd0, 0x81, 0xd0, 0xde, 0xd0, 0xdf, 0xe0, 0xe1, 0x00, 0x01, 0x7e, 0x7f, 0xd1, 0x00, 0x80, 0xd1, 0x00, 0x81, 0xd1, 0x00, 0x82, 0xd1, 0x7f, 0xfd, 0xd1, 0x7f, 0xfe, 0xd1, 0x7f, 0xff, 0xd2, 0x00, 0x00, 0x80, 0x00, 0xd2, 0x00, 0x00, 0x80, 0x01, 0xd2, 0x00, 0x00, 0x80, 0x02, 0xd2, 0x7f, 0xff, 0xff, 0xfd, 0xd2, 0x7f, 0xff, 0xff, 0xfe, 0xd2, 0x7f, 0xff, 0xff, 0xff}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackInt64(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range []int64{-9223372036854775808, -9223372036854775807, -9223372036854775806, -2147483651, -2147483650, -2147483649, -2147483648, -2147483647, -2147483646, -32771, -32770, -32769, -32768, -32767, -131, -130, -129, -128, -127, -34, -33, -32, -31, 0, 1, 126, 127, 128, 129, 130, 32765, 32766, 32767, 32768, 32769, 32770, 2147483645, 2147483646, 2147483647, 2147483648, 2147483649, 2147483650, 4294967296, 4294967297, 4294967298} {
		_, err := PackInt64(b, i)
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfd, 0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe, 0xd3, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xd2, 0x80, 0x00, 0x00, 0x00, 0xd2, 0x80, 0x00, 0x00, 0x01, 0xd2, 0x80, 0x00, 0x00, 0x02, 0xd2, 0xff, 0xff, 0x7f, 0xfd, 0xd2, 0xff, 0xff, 0x7f, 0xfe, 0xd2, 0xff, 0xff, 0x7f, 0xff, 0xd1, 0x80, 0x00, 0xd1, 0x80, 0x01, 0xd1, 0xff, 0x7d, 0xd1, 0xff, 0x7e, 0xd1, 0xff, 0x7f, 0xd0, 0x80, 0xd0, 0x81, 0xd0, 0xde, 0xd0, 0xdf, 0xe0, 0xe1, 0x00, 0x01, 0x7e, 0x7f, 0xd1, 0x00, 0x80, 0xd1, 0x00, 0x81, 0xd1, 0x00, 0x82, 0xd1, 0x7f, 0xfd, 0xd1, 0x7f, 0xfe, 0xd1, 0x7f, 0xff, 0xd2, 0x00, 0x00, 0x80, 0x00, 0xd2, 0x00, 0x00, 0x80, 0x01, 0xd2, 0x00, 0x00, 0x80, 0x02, 0xd2, 0x7f, 0xff, 0xff, 0xfd, 0xd2, 0x7f, 0xff, 0xff, 0xfe, 0xd2, 0x7f, 0xff, 0xff, 0xff, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x02, 0xd3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackNil(t *testing.T) {
	b := &bytes.Buffer{}
	nbyteswrite, err := PackNil(b)
	if nbyteswrite != 1 {
		t.Error("nbyteswrite != 1")
	}
	if err != nil {
		t.Error("err != nil")
	}
	if bytes.Compare(b.Bytes(), []byte{0xc0}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackBool(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range []bool{false, true} {
		nbyteswrite, err := PackBool(b, i)
		if nbyteswrite != 1 {
			t.Error("nbyteswrite != 1")
		}
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0xc2, 0xc3}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackInt32Array(t *testing.T) {
	b := &bytes.Buffer{}
	_, err := PackInt32Array(b, []int32{})
	if err != nil {
		t.Error("err != nil")
	}
	_, err = PackInt32Array(b, []int32{0})
	if err != nil {
		t.Error("err != nil")
	}
	_, err = PackInt32Array(b, []int32{0, 1})
	if err != nil {
		t.Error("err != nil")
	}
	_, err = PackInt32Array(b, []int32{0, 1, 2})
	if err != nil {
		t.Error("err != nil")
	}
	if bytes.Compare(b.Bytes(), []byte{0x90, 0x91, 0x00, 0x92, 0x00, 0x01, 0x93, 0x00, 0x01, 0x02}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackArray(t *testing.T) {
	b := &bytes.Buffer{}
	_, err := PackArray(b, reflect.ValueOf([]int32{}))
	if err != nil {
		t.Error("err != nil")
	}
	_, err = PackArray(b, reflect.ValueOf([]int32{0}))
	if err != nil {
		t.Error("err != nil")
	}
	_, err = PackArray(b, reflect.ValueOf([]int32{0, 1}))
	if err != nil {
		t.Error("err != nil")
	}
	_, err = PackArray(b, reflect.ValueOf([]int32{0, 1, 2}))
	if err != nil {
		t.Error("err != nil")
	}
	if bytes.Compare(b.Bytes(), []byte{0x90, 0x91, 0x00, 0x92, 0x00, 0x01, 0x93, 0x00, 0x01, 0x02}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPackMap(t *testing.T) {
	b := &bytes.Buffer{}
	_, err := PackMap(b, reflect.ValueOf(map[int]int{0: 1, 2: 3, 4: 5}))
	if err != nil {
		t.Error("err != nil")
	}
	if bytes.Compare(b.Bytes(), []byte{0x83, 0x00, 0x01, 0x04, 0x05, 0x02, 0x03}) != 0 {
		t.Error("wrong output", b.Bytes())
	}
}

func TestPack(t *testing.T) {
	b := &bytes.Buffer{}
	for _, i := range [](interface{}){nil, false, true, 0, 1, 2, 3, 127, -32, -1, -33, 128} {
		_, err := Pack(b, i)
		if err != nil {
			t.Error("err != nil")
		}
	}
	if bytes.Compare(b.Bytes(), []byte{0xc0, 0xc2, 0xc3, 0x00, 0x01, 0x02, 0x03, 0x7f, 0xf0, 0xff, 0xd0, 0xef, 0xd1, 0x00, 0x80}) == 0 {
		t.Error("wrong output")
	}
}

func TestUnpackArray(t *testing.T) {
	b := bytes.NewBuffer([]byte{0x90, 0x91, 0x00, 0x92, 0x00, 0x01, 0x93, 0xd1, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xdc, 0x00, 0x02, 0x00, 0x01, 0xdd, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, 0x03})
	for _, v := range [](interface{}){[](interface{}){}, [](interface{}){int8(0)}, [](interface{}){int8(0), int8(1)}, [](interface{}){int16(0), int32(1), int64(2)}, [](interface{}){int8(0), int8(1)}, [](interface{}){int8(0), int8(1), int8(2), int8(3)}} {
		retval, _, e := Unpack(b)
		if e != nil {
			t.Error("err != nil")
		}
		if !equal(reflect.ValueOf(retval.Interface()), reflect.ValueOf(v)) {
			t.Errorf("%s != %s", retval.Interface(), v)
		}
	}
}

func TestUnpackInt(t *testing.T) {
	b := bytes.NewBuffer([]byte{0xff, 0xe0, 0x00, 0x01, 0x02, 0x7d, 0x7e, 0x7f, 0xd0, 0x01, 0xd0, 0x80, 0xd0, 0xff, 0xcc, 0x80, 0xcc, 0xfd, 0xcc, 0xfe, 0xcc, 0xff, 0xd1, 0x00, 0x00, 0xd1, 0x7f, 0xff, 0xd1, 0xff, 0xff, 0xcd, 0x80, 0x00, 0xcd, 0xff, 0xff, 0xd2, 0x7f, 0xff, 0xff, 0xff, 0xce, 0x7f, 0xff, 0xff, 0xff, 0xd3, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
	for _, v := range [](interface{}){
		int8(-1), int8(-32), int8(0), int8(1), int8(2), int8(125), int8(126), int8(127), int8(1), int8(-128), int8(-1), uint8(128), uint8(253), uint8(254), uint8(255), int16(0), int16(32767), int16(-1), uint16(32768), uint16(65535), int32(2147483647), uint32(2147483647), int64(9223372036854775807), uint64(18446744073709551615)} {
		retval, _, e := Unpack(b)
		if e != nil {
			t.Error("err != nil")
		}
		if retval.Interface() != v {
			t.Errorf("%u != %u", retval.Interface(), v)
		}
	}
}

func TestUnpackFloat(t *testing.T) {
	b := bytes.NewBuffer([]byte{0xca, 0x3d, 0xcc, 0xcc, 0xcd, 0xca, 0x3e, 0x4c, 0xcc, 0xcd, 0xca, 0xbd, 0xcc, 0xcc, 0xcd, 0xca, 0xbe, 0x4c, 0xcc, 0xcd, 0xca, 0x7f, 0x80, 0x00, 0x00, 0xca, 0xff, 0x80, 0x00, 0x00, 0xca, 0xff, 0xc0, 0x00, 0x0, 0xcb, 0x3f, 0xb9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xcb, 0x3f, 0xc9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xcb, 0xbf, 0xb9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xcb, 0xbf, 0xc9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a, 0xcb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb, 0xcb, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
	for _, v := range [](interface{}){float32(.1), float32(.2), float32(-.1), float32(-.2), float32(math.Inf(1)), float32(math.Inf(-1)), float32(math.NaN()), float64(.1), float64(.2), float64(-.1), float64(-.2)} {
		retval, _, e := Unpack(b)
		if e != nil {
			t.Error("err != nil")
		}
		isnan := false
		if _v, ok := v.(float64); ok {
			isnan = math.IsNaN(_v)
		} else if _v, ok := v.(float32); ok {
			isnan = math.IsNaN(float64(_v))
		}
		if isnan {
			if retval.Interface() == v {
				t.Errorf("[NaN] %u == %u", retval.Interface(), v)
			}
		} else {
			if retval.Interface() != v {
				t.Errorf("%u != %u", retval.Interface(), v)
			}
		}
	}
}