// This package exists purely for the convenience of easily running tests which
// test the offline functionality of the graph package.
// `unshare -nr` is used to deny network access, and then the tests are run using
// cached data from the tests in the graph package.
package offline

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

	"github.com/jstaf/onedriver/fs"
	"github.com/stretchr/testify/require"
)

// We should see more than zero items when we run ls.
func TestOfflineReaddir(t *testing.T) {
	t.Parallel()
	files, err := os.ReadDir(TestDir)
	if err != nil {
		t.Fatal(err)
	}

	if len(files) == 0 {
		t.Fatal("Expected more than 0 files in the test directory.")
	}
}

// We should find the file named bagels (from TestEchoWritesToFile)
func TestOfflineBagelDetection(t *testing.T) {
	t.Parallel()
	files, err := os.ReadDir(TestDir)
	if err != nil {
		t.Fatal(err)
	}

	found := false
	allFiles := make([]string, 0)
	for _, f := range files {
		allFiles = append(allFiles, f.Name())

		if f.Name() == "bagels" {
			found = true
			if f.IsDir() {
				t.Fatal("\"bagels\" should be an ordinary file, not a directory")
			}
			info, _ := f.Info()
			octal := fs.Octal(uint32(info.Mode().Perm()))
			if octal[0] != '6' || int(octal[1])-4 < 0 || octal[2] != '4' {
				// middle bit just needs to be higher than 4
				// for compatibility with 022 / 002 umasks on different distros
				t.Fatalf("\"bagels\" permissions bits wrong, got %s, expected 644", octal)
			}
			break
		}
	}
	if !found {
		t.Error("\"bagels\" not found! Expected file not present.")
		t.Errorf("Got: %+v", allFiles)
	}
}

// Does the contents of the bagels file match what it should?
// (File contents generated by TestEchoWritesToFile in previous tests.)
func TestOfflineBagelContents(t *testing.T) {
	t.Parallel()
	contents, err := os.ReadFile(filepath.Join(TestDir, "bagels"))
	require.NoError(t, err)
	require.Equal(t, []byte("bagels\n"), contents, "Offline file contents did not match.")
}

// Creating a file should fail
func TestOfflineFileCreation(t *testing.T) {
	t.Parallel()
	require.Error(t,
		os.WriteFile(filepath.Join(TestDir, "donuts"), []byte("fail me"), 0644),
		"Writing a file while offline should fail.",
	)
}

// Modifying a file offline should fail.
func TestOfflineFileModification(t *testing.T) {
	t.Parallel()
	require.Error(t,
		os.WriteFile(filepath.Join(TestDir, "bagels"), []byte("fail me too"), 0644),
		"Modifying a file while offline should fail.",
	)
}

// Deleting a file offline should fail.
func TestOfflineFileDeletion(t *testing.T) {
	t.Parallel()
	if os.Remove(filepath.Join(TestDir, "write.txt")) == nil {
		t.Error("Deleting a file while offline should fail.")
	}
	if os.Remove(filepath.Join(TestDir, "empty")) == nil {
		t.Error("Deleting an empty file while offline should fail.")
	}
}

// Creating a directory offline should fail.
func TestOfflineMkdir(t *testing.T) {
	t.Parallel()
	if os.Mkdir(filepath.Join(TestDir, "offline_dir"), 0755) == nil {
		t.Fatal("Creating a directory should have failed offline.")
	}
}

// Deleting a directory offline should fail.
func TestOfflineRmdir(t *testing.T) {
	t.Parallel()
	if os.Remove(filepath.Join(TestDir, "folder1")) == nil {
		t.Fatal("Removing a directory should have failed offline.")
	}
}
