package scanproto

import (
	"bytes"
	"log"
	"testing"

	"code.justin.tv/release/trace/pbmsg"
	"github.com/golang/protobuf/proto"
)

func (ps protoSplit) splitLog(data []byte, atEOF bool) (advance int, token []byte, err error) {
	advance, token, err = ps.split(data, atEOF)

	log.Printf("data=%#02x atEOF=%t advance=%d token=%#02x err=%q",
		data, atEOF, advance, token, err)

	return advance, token, err
}

func TestScan(t *testing.T) {
	var buf []byte
	for _, msg := range []string{"abc", "def", "ghi"} {
		ev := &pbmsg.Event{Svcname: proto.String(msg)}
		set := &pbmsg.EventSet{Event: []*pbmsg.Event{ev}}
		b, err := proto.Marshal(set)
		if err != nil {
			t.Fatalf("proto.Marshal; err = %q", err)
		}
		buf = append(buf, b...)
	}

	sc := NewEventSetScanner(bytes.NewReader(buf))
	for sc.Scan() {
		t.Logf("bytes=%x", sc.Bytes())
		var set pbmsg.EventSet
		err := proto.Unmarshal(sc.Bytes(), &set)
		if err != nil {
			t.Errorf("proto.Unmarshal; err = %q", err)
			break
		}
		for _, ev := range set.Event {
			t.Logf("svcname = %q", ev.GetSvcname())
		}
	}
	err := sc.Err()
	if err != nil {
		t.Errorf("sc.Err; err = %q", err)
	}
}

func TestScanBogus(t *testing.T) {
	// https://developers.google.com/protocol-buffers/docs/encoding

	const (
		wireVarint      = 0
		wire64bit       = 1
		wireLengthDelim = 2
		wire32bit       = 5
	)

	tests := []struct {
		buf []byte
	}{
		{buf: []byte{}},
		{buf: []byte{9<<3 | wireVarint, 0}},
		{buf: []byte{9<<3 | wireVarint, 20}},
		{buf: []byte{9<<3 | wireVarint, 0x92, 0x29}},
		{buf: []byte{9<<3 | wire64bit, 3, 3, 3, 3, 3, 3, 3, 3}},
		{buf: []byte{9<<3 | wireLengthDelim, 5, 'h', 'e', 'l', 'l', 'o'}},
		{buf: []byte{9<<3 | wireLengthDelim, 0}},
		{buf: []byte{9<<3 | wire32bit, 3, 3, 3, 3}},
	}

	for _, tt := range tests {
		sc := NewEventSetScanner(bytes.NewReader(tt.buf))
		i := 0
		for sc.Scan() {
			i++
		}
		err := sc.Err()
		if err != nil {
			t.Errorf("sc.Err() = %q; want nil (input %02x)", err, tt.buf)
		}
		if have, want := i, 0; have != want {
			t.Errorf("sc.Scan() count = %d; want %d", have, want)
		}

		for _, atEOF := range []bool{false, true} {
			advance, token, err := protoSplit{field: 1}.split(tt.buf, atEOF)
			if have, want := advance, len(tt.buf); have != want {
				t.Errorf("split(%02x, %t); advance = %d; want %d", tt.buf, atEOF, have, want)
			}
			if token != nil {
				t.Errorf("split(%02x, %t); token = %d", tt.buf, atEOF, token)
			}
			if err != nil {
				t.Errorf("split(%02x, %t); err = %q", tt.buf, atEOF, err)
			}
		}
	}
}
