/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

/*
   Portions from https://github.com/docker/cli/blob/v20.10.9/cli/command/image/build/context.go
   Copyright (C) Docker authors.
   Licensed under the Apache License, Version 2.0
   NOTICE: https://github.com/docker/cli/blob/v20.10.9/NOTICE
*/

package buildkitutil

import (
	"os"
	"path/filepath"
	"testing"

	"gotest.tools/v3/assert"

	"github.com/containerd/nerdctl/v2/pkg/internal/filesystem"
)

func TestBuildKitFile(t *testing.T) {
	var tmp = t.TempDir()
	var wd, err = os.Getwd()
	assert.NilError(t, err)
	tmp, err = filepath.EvalSymlinks(tmp)
	assert.NilError(t, err)
	err = os.Chdir(tmp)
	assert.NilError(t, err)
	defer os.Chdir(wd)
	type args struct {
		dir       string
		inputfile string
	}
	tests := []struct {
		name       string
		args       args
		prepare    func(t *testing.T) error
		wantAbsDir string
		wantFile   string
		wantErr    bool
	}{
		{
			name: "only Dockerfile is present",
			prepare: func(t *testing.T) error {
				return filesystem.WriteFile(filepath.Join(tmp, DefaultDockerfileName), []byte{}, 0644)
			},
			args:       args{".", ""},
			wantAbsDir: tmp,
			wantFile:   DefaultDockerfileName,
			wantErr:    false,
		},
		{
			name: "only Containerfile is present",
			prepare: func(t *testing.T) error {
				return filesystem.WriteFile(filepath.Join(tmp, "Containerfile"), []byte{}, 0644)
			},
			args:       args{".", ""},
			wantAbsDir: tmp,
			wantFile:   ContainerfileName,
			wantErr:    false,
		},
		{
			name: "both Dockerfile and Containerfile are present",
			prepare: func(t *testing.T) error {
				var err = filesystem.WriteFile(filepath.Join(tmp, "Dockerfile"), []byte{}, 0644)
				if err != nil {
					return err
				}
				return filesystem.WriteFile(filepath.Join(tmp, "Containerfile"), []byte{}, 0644)
			},
			args:       args{".", ""},
			wantAbsDir: tmp,
			wantFile:   DefaultDockerfileName,
			wantErr:    false,
		},
		{
			name: "Dockerfile and Containerfile have different contents",
			prepare: func(t *testing.T) error {
				var err = filesystem.WriteFile(filepath.Join(tmp, "Dockerfile"), []byte{'d'}, 0644)
				if err != nil {
					return err
				}
				return filesystem.WriteFile(filepath.Join(tmp, "Containerfile"), []byte{'c'}, 0644)
			},
			args:       args{".", ""},
			wantAbsDir: tmp,
			wantFile:   DefaultDockerfileName,
			wantErr:    false,
		},
		{
			name: "Custom file is specfied",
			prepare: func(t *testing.T) error {
				return filesystem.WriteFile(filepath.Join(tmp, "CustomFile"), []byte{}, 0644)
			},
			args:       args{".", "CustomFile"},
			wantAbsDir: tmp,
			wantFile:   "CustomFile",
			wantErr:    false,
		},
		{
			name: "Absolute path is specified along with custom file",
			prepare: func(t *testing.T) error {
				return filesystem.WriteFile(filepath.Join(tmp, "CustomFile"), []byte{}, 0644)
			},
			args:       args{tmp, "CustomFile"},
			wantAbsDir: tmp,
			wantFile:   "CustomFile",
			wantErr:    false,
		},
		{
			name: "Absolute path is specified along with Docker file",
			prepare: func(t *testing.T) error {
				return filesystem.WriteFile(filepath.Join(tmp, "Dockerfile"), []byte{}, 0644)
			},
			args:       args{tmp, "."},
			wantAbsDir: tmp,
			wantFile:   DefaultDockerfileName,
			wantErr:    false,
		},
		{
			name: "Absolute path is specified with Container file in the path",
			prepare: func(t *testing.T) error {
				return filesystem.WriteFile(filepath.Join(tmp, ContainerfileName), []byte{}, 0644)
			},
			args:       args{tmp, "."},
			wantAbsDir: tmp,
			wantFile:   ContainerfileName,
			wantErr:    false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.prepare(t)
			gotAbsDir, gotFile, err := BuildKitFile(tt.args.dir, tt.args.inputfile)
			if (err != nil) != tt.wantErr {
				t.Errorf("BuildKitFile() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if gotAbsDir != tt.wantAbsDir {
				t.Errorf("BuildKitFile() gotAbsDir = %v, want %v", gotAbsDir, tt.wantAbsDir)
			}
			if gotFile != tt.wantFile {
				t.Errorf("BuildKitFile() gotFile = %v, want %v", gotFile, tt.wantFile)
			}

			entry, err := os.ReadDir(tmp)
			assert.NilError(t, err)
			for _, f := range entry {
				err = os.Remove(f.Name())
				assert.NilError(t, err)
			}
		})
	}
}
