package compiler

import (
	"go/build"
	"testing"

	logpattern_go_proto "github.com/pingcap-inc/alioth/proto"
	. "github.com/pingcap/check"
)

func TestClient(t *testing.T) {
	TestingT(t)
}

var _ = Suite(&testLogCompilerSuite{})

type testLogCompilerSuite struct {
}

func (t *testLogCompilerSuite) TestPackageCompile(c *C) {
	pc := NewPackageComplier(build.Default)
	t.testPackageCompile(c, pc)
	t.testImportSpecialPackage(c, pc)
}

func (t *testLogCompilerSuite) testPackageCompile(c *C, pc *PackageCompiler) {
	testPackageImportPath := "../../../test/ast_test/example"

	pl, err := pc.importPackage(testPackageImportPath)
	c.Assert(err, IsNil)
	c.Assert(pl, NotNil)

	expectPackages := map[string]bool{
		"github.com/pingcap/log": true,
		"go.uber.org/zap":        true,
		"fmt":                    true,
		"github.com/pingcap-inc/alioth/test/ast_test/example": false,
	}

	for path, depOnly := range expectPackages {
		pi := pc.GetCompliant(path)
		c.Assert(pi, NotNil)
		c.Assert(pi.DepOnly, Equals, depOnly)
	}

	t.testCompilation(c, pl)

}

func (t *testLogCompilerSuite) testCompilation(c *C, pl *PackageCompilation) {
	// check packageCompilation
	c.Assert(pl.ImportPath, Equals, "github.com/pingcap-inc/alioth/test/ast_test/example")
	c.Assert(pl.PackagePath, DeepEquals, &logpattern_go_proto.Package{
		Repo: "github.com/pingcap-inc/alioth",
		Path: "test/ast_test/example",
	})
	c.Assert(pl.DepOnly, IsFalse)

	sourceFiles := []string{"print.go"}
	sourceFilePaths := []*FilePath{
		{
			RelPath: "test/ast_test/example/print.go",
			AbsPath: "/Users/ianz/Work/go/src/github.com/pingcap-inc/alioth/test/ast_test/example/print.go",
			Digest:  "/Users/ianz/Work/go/src/github.com/pingcap-inc/alioth/test/ast_test/example/print.go",
		},
	}
	dependPkgs := map[string]bool{
		"github.com/pingcap/log": false,
		"go.uber.org/zap":        false,
		"fmt":                    false,
	}

	// check BuiledPackage
	builedPackage := pl.BuiledPackage
	c.Assert(builedPackage, NotNil)
	c.Assert(builedPackage.GoFiles, DeepEquals, sourceFiles)
	depCnt := 0
	for _, path := range builedPackage.Imports {
		if exist := dependPkgs[path]; !exist {
			depCnt++
			dependPkgs[path] = true
		}
	}
	c.Assert(dependPkgs, HasLen, depCnt)
	c.Assert(builedPackage.Root, Equals, "/Users/ianz/Work/go/src/github.com/pingcap-inc/alioth")
	c.Assert(builedPackage.Dir, Equals, "/Users/ianz/Work/go/src/github.com/pingcap-inc/alioth/test/ast_test/example")

	// test ComputeFilePath
	for index, file := range builedPackage.GoFiles {
		c.Assert(ComputeFilePath(builedPackage.Root, builedPackage.Dir, file), DeepEquals, sourceFilePaths[index])
	}

	// compile compilation
	c.Assert(pl.SourceFileSet, HasLen, 0)
	c.Assert(pl.Deps, HasLen, 0)

	err := pl.Compile()
	c.Assert(err, IsNil)
	c.Assert(pl.SourceFileSet, HasLen, 1)
	c.Assert(pl.Deps, HasLen, 3)
	c.Assert(pl.helper, NotNil)
}

func (t *testLogCompilerSuite) testImportSpecialPackage(c *C, pc *PackageCompiler) {
	// multiple packages in one dir
	testPackageImportPath := "../../../test/ast_test/multiple_package"
	pl, err := pc.importPackage(testPackageImportPath)
	c.Assert(err, NotNil)
	c.Assert(pl, IsNil)

	// multiple main function in one dir
	testPackageImportPath = "../../../test/ast_test/multiple_main"
	pl, err = pc.importPackage(testPackageImportPath)
	c.Assert(err, NotNil)
	c.Assert(pl, IsNil)

	// multiple main function in one dir
	testPackageImportPath = "../analyzer"
	pl, err = pc.importPackage(testPackageImportPath)
	c.Assert(err, IsNil)
	c.Assert(pl, NotNil)
	c.Assert(pl.ImportPath, Equals, "github.com/pingcap-inc/alioth/extractor/go/analyzer")
}
