package processors

import (
	"go/parser"
	"go/token"
	"path/filepath"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/golangci/golangci-lint/v2/pkg/config"
)

func TestGeneratedFileMatcher_isGeneratedFileLax_generated(t *testing.T) {
	p := NewGeneratedFileMatcher(config.GeneratedModeLax)

	comments := []string{
		`	// generated by stringer -type Pill pill.go; DO NOT EDIT`,
		`// Code generated by "stringer -type Pill pill.go"; DO NOT EDIT`,
		`// Code generated by vfsgen; DO NOT EDIT`,
		`// Created by cgo -godefs - DO NOT EDIT`,
		`/* Created by cgo - DO NOT EDIT. */`,
		`// Generated by stringer -i a.out.go -o anames.go -p ppc64
// Do not edit.`,
		`// DO NOT EDIT
// generated by: x86map -fmt=decoder ../x86.csv`,
		`// DO NOT EDIT.
// Generate with: go run gen.go -full -output md5block.go`,
		`// generated by "go run gen.go". DO NOT EDIT.`,
		`// DO NOT EDIT. This file is generated by mksyntaxgo from the RE2 distribution.`,
		`// GENERATED BY make_perl_groups.pl; DO NOT EDIT.`,
		`// generated by mknacl.sh - do not edit`,
		`// DO NOT EDIT ** This file was generated with the bake tool ** DO NOT EDIT //`,
		`// Generated by running
//  maketables --tables=all --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt
// --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt
// DO NOT EDIT`,
		`/*
* CODE GENERATED AUTOMATICALLY WITH github.com/ernesto-jimenez/gogen/unmarshalmap
* THIS FILE SHOULD NOT BE EDITED BY HAND
  */`,
		`// AUTOGENERATED FILE: easyjson file.go`,
		` * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)`,
	}

	for _, comment := range comments {
		t.Run(comment, func(t *testing.T) {
			t.Parallel()

			generated := p.isGeneratedFileLax(comment)
			assert.True(t, generated)
		})
	}
}

func TestGeneratedFileMatcher_isGeneratedFileLax_nonGenerated(t *testing.T) {
	p := NewGeneratedFileMatcher(config.GeneratedModeLax)

	comments := []string{
		"code not generated by",
		"test",
	}

	for _, comment := range comments {
		t.Run(comment, func(t *testing.T) {
			t.Parallel()

			generated := p.isGeneratedFileLax(comment)
			assert.False(t, generated)
		})
	}
}

func Test_isGeneratedFileStrict(t *testing.T) {
	testCases := []struct {
		desc     string
		filepath string
		assert   assert.BoolAssertionFunc
	}{
		{
			desc:     "go strict",
			filepath: filepath.FromSlash("testdata/exclusion_generated_file_filter/go_strict.go"),
			assert:   assert.True,
		},
		{
			desc:     "go strict invalid",
			filepath: filepath.FromSlash("testdata/exclusion_generated_file_filter/go_strict_invalid.go"),
			assert:   assert.False,
		},
	}

	for _, test := range testCases {
		t.Run(test.desc, func(t *testing.T) {
			t.Parallel()

			file, err := parser.ParseFile(token.NewFileSet(), test.filepath, nil, parser.PackageClauseOnly|parser.ParseComments)
			require.NoError(t, err)

			generated := isGeneratedFileStrict(file)

			test.assert(t, generated)
		})
	}
}

func Test_getComments(t *testing.T) {
	testCases := []struct {
		fpath string
		doc   string
	}{
		{
			fpath: filepath.FromSlash("testdata/exclusion_generated_file_filter/exclude.go"),
			doc: `first line
second line
third line
this text also
and this text also`,
		},
		{
			fpath: filepath.FromSlash("testdata/exclusion_generated_file_filter/exclude_doc.go"),
			doc:   `DO NOT EDIT`,
		},
		{
			fpath: filepath.FromSlash("testdata/exclusion_generated_file_filter/exclude_block_comment.go"),
			doc: `* first line
 *
 * second line
 * third line
and this text also
this type of block comment also
this one line comment also`,
		},
	}

	for _, tc := range testCases {
		file, err := parser.ParseFile(token.NewFileSet(), tc.fpath, nil, parser.PackageClauseOnly|parser.ParseComments)
		require.NoError(t, err)

		doc := getComments(file)
		assert.Equal(t, tc.doc, doc)
	}
}

// Issue 954: Some lines can be very long, e.g. auto-generated
// embedded resources. Reported on file of 86.2KB.
func TestGeneratedFileMatcher_IsGeneratedFile_fileWithLongLine(t *testing.T) {
	p := NewGeneratedFileMatcher(config.GeneratedModeLax)

	fpath := filepath.FromSlash("testdata/exclusion_generated_file_filter/exclude_long_line.go")

	_, err := p.IsGeneratedFile(fpath, nil)
	assert.NoError(t, err)
}
