package main

import (
	"testing"
)

func TestParseBasicCommand(t *testing.T) {
	sf, err := parse("test.shout", "$ echo hello\nhello\n")
	if err != nil {
		t.Fatal(err)
	}
	if len(sf.Commands) != 1 {
		t.Fatalf("expected 1 command, got %d", len(sf.Commands))
	}
	c := sf.Commands[0]
	if c.Cmd != "echo hello" {
		t.Errorf("cmd = %q, want %q", c.Cmd, "echo hello")
	}
	if len(c.Expected) != 1 || c.Expected[0] != "hello" {
		t.Errorf("expected = %v, want [hello]", c.Expected)
	}
	if c.ExitCodeType != ExitCodeNone {
		t.Errorf("exit code type = %d, want ExitCodeNone", c.ExitCodeType)
	}
}

func TestParseMultipleCommands(t *testing.T) {
	sf, err := parse("test.shout", "$ echo one\none\n\n$ echo two\ntwo\n")
	if err != nil {
		t.Fatal(err)
	}
	if len(sf.Commands) != 2 {
		t.Fatalf("expected 2 commands, got %d", len(sf.Commands))
	}
	if sf.Commands[0].Cmd != "echo one" {
		t.Errorf("cmd[0] = %q", sf.Commands[0].Cmd)
	}
	if sf.Commands[1].Cmd != "echo two" {
		t.Errorf("cmd[1] = %q", sf.Commands[1].Cmd)
	}
}

func TestParseExitCode(t *testing.T) {
	sf, err := parse("test.shout", "$ false\n[1]\n")
	if err != nil {
		t.Fatal(err)
	}
	c := sf.Commands[0]
	if c.ExitCodeType != ExitCodeExact || c.ExitCodeValue != 1 {
		t.Errorf("exit code = (%d, %d), want (Exact, 1)", c.ExitCodeType, c.ExitCodeValue)
	}
	if len(c.Expected) != 0 {
		t.Errorf("expected = %v, want []", c.Expected)
	}
}

func TestParseExitCodeWildcard(t *testing.T) {
	sf, err := parse("test.shout", "$ false\n[*]\n")
	if err != nil {
		t.Fatal(err)
	}
	c := sf.Commands[0]
	if c.ExitCodeType != ExitCodeWildcard {
		t.Errorf("exit code type = %d, want Wildcard", c.ExitCodeType)
	}
}

func TestParseExitCodeWithOutput(t *testing.T) {
	sf, err := parse("test.shout", "$ sh -c \"echo oops && exit 1\"\noops\n[*]\n")
	if err != nil {
		t.Fatal(err)
	}
	c := sf.Commands[0]
	if len(c.Expected) != 1 || c.Expected[0] != "oops" {
		t.Errorf("expected = %v, want [oops]", c.Expected)
	}
	if c.ExitCodeType != ExitCodeWildcard {
		t.Errorf("exit code type = %d, want Wildcard", c.ExitCodeType)
	}
}

func TestParseComment(t *testing.T) {
	sf, err := parse("test.shout", "$ echo hello   # this is a comment\nhello\n")
	if err != nil {
		t.Fatal(err)
	}
	if sf.Commands[0].Cmd != "echo hello" {
		t.Errorf("cmd = %q, want %q", sf.Commands[0].Cmd, "echo hello")
	}
}

func TestParseCommentInQuotes(t *testing.T) {
	sf, err := parse("test.shout", "$ echo \"keep # this\"\nkeep # this\n")
	if err != nil {
		t.Fatal(err)
	}
	if sf.Commands[0].Cmd != `echo "keep # this"` {
		t.Errorf("cmd = %q", sf.Commands[0].Cmd)
	}
}

func TestParseEnvDirective(t *testing.T) {
	sf, err := parse("test.shout", "@env GREETING=hello\n\n$ echo $GREETING\nhello\n")
	if err != nil {
		t.Fatal(err)
	}
	if len(sf.Directives) != 1 {
		t.Fatalf("expected 1 directive, got %d", len(sf.Directives))
	}
	d := sf.Directives[0]
	if d.Type != "env" || d.Key != "GREETING" || d.Value != "hello" {
		t.Errorf("directive = %+v", d)
	}
}

func TestParseSetupDirective(t *testing.T) {
	sf, err := parse("test.shout", "@setup shared.shout\n\n$ echo hi\nhi\n")
	if err != nil {
		t.Fatal(err)
	}
	if len(sf.Directives) != 1 {
		t.Fatalf("expected 1 directive, got %d", len(sf.Directives))
	}
	d := sf.Directives[0]
	if d.Type != "setup" || d.Path != "shared.shout" {
		t.Errorf("directive = %+v", d)
	}
}

func TestParseNoExpectedOutput(t *testing.T) {
	sf, err := parse("test.shout", "$ export FOO=bar\n$ echo $FOO\nbar\n")
	if err != nil {
		t.Fatal(err)
	}
	if len(sf.Commands) != 2 {
		t.Fatalf("expected 2 commands, got %d", len(sf.Commands))
	}
	if len(sf.Commands[0].Expected) != 0 {
		t.Errorf("first command expected = %v, want []", sf.Commands[0].Expected)
	}
}

func TestParseTrimsTrailingBlanks(t *testing.T) {
	sf, err := parse("test.shout", "$ echo hello\nhello\n\n\n$ echo world\nworld\n")
	if err != nil {
		t.Fatal(err)
	}
	if len(sf.Commands[0].Expected) != 1 || sf.Commands[0].Expected[0] != "hello" {
		t.Errorf("expected = %v", sf.Commands[0].Expected)
	}
}

func TestParseLineNumbers(t *testing.T) {
	sf, err := parse("test.shout", "@env X=1\n\n$ echo hello\nhello\n\n$ echo world\nworld\n")
	if err != nil {
		t.Fatal(err)
	}
	if sf.Directives[0].Line != 1 {
		t.Errorf("directive line = %d, want 1", sf.Directives[0].Line)
	}
	if sf.Commands[0].Line != 3 {
		t.Errorf("command[0] line = %d, want 3", sf.Commands[0].Line)
	}
	if sf.Commands[1].Line != 6 {
		t.Errorf("command[1] line = %d, want 6", sf.Commands[1].Line)
	}
}
