package winpwn

import "testing"

func TestOpenPEAndHeader(t *testing.T) {
	requireFixturePE(t)
	pf, err := OpenPE(testFixturePE)
	if err != nil {
		t.Fatal(err)
	}
	defer pf.Close()

	is64, err := pf.Is64Bit()
	if err != nil {
		t.Fatal(err)
	}
	if !is64 {
		t.Error("expected bof_win.c.exe to be PE32+ (x64)")
	}

	base, err := pf.ImageBase()
	if err != nil {
		t.Fatal(err)
	}
	if base == 0 {
		t.Error("ImageBase should not be zero")
	}

	entry, err := pf.EntryPoint()
	if err != nil {
		t.Fatal(err)
	}
	if entry < base {
		t.Errorf("EntryPoint 0x%x should be >= ImageBase 0x%x", entry, base)
	}
}

func TestChecksecSEHNotApplicableOnX64(t *testing.T) {
	requireFixturePE(t)
	pf, err := OpenPE(testFixturePE)
	if err != nil {
		t.Fatal(err)
	}
	defer pf.Close()

	r, err := pf.Checksec()
	if err != nil {
		t.Fatal(err)
	}
	if !r.Is64Bit {
		t.Fatal("expected fixture to be 64-bit")
	}
	if r.SEHApplicable {
		t.Error("SEHApplicable should be false for an x64 binary (table-based SEH, no classic SafeSEH attack class)")
	}
}

func TestSectionsHaveAnExecutableOne(t *testing.T) {
	requireFixturePE(t)
	pf, err := OpenPE(testFixturePE)
	if err != nil {
		t.Fatal(err)
	}
	defer pf.Close()

	secs := pf.Sections()
	if len(secs) == 0 {
		t.Fatal("expected at least one section")
	}
	for _, s := range secs {
		if s.IsExecutable() {
			return
		}
	}
	t.Error("expected at least one executable section (.text)")
}

func TestImportsContainKernel32(t *testing.T) {
	requireFixturePE(t)
	pf, err := OpenPE(testFixturePE)
	if err != nil {
		t.Fatal(err)
	}
	defer pf.Close()

	imports, err := pf.ListImports()
	if err != nil {
		t.Fatal(err)
	}
	for _, im := range imports {
		if im.DLL == "KERNEL32.dll" {
			return
		}
	}
	t.Error("expected an import from KERNEL32.dll")
}

func TestRVAToFileOffsetMapsIntoASectionsByteRange(t *testing.T) {
	requireFixturePE(t)
	pf, err := OpenPE(testFixturePE)
	if err != nil {
		t.Fatal(err)
	}
	defer pf.Close()

	secs := pf.Sections()
	if len(secs) == 0 {
		t.Fatal("expected at least one section")
	}
	sec := secs[0]
	offset := pf.RVAToFileOffset(sec.VirtualAddress)
	if offset != int64(sec.Offset) {
		t.Errorf("RVAToFileOffset(section start) = %d, want %d (sec.Offset)", offset, sec.Offset)
	}
}
