// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tls

import (
	"rand";
	"reflect";
	"testing";
	"testing/quick";
)

var tests = []interface{}{
	&clientHelloMsg{},
	&clientKeyExchangeMsg{},
	&finishedMsg{},
}

type testMessage interface {
	marshal() []byte;
	unmarshal([]byte) bool;
}

func TestMarshalUnmarshal(t *testing.T) {
	rand := rand.New(rand.NewSource(0));
	for i, iface := range tests {
		ty := reflect.NewValue(iface).Type();

		for j := 0; j < 100; j++ {
			v, ok := quick.Value(ty, rand);
			if !ok {
				t.Errorf("#%d: failed to create value", i);
				break;
			}

			m1 := v.Interface().(testMessage);
			marshaled := m1.marshal();
			m2 := iface.(testMessage);
			if !m2.unmarshal(marshaled) {
				t.Errorf("#%d failed to unmarshal %#v", i, m1);
				break;
			}
			m2.marshal();	// to fill any marshal cache in the message

			if !reflect.DeepEqual(m1, m2) {
				t.Errorf("#%d got:%#v want:%#v", i, m1, m2);
				break;
			}

			// Now check that all prefixes are invalid.
			for j := 0; j < len(marshaled); j++ {
				if m2.unmarshal(marshaled[0:j]) {
					t.Errorf("#%d unmarshaled a prefix of length %d of %#v", i, j, m1);
					break;
				}
			}
		}
	}
}

func randomBytes(n int, rand *rand.Rand) []byte {
	r := make([]byte, n);
	for i := 0; i < n; i++ {
		r[i] = byte(rand.Int31());
	}
	return r;
}

func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
	m := &clientHelloMsg{};
	m.major = uint8(rand.Intn(256));
	m.minor = uint8(rand.Intn(256));
	m.random = randomBytes(32, rand);
	m.sessionId = randomBytes(rand.Intn(32), rand);
	m.cipherSuites = make([]uint16, rand.Intn(63) + 1);
	for i := 0; i < len(m.cipherSuites); i++ {
		m.cipherSuites[i] = uint16(rand.Int31());
	}
	m.compressionMethods = randomBytes(rand.Intn(63) + 1, rand);

	return reflect.NewValue(m);
}

func (*clientKeyExchangeMsg) Generate(rand *rand.Rand, size int) reflect.Value {
	m := &clientKeyExchangeMsg{};
	m.ciphertext = randomBytes(rand.Intn(1000), rand);
	return reflect.NewValue(m);
}

func (*finishedMsg) Generate(rand *rand.Rand, size int) reflect.Value {
	m := &finishedMsg{};
	m.verifyData = randomBytes(12, rand);
	return reflect.NewValue(m);
}
