package main

import "testing"

func testFrame() []byte {
	buf := make([]byte, 512)
	spec := newFrameSpec([6]byte{1, 2, 3, 4, 5, 6}, [6]byte{7, 8, 9, 10, 11, 12},
		etherBase, []int{512})
	spec.prefill(buf, 3)
	putHeader(buf, 3, 5, 0x0123456789ab, 512-minFrame)
	return buf
}

func TestHeaderRoundTrip(t *testing.T) {
	p, st := parseHeader(testFrame())
	if st != hdrOK {
		t.Fatalf("status = %v, want hdrOK", st)
	}
	want := parsed{patIdx: 3, stream: 5, seq: 0x0123456789ab, payLen: 512 - minFrame}
	if p != want {
		t.Errorf("parsed = %+v, want %+v", p, want)
	}
}

// The sequence number is the one field on the wire that nothing else checks, and
// a single flipped bit in it is exactly what a marginal cable produces. Every
// bit of the header has to be covered, including the checksum's own.
func TestHeaderChecksumCatchesEverySingleBitFlip(t *testing.T) {
	for byteIdx := 0; byteIdx < hdrLen; byteIdx++ {
		for bit := 0; bit < 8; bit++ {
			buf := testFrame()
			buf[ethHdrLen+byteIdx] ^= 1 << bit

			_, st := parseHeader(buf)
			if st == hdrOK {
				t.Errorf("header byte %d bit %d flipped and the frame was accepted",
					byteIdx, bit)
			}
			// The magic is what says the frame is ours at all, so damage there is
			// somebody else's traffic as far as we can tell.
			wantForeign := byteIdx < 4
			if wantForeign && st != hdrForeign {
				t.Errorf("magic byte %d bit %d = %v, want hdrForeign", byteIdx, bit, st)
			}
			if !wantForeign && st != hdrDamaged {
				t.Errorf("header byte %d bit %d = %v, want hdrDamaged", byteIdx, bit, st)
			}
		}
	}
}

func TestHeaderShortFrameIsForeign(t *testing.T) {
	if _, st := parseHeader(testFrame()[:minFrame-1]); st != hdrForeign {
		t.Errorf("status = %v, want hdrForeign", st)
	}
}

// A length that runs past the frame is damage rather than a foreign header: the
// magic and the checksum both said the header was ours.
func TestHeaderLengthPastFrameIsDamaged(t *testing.T) {
	buf := testFrame()
	putHeader(buf, 3, 5, 1, len(buf))
	if _, st := parseHeader(buf); st != hdrDamaged {
		t.Errorf("status = %v, want hdrDamaged", st)
	}
}
