Fix (tools): tests for tools and some fixes
This commit is contained in:
144
tools/fs.go
144
tools/fs.go
@@ -162,7 +162,10 @@ func FsCat(args []string, stdin string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return "[error] usage: cat <path>"
|
if stdin != "" {
|
||||||
|
return stdin
|
||||||
|
}
|
||||||
|
return "[error] usage: cat <path> or cat (with stdin)"
|
||||||
}
|
}
|
||||||
abs, err := resolvePath(path)
|
abs, err := resolvePath(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -426,12 +429,13 @@ func FsTime(args []string, stdin string) string {
|
|||||||
|
|
||||||
func FsGrep(args []string, stdin string) string {
|
func FsGrep(args []string, stdin string) string {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return "[error] usage: grep [-i] [-v] [-c] <pattern>"
|
return "[error] usage: grep [-i] [-v] [-c] <pattern> [file]"
|
||||||
}
|
}
|
||||||
ignoreCase := false
|
ignoreCase := false
|
||||||
invert := false
|
invert := false
|
||||||
countOnly := false
|
countOnly := false
|
||||||
var pattern string
|
var pattern string
|
||||||
|
var filePath string
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
switch a {
|
switch a {
|
||||||
case "-i":
|
case "-i":
|
||||||
@@ -441,16 +445,35 @@ func FsGrep(args []string, stdin string) string {
|
|||||||
case "-c":
|
case "-c":
|
||||||
countOnly = true
|
countOnly = true
|
||||||
default:
|
default:
|
||||||
pattern = a
|
if pattern == "" {
|
||||||
|
pattern = a
|
||||||
|
} else if filePath == "" {
|
||||||
|
filePath = a
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pattern == "" {
|
if pattern == "" {
|
||||||
return "[error] pattern required"
|
return "[error] pattern required"
|
||||||
}
|
}
|
||||||
|
var lines []string
|
||||||
|
if filePath != "" {
|
||||||
|
abs, err := resolvePath(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] grep: %v", err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(abs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] grep: %v", err)
|
||||||
|
}
|
||||||
|
lines = strings.Split(string(data), "\n")
|
||||||
|
} else if stdin != "" {
|
||||||
|
lines = strings.Split(stdin, "\n")
|
||||||
|
} else {
|
||||||
|
return "[error] grep: no input (use file path or pipe from stdin)"
|
||||||
|
}
|
||||||
if ignoreCase {
|
if ignoreCase {
|
||||||
pattern = strings.ToLower(pattern)
|
pattern = strings.ToLower(pattern)
|
||||||
}
|
}
|
||||||
lines := strings.Split(stdin, "\n")
|
|
||||||
var matched []string
|
var matched []string
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
haystack := line
|
haystack := line
|
||||||
@@ -473,6 +496,7 @@ func FsGrep(args []string, stdin string) string {
|
|||||||
|
|
||||||
func FsHead(args []string, stdin string) string {
|
func FsHead(args []string, stdin string) string {
|
||||||
n := 10
|
n := 10
|
||||||
|
var filePath string
|
||||||
for i, a := range args {
|
for i, a := range args {
|
||||||
if a == "-n" && i+1 < len(args) {
|
if a == "-n" && i+1 < len(args) {
|
||||||
if parsed, err := strconv.Atoi(args[i+1]); err == nil {
|
if parsed, err := strconv.Atoi(args[i+1]); err == nil {
|
||||||
@@ -482,9 +506,26 @@ func FsHead(args []string, stdin string) string {
|
|||||||
continue
|
continue
|
||||||
} else if parsed, err := strconv.Atoi(a); err == nil {
|
} else if parsed, err := strconv.Atoi(a); err == nil {
|
||||||
n = parsed
|
n = parsed
|
||||||
|
} else if filePath == "" && !strings.HasPrefix(a, "-") {
|
||||||
|
filePath = a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lines := strings.Split(stdin, "\n")
|
var lines []string
|
||||||
|
if filePath != "" {
|
||||||
|
abs, err := resolvePath(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] head: %v", err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(abs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] head: %v", err)
|
||||||
|
}
|
||||||
|
lines = strings.Split(string(data), "\n")
|
||||||
|
} else if stdin != "" {
|
||||||
|
lines = strings.Split(stdin, "\n")
|
||||||
|
} else {
|
||||||
|
return "[error] head: no input (use file path or pipe from stdin)"
|
||||||
|
}
|
||||||
if n > 0 && len(lines) > n {
|
if n > 0 && len(lines) > n {
|
||||||
lines = lines[:n]
|
lines = lines[:n]
|
||||||
}
|
}
|
||||||
@@ -493,6 +534,7 @@ func FsHead(args []string, stdin string) string {
|
|||||||
|
|
||||||
func FsTail(args []string, stdin string) string {
|
func FsTail(args []string, stdin string) string {
|
||||||
n := 10
|
n := 10
|
||||||
|
var filePath string
|
||||||
for i, a := range args {
|
for i, a := range args {
|
||||||
if a == "-n" && i+1 < len(args) {
|
if a == "-n" && i+1 < len(args) {
|
||||||
if parsed, err := strconv.Atoi(args[i+1]); err == nil {
|
if parsed, err := strconv.Atoi(args[i+1]); err == nil {
|
||||||
@@ -502,9 +544,26 @@ func FsTail(args []string, stdin string) string {
|
|||||||
continue
|
continue
|
||||||
} else if parsed, err := strconv.Atoi(a); err == nil {
|
} else if parsed, err := strconv.Atoi(a); err == nil {
|
||||||
n = parsed
|
n = parsed
|
||||||
|
} else if filePath == "" && !strings.HasPrefix(a, "-") {
|
||||||
|
filePath = a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lines := strings.Split(stdin, "\n")
|
var lines []string
|
||||||
|
if filePath != "" {
|
||||||
|
abs, err := resolvePath(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] tail: %v", err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(abs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] tail: %v", err)
|
||||||
|
}
|
||||||
|
lines = strings.Split(string(data), "\n")
|
||||||
|
} else if stdin != "" {
|
||||||
|
lines = strings.Split(stdin, "\n")
|
||||||
|
} else {
|
||||||
|
return "[error] tail: no input (use file path or pipe from stdin)"
|
||||||
|
}
|
||||||
if n > 0 && len(lines) > n {
|
if n > 0 && len(lines) > n {
|
||||||
lines = lines[len(lines)-n:]
|
lines = lines[len(lines)-n:]
|
||||||
}
|
}
|
||||||
@@ -512,9 +571,34 @@ func FsTail(args []string, stdin string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FsWc(args []string, stdin string) string {
|
func FsWc(args []string, stdin string) string {
|
||||||
lines := len(strings.Split(stdin, "\n"))
|
var content string
|
||||||
words := len(strings.Fields(stdin))
|
var filePath string
|
||||||
chars := len(stdin)
|
for _, a := range args {
|
||||||
|
if strings.HasPrefix(a, "-") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if filePath == "" {
|
||||||
|
filePath = a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if filePath != "" {
|
||||||
|
abs, err := resolvePath(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] wc: %v", err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(abs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] wc: %v", err)
|
||||||
|
}
|
||||||
|
content = string(data)
|
||||||
|
} else if stdin != "" {
|
||||||
|
content = stdin
|
||||||
|
} else {
|
||||||
|
return "[error] wc: no input (use file path or pipe from stdin)"
|
||||||
|
}
|
||||||
|
lines := len(strings.Split(content, "\n"))
|
||||||
|
words := len(strings.Fields(content))
|
||||||
|
chars := len(content)
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "-l":
|
case "-l":
|
||||||
@@ -529,17 +613,37 @@ func FsWc(args []string, stdin string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FsSort(args []string, stdin string) string {
|
func FsSort(args []string, stdin string) string {
|
||||||
lines := strings.Split(stdin, "\n")
|
|
||||||
reverse := false
|
reverse := false
|
||||||
numeric := false
|
numeric := false
|
||||||
|
var filePath string
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
switch a {
|
switch a {
|
||||||
case "-r":
|
case "-r":
|
||||||
reverse = true
|
reverse = true
|
||||||
case "-n":
|
case "-n":
|
||||||
numeric = true
|
numeric = true
|
||||||
|
default:
|
||||||
|
if filePath == "" && !strings.HasPrefix(a, "-") {
|
||||||
|
filePath = a
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var lines []string
|
||||||
|
if filePath != "" {
|
||||||
|
abs, err := resolvePath(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] sort: %v", err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(abs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] sort: %v", err)
|
||||||
|
}
|
||||||
|
lines = strings.Split(string(data), "\n")
|
||||||
|
} else if stdin != "" {
|
||||||
|
lines = strings.Split(stdin, "\n")
|
||||||
|
} else {
|
||||||
|
return "[error] sort: no input (use file path or pipe from stdin)"
|
||||||
|
}
|
||||||
sortFunc := func(i, j int) bool {
|
sortFunc := func(i, j int) bool {
|
||||||
if numeric {
|
if numeric {
|
||||||
ni, _ := strconv.Atoi(lines[i])
|
ni, _ := strconv.Atoi(lines[i])
|
||||||
@@ -559,13 +663,31 @@ func FsSort(args []string, stdin string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FsUniq(args []string, stdin string) string {
|
func FsUniq(args []string, stdin string) string {
|
||||||
lines := strings.Split(stdin, "\n")
|
|
||||||
showCount := false
|
showCount := false
|
||||||
|
var filePath string
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
if a == "-c" {
|
if a == "-c" {
|
||||||
showCount = true
|
showCount = true
|
||||||
|
} else if filePath == "" && !strings.HasPrefix(a, "-") {
|
||||||
|
filePath = a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var lines []string
|
||||||
|
if filePath != "" {
|
||||||
|
abs, err := resolvePath(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] uniq: %v", err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(abs)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("[error] uniq: %v", err)
|
||||||
|
}
|
||||||
|
lines = strings.Split(string(data), "\n")
|
||||||
|
} else if stdin != "" {
|
||||||
|
lines = strings.Split(stdin, "\n")
|
||||||
|
} else {
|
||||||
|
return "[error] uniq: no input (use file path or pipe from stdin)"
|
||||||
|
}
|
||||||
var result []string
|
var result []string
|
||||||
var prev string
|
var prev string
|
||||||
first := true
|
first := true
|
||||||
|
|||||||
390
tools/fs_test.go
Normal file
390
tools/fs_test.go
Normal file
@@ -0,0 +1,390 @@
|
|||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gf-lt/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cfg = &config.Config{}
|
||||||
|
cfg.FilePickerDir, _ = os.Getwd()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFsLs(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
stdin string
|
||||||
|
check func(string) bool
|
||||||
|
}{
|
||||||
|
{"no args", []string{"ls"}, "", func(r string) bool { return strings.Contains(r, "fs_test.go") || strings.Contains(r, "fs.go") }},
|
||||||
|
{"long format", []string{"ls", "-l"}, "", func(r string) bool { return strings.Contains(r, "f ") }},
|
||||||
|
{"all files", []string{"ls", "-a"}, "", func(r string) bool { return strings.Contains(r, ".") || strings.Contains(r, "..") }},
|
||||||
|
{"combine flags", []string{"ls", "-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"},
|
||||||
|
{"multiple", []string{"hello", "world"}, "", "hello world"},
|
||||||
|
{"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, "")
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
if !strings.Contains(result, cwd) && result != cwd {
|
||||||
|
t.Errorf("expected current dir, 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") && strings.Contains(r, "line1") }},
|
||||||
|
{"tail file", "tail -2 " + tmpFile, func(r string) bool { return strings.Contains(r, "line2") }},
|
||||||
|
{"echo | head", "echo line1 line2 line3 | head -2", func(r string) bool { return strings.Contains(r, "line") }},
|
||||||
|
{"echo | wc -l", "echo a b c | wc -l", func(r string) bool { return r == "3" }},
|
||||||
|
{"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 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user