Files
gf-lt/tools/fs_test.go
2026-04-08 17:43:28 +03:00

424 lines
12 KiB
Go

package tools
import (
"os"
"path/filepath"
"strings"
"testing"
"gf-lt/config"
)
func init() {
cfg = &config.Config{}
cwd, _ := os.Getwd()
if strings.HasSuffix(cwd, "/tools") || strings.HasSuffix(cwd, "\\tools") {
cwd = filepath.Dir(cwd)
}
cfg.FilePickerDir = cwd
}
func TestFsLs(t *testing.T) {
tests := []struct {
name string
args []string
stdin string
check func(string) bool
}{
{"no args", []string{}, "", func(r string) bool { return strings.Contains(r, "tools/") }},
{"long format", []string{"-l"}, "", func(r string) bool { return strings.Contains(r, "f ") }},
{"all files", []string{"-a"}, "", func(r string) bool { return strings.Contains(r, ".") || strings.Contains(r, "..") }},
{"combine flags", []string{"-la"}, "", func(r string) bool { return strings.Contains(r, "f ") && strings.Contains(r, ".") }},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsLs(tt.args, tt.stdin)
if !tt.check(result) {
t.Errorf("check failed for %q, got %q", tt.name, result)
}
})
}
}
func TestFsCat(t *testing.T) {
tmpFile := filepath.Join(cfg.FilePickerDir, "test_cat.txt")
content := "hello\nworld\n"
os.WriteFile(tmpFile, []byte(content), 0644)
defer os.Remove(tmpFile)
tests := []struct {
name string
args []string
stdin string
want string
}{
{"file path", []string{tmpFile}, "", "hello\nworld\n"},
{"stdin fallback", []string{}, "stdin content", "stdin content"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsCat(tt.args, tt.stdin)
if result != tt.want && !strings.Contains(result, tt.want) {
t.Errorf("expected %q, got %q", tt.want, result)
}
})
}
}
func TestFsHead(t *testing.T) {
tmpFile := filepath.Join(cfg.FilePickerDir, "test_head.txt")
content := "line1\nline2\nline3\nline4\nline5\n"
os.WriteFile(tmpFile, []byte(content), 0644)
defer os.Remove(tmpFile)
tests := []struct {
name string
args []string
stdin string
want string
}{
{"default from stdin", []string{}, "line1\nline2\nline3", "line1\nline2\nline3"},
{"n from stdin", []string{"-n", "2"}, "line1\nline2\nline3", "line1\nline2"},
{"numeric n", []string{"-2"}, "line1\nline2\nline3", "line1\nline2"},
{"file path", []string{tmpFile}, "", "line1\nline2\nline3\nline4\nline5"},
{"file with n", []string{"-n", "2", tmpFile}, "", "line1\nline2"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsHead(tt.args, tt.stdin)
if result != tt.want && !strings.Contains(result, tt.want) {
t.Errorf("expected %q, got %q", tt.want, result)
}
})
}
}
func TestFsTail(t *testing.T) {
tmpFile := filepath.Join(cfg.FilePickerDir, "test_tail.txt")
content := "line1\nline2\nline3\nline4\nline5\n"
os.WriteFile(tmpFile, []byte(content), 0644)
defer os.Remove(tmpFile)
tests := []struct {
name string
args []string
stdin string
want string
}{
{"default from stdin", []string{}, "line1\nline2\nline3", "line1\nline2\nline3"},
{"n from stdin", []string{"-n", "2"}, "line1\nline2\nline3", "line2\nline3"},
{"file path", []string{tmpFile}, "", "line1\nline2\nline3\nline4\nline5"},
{"file with n", []string{"-n", "3", tmpFile}, "", "line3\nline4\nline5"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsTail(tt.args, tt.stdin)
if result != tt.want && !strings.Contains(result, tt.want) {
t.Errorf("expected %q, got %q", tt.want, result)
}
})
}
}
func TestFsWc(t *testing.T) {
tmpFile := filepath.Join(cfg.FilePickerDir, "test_wc.txt")
content := "one two three\nfour five\nsix\n"
os.WriteFile(tmpFile, []byte(content), 0644)
defer os.Remove(tmpFile)
tests := []struct {
name string
args []string
stdin string
want string
}{
{"default", []string{}, "one two", "1 lines, 2 words, 7 chars"},
{"lines", []string{"-l"}, "line1\nline2\nline3", "3"},
{"words", []string{"-w"}, "one two three", "3"},
{"chars", []string{"-c"}, "abc", "3"},
{"file lines", []string{"-l", tmpFile}, "", "3"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsWc(tt.args, tt.stdin)
if !strings.Contains(result, tt.want) {
t.Errorf("expected %q in output, got %q", tt.want, result)
}
})
}
}
func TestFsSort(t *testing.T) {
tests := []struct {
name string
args []string
stdin string
want string
}{
{"basic", []string{}, "c\na\nb\n", "a\nb\nc"},
{"reverse", []string{"-r"}, "a\nb\nc", "c\nb\na"},
{"numeric", []string{"-n"}, "10\n2\n1\n", "1\n2\n10"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsSort(tt.args, tt.stdin)
if result != tt.want {
t.Errorf("expected %q, got %q", tt.want, result)
}
})
}
}
func TestFsUniq(t *testing.T) {
tests := []struct {
name string
args []string
stdin string
want string
}{
{"basic", []string{}, "a\nb\na\nc", "a\nb\nc"},
{"count", []string{"-c"}, "a\na\nb", "2 a\n1 b"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsUniq(tt.args, tt.stdin)
if result != tt.want && !strings.Contains(result, tt.want) {
t.Errorf("expected %q, got %q", tt.want, result)
}
})
}
}
func TestFsGrep(t *testing.T) {
tests := []struct {
name string
args []string
stdin string
want string
}{
{"basic", []string{"world"}, "hello\nworld\ntest", "world"},
{"ignore case", []string{"-i", "WORLD"}, "hello\nworld\ntest", "world"},
{"invert", []string{"-v", "world"}, "hello\nworld\ntest", "hello\ntest"},
{"count", []string{"-c", "o"}, "hello\no world\no foo", "3"},
{"no match", []string{"xyz"}, "hello\nworld", ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsGrep(tt.args, tt.stdin)
if tt.want != "" && !strings.Contains(result, tt.want) {
t.Errorf("expected %q, got %q", tt.want, result)
}
})
}
}
func TestFsEcho(t *testing.T) {
tests := []struct {
name string
args []string
stdin string
want string
}{
{"single", []string{"hello"}, "", "hello\n"},
{"multiple", []string{"hello", "world"}, "", "hello world\n"},
{"with stdin", []string{}, "stdin", "stdin"},
{"empty", []string{}, "", ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsEcho(tt.args, tt.stdin)
if result != tt.want {
t.Errorf("expected %q, got %q", tt.want, result)
}
})
}
}
func TestFsPwd(t *testing.T) {
result := FsPwd(nil, "")
if !strings.Contains(result, "gf-lt") {
t.Errorf("expected gf-lt in path, got %q", result)
}
}
func TestFsTime(t *testing.T) {
result := FsTime(nil, "")
if len(result) < 10 {
t.Errorf("expected time output, got %q", result)
}
}
func TestFsStat(t *testing.T) {
tmpFile := filepath.Join(cfg.FilePickerDir, "test_stat.txt")
os.WriteFile(tmpFile, []byte("content"), 0644)
defer os.Remove(tmpFile)
result := FsStat([]string{tmpFile}, "")
if !strings.Contains(result, "test_stat.txt") {
t.Errorf("expected filename in output, got %q", result)
}
}
func TestFsMkdir(t *testing.T) {
testDir := filepath.Join(cfg.FilePickerDir, "test_mkdir_xyz")
defer os.RemoveAll(testDir)
result := FsMkdir([]string{testDir}, "")
if _, err := os.Stat(testDir); err != nil {
t.Errorf("directory not created: %v, result: %q", err, result)
}
}
func TestFsCp(t *testing.T) {
src := filepath.Join(cfg.FilePickerDir, "test_cp_src.txt")
dst := filepath.Join(cfg.FilePickerDir, "test_cp_dst.txt")
os.WriteFile(src, []byte("test"), 0644)
defer os.Remove(src)
defer os.Remove(dst)
result := FsCp([]string{src, dst}, "")
if _, err := os.Stat(dst); err != nil {
t.Errorf("file not copied: %v, result: %q", err, result)
}
}
func TestFsMv(t *testing.T) {
src := filepath.Join(cfg.FilePickerDir, "test_mv_src.txt")
dst := filepath.Join(cfg.FilePickerDir, "test_mv_dst.txt")
os.WriteFile(src, []byte("test"), 0644)
defer os.Remove(src)
defer os.Remove(dst)
result := FsMv([]string{src, dst}, "")
if _, err := os.Stat(dst); err != nil {
t.Errorf("file not moved: %v, result: %q", err, result)
}
if _, err := os.Stat(src); err == nil {
t.Errorf("source file still exists")
}
}
func TestFsRm(t *testing.T) {
tmpFile := filepath.Join(cfg.FilePickerDir, "test_rm_xyz.txt")
os.WriteFile(tmpFile, []byte("test"), 0644)
result := FsRm([]string{tmpFile}, "")
if _, err := os.Stat(tmpFile); err == nil {
t.Errorf("file not removed, result: %q", result)
}
}
func TestFsSed(t *testing.T) {
tests := []struct {
name string
args []string
stdin string
want string
}{
{"replace", []string{"s/hello/bye/"}, "hello world", "bye world"},
{"global", []string{"s/o/X/g"}, "hello world", "hellX wXrld"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := FsSed(tt.args, tt.stdin)
if result != tt.want && !strings.Contains(result, tt.want) {
t.Errorf("expected %q, got %q", tt.want, result)
}
})
}
}
func TestPiping(t *testing.T) {
tmpFile := filepath.Join(cfg.FilePickerDir, "test_pipe.txt")
os.WriteFile(tmpFile, []byte("line3\nline1\nline2"), 0644)
defer os.Remove(tmpFile)
tests := []struct {
name string
cmd string
check func(string) bool
}{
{"ls | head -3", "ls | head -3", func(r string) bool { return r != "" }},
{"sort file", "sort " + tmpFile, func(r string) bool { return strings.Contains(r, "line1") }},
{"grep file", "grep line1 " + tmpFile, func(r string) bool { return r == "line1" }},
{"wc file", "wc -l " + tmpFile, func(r string) bool { return r == "3" }},
{"head file", "head -2 " + tmpFile, func(r string) bool { return strings.Contains(r, "line3") }},
{"tail file", "tail -2 " + tmpFile, func(r string) bool { return strings.Contains(r, "line2") }},
{"echo | head", "echo a b c | head -2", func(r string) bool { return strings.Contains(r, "a") }},
{"echo | wc -l", "echo a b c | wc -l", func(r string) bool { return r == "1" }},
{"echo | sort", "echo c a b | sort", func(r string) bool { return strings.Contains(r, "a") }},
{"echo | grep", "echo hello world | grep hello", func(r string) bool { return strings.Contains(r, "hello") }},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ExecChain(tt.cmd)
if !tt.check(result) {
t.Errorf("check failed for %q, got %q", tt.name, result)
}
})
}
}
func TestChaining(t *testing.T) {
tests := []struct {
name string
cmd string
check func(string) bool
}{
{"ls && echo ok", "ls && echo ok", func(r string) bool { return strings.Contains(r, "ok") }},
{"ls || echo not run", "ls || echo fallback", func(r string) bool { return !strings.Contains(r, "fallback") }},
{"false || echo run", "cd /nonexistent123 || echo fallback", func(r string) bool { return strings.Contains(r, "fallback") }},
{"echo a ; echo b", "echo a ; echo b", func(r string) bool { return strings.Contains(r, "a") && strings.Contains(r, "b") }},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ExecChain(tt.cmd)
if !tt.check(result) {
t.Errorf("check failed for %q, got %q", tt.name, result)
}
})
}
}
func TestRedirect(t *testing.T) {
tmpFile := filepath.Join(cfg.FilePickerDir, "test_redirect.txt")
os.Remove(tmpFile)
defer os.Remove(tmpFile)
// Test echo >
result1 := ExecChain("echo hello world > " + tmpFile)
if !strings.Contains(result1, "Wrote") {
t.Errorf("echo > failed: %q", result1)
}
// Test cat
result2 := ExecChain("cat " + tmpFile)
if !strings.Contains(result2, "hello") {
t.Errorf("cat failed: %q", result2)
}
// Test echo >>
result3 := ExecChain("echo more >> " + tmpFile)
if !strings.Contains(result3, "Appended") {
t.Errorf("echo >> failed: %q", result3)
}
// Test cat after append
result4 := ExecChain("cat " + tmpFile)
if !strings.Contains(result4, "hello") || !strings.Contains(result4, "more") {
t.Errorf("cat after append failed: %q", result4)
}
}