// Copyright 2022 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 worker

import (
	"errors"
	"fmt"
	"io"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"golang.org/x/pkgsite-metrics/internal/buildtest"
	"golang.org/x/pkgsite-metrics/internal/govulncheck"
	"golang.org/x/pkgsite-metrics/internal/govulncheckapi"
)

func TestAsScanError(t *testing.T) {
	check := func(err error, want bool) {
		if got := errors.As(err, new(scanError)); got != want {
			t.Errorf("%T: got %t, want %t", err, got, want)
		}
	}
	check(io.EOF, false)
	check(scanError{io.EOF}, true)
}

func TestVulnsForMode(t *testing.T) {
	findings := []*govulncheckapi.Finding{
		{Trace: []*govulncheckapi.Frame{{Module: "M1", Package: "P1", Function: "F1"}}},
		{Trace: []*govulncheckapi.Frame{{Module: "M1", Package: "P1"}}},
		{Trace: []*govulncheckapi.Frame{{Module: "M1"}}},
		{Trace: []*govulncheckapi.Frame{{Module: "M2"}}},
	}

	vulnsStr := func(vulns []*govulncheck.Vuln) string {
		var vs []string
		for _, v := range vulns {
			vs = append(vs, fmt.Sprintf("%s:%s", v.ModulePath, v.PackagePath))
		}
		return strings.Join(vs, ", ")
	}

	for _, tc := range []struct {
		mode string
		want string
	}{
		{scanModeSourceSymbol, "M1:P1"},
		{scanModeBinarySymbol, "M1:P1"},
		{scanModeSourcePackage, "M1:P1"},
		{scanModeSourceModule, "M1:, M2:"},
	} {
		tc := tc
		t.Run(tc.mode, func(t *testing.T) {
			vs := vulnsForScanMode(findings, tc.mode)
			if got := vulnsStr(vs); got != tc.want {
				t.Errorf("got %s; want %s", got, tc.want)
			}
		})
	}
}

func TestUnrecoverableError(t *testing.T) {
	for _, e := range []struct {
		ec   string
		want bool
	}{
		{"LOAD", true},
		{"MISC", false},
		{"BIGQUERY", false},
	} {
		if got := unrecoverableError(e.ec); got != e.want {
			t.Errorf("want %t for %s; got %t", e.want, e.ec, got)
		}
	}
}

// TODO: can we have a test for sandbox? We do test the sandbox
// and unmarshalling in cmd/govulncheck_sandbox, so what would be
// left here is checking that runsc is initiated properly. It is
// not clear how to do that here nor is it necessary.
func TestRunScanModuleInsecure(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test that uses internet in short mode")
	}

	govulncheckPath, err := buildtest.BuildGovulncheck(t.TempDir())
	if err != nil {
		t.Fatal(err)
	}

	vulndb, err := filepath.Abs("../testdata/vulndb")
	if err != nil {
		t.Fatal(err)
	}

	s := &scanner{insecure: true, govulncheckPath: govulncheckPath, vulnDBDir: vulndb}

	stats := &govulncheck.ScanStats{}
	findings, err := s.runGovulncheckScanInsecure("../testdata/module", ModeGovulncheck, stats)
	if err != nil {
		t.Fatal(err)
	}
	wantID := "GO-2021-0113"
	found := false
	for _, v := range findings {
		if v.OSV == wantID {
			found = true
			break
		}
	}
	if !found {
		t.Errorf("want %s, did not find it in %d vulns", wantID, len(findings))
	}
	if got := stats.ScanSeconds; got <= 0 {
		t.Errorf("scan time not collected or negative: %v", got)
	}
	if got := stats.ScanMemory; got <= 0 && runtime.GOOS == "linux" {
		t.Errorf("scan memory not collected or negative: %v", got)
	}
}
