Skip to content

Commit

Permalink
Refactor out invalid_command
Browse files Browse the repository at this point in the history
  • Loading branch information
andy1li committed Dec 24, 2024
1 parent caa1360 commit 391f94b
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 125 deletions.
114 changes: 114 additions & 0 deletions internal/invalid_command/invalid_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package invalid_command

import (
"fmt"
"regexp"

"github.com/codecrafters-io/shell-tester/internal/assertions"
"github.com/codecrafters-io/shell-tester/internal/logged_shell_asserter"
"github.com/codecrafters-io/shell-tester/internal/shell_executable"
"github.com/codecrafters-io/shell-tester/internal/test_cases"
"github.com/codecrafters-io/tester-utils/logger"
"github.com/codecrafters-io/tester-utils/random"
)

func getExpectedOutputForCommand(invalidCommand string) string {
return fmt.Sprintf("%s: command not found", invalidCommand)
}

func getExpectedOutputForType(invalidCommand string) string {
return fmt.Sprintf("%s: not found", invalidCommand)
}

func getFallbackPatternsForCommand(invalidCommand string) []*regexp.Regexp {
return []*regexp.Regexp{regexp.MustCompile(`^(bash: )?` + invalidCommand + `: (command )?not found$`)}
}

func getFallbackPatternsForType(invalidCommand string) []*regexp.Regexp {
return []*regexp.Regexp{regexp.MustCompile(fmt.Sprintf(`^(bash: type: )?%s[:]? not found$`, invalidCommand))}
}

func getRandomInvalidCommand() string {
return "invalid_" + random.RandomWord() + "_command"
}

func getRandomInvalidCommands(n int) []string {
words := random.RandomWords(n)
invalidCommands := make([]string, n)

for i := 0; i < n; i++ {
invalidCommands[i] = "invalid_" + words[i] + "_command"
}

return invalidCommands
}

func TestCommandReflection(asserter *logged_shell_asserter.LoggedShellAsserter, shell *shell_executable.ShellExecutable, logger *logger.Logger) error {
invalidCommand := getRandomInvalidCommand()

// We are seperating this out because we don't want to assert
// The prompt at the end
testCase := test_cases.CommandReflectionTestCase{
Command: invalidCommand,
SkipPromptAssertion: true,
}
if err := testCase.Run(asserter, shell, logger, true); err != nil {
return err
}

asserter.AddAssertion(assertions.SingleLineAssertion{
ExpectedOutput: getExpectedOutputForCommand(invalidCommand),
FallbackPatterns: getFallbackPatternsForCommand(invalidCommand),
})

if err := asserter.AssertWithoutPrompt(); err != nil {
return err
}

return nil
}

func TestCommandResponse(asserter *logged_shell_asserter.LoggedShellAsserter, shell *shell_executable.ShellExecutable, logger *logger.Logger) error {
return TestCommandResponses(asserter, shell, logger, 1)
}

func TestCommandResponses(asserter *logged_shell_asserter.LoggedShellAsserter, shell *shell_executable.ShellExecutable, logger *logger.Logger, numberOfCommands int) error {
invalidCommands := getRandomInvalidCommands(numberOfCommands)

for i := 0; i < numberOfCommands; i++ {
invalidCommand := invalidCommands[i]

testCase := test_cases.CommandResponseTestCase{
Command: invalidCommand,
ExpectedOutput: getExpectedOutputForCommand(invalidCommand),
FallbackPatterns: getFallbackPatternsForCommand(invalidCommand),
SuccessMessage: "✓ Received command not found message",
}

if err := testCase.Run(asserter, shell, logger); err != nil {
return err
}
}

return nil
}

func TestTypeResponses(asserter *logged_shell_asserter.LoggedShellAsserter, shell *shell_executable.ShellExecutable, logger *logger.Logger, numberOfCommands int) error {
invalidCommands := getRandomInvalidCommands(2)

for _, invalidCommand := range invalidCommands {
command := fmt.Sprintf("type %s", invalidCommand)

testCase := test_cases.CommandResponseTestCase{
Command: command,
ExpectedOutput: getExpectedOutputForType(invalidCommand),
FallbackPatterns: getFallbackPatternsForType(invalidCommand),
SuccessMessage: "✓ Received expected response",
}
if err := testCase.Run(asserter, shell, logger); err != nil {
return err
}
}

return nil
}
28 changes: 2 additions & 26 deletions internal/stage2.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package internal

import (
"fmt"
"regexp"

"github.com/codecrafters-io/shell-tester/internal/assertions"
"github.com/codecrafters-io/shell-tester/internal/invalid_command"
"github.com/codecrafters-io/shell-tester/internal/logged_shell_asserter"
"github.com/codecrafters-io/shell-tester/internal/shell_executable"
"github.com/codecrafters-io/shell-tester/internal/test_cases"
"github.com/codecrafters-io/tester-utils/test_case_harness"
)

Expand All @@ -20,27 +16,7 @@ func testInvalidCommand(stageHarness *test_case_harness.TestCaseHarness) error {
return err
}

invalidCommand := getRandomInvalidCommand()

// We are seperating this out because we don't want to assert
// The prompt at the end
testCase := test_cases.CommandReflectionTestCase{
Command: invalidCommand,
SkipPromptAssertion: true,
}
if err := testCase.Run(asserter, shell, logger, true); err != nil {
return err
}

asserter.AddAssertion(assertions.SingleLineAssertion{
ExpectedOutput: fmt.Sprintf("%s: command not found", invalidCommand),
FallbackPatterns: []*regexp.Regexp{
regexp.MustCompile(fmt.Sprintf(`^bash: %s: command not found$`, invalidCommand)),
regexp.MustCompile(fmt.Sprintf(`^%s: command not found$`, invalidCommand)),
},
})

if err := asserter.AssertWithoutPrompt(); err != nil {
if err := invalid_command.TestCommandReflection(asserter, shell, logger); err != nil {
return err
}

Expand Down
26 changes: 4 additions & 22 deletions internal/stage3.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package internal

import (
"fmt"
"regexp"
"strconv"

"github.com/codecrafters-io/shell-tester/internal/invalid_command"
"github.com/codecrafters-io/shell-tester/internal/logged_shell_asserter"
"github.com/codecrafters-io/shell-tester/internal/shell_executable"
"github.com/codecrafters-io/shell-tester/internal/test_cases"
"github.com/codecrafters-io/tester-utils/random"
"github.com/codecrafters-io/tester-utils/test_case_harness"
)
Expand All @@ -17,28 +13,14 @@ func testREPL(stageHarness *test_case_harness.TestCaseHarness) error {
shell := shell_executable.NewShellExecutable(stageHarness)
asserter := logged_shell_asserter.NewLoggedShellAsserter(shell)

numberOfCommands := random.RandomInt(3, 6)

if err := startShellAndAssertPrompt(asserter, shell); err != nil {
return err
}

for i := 0; i < numberOfCommands; i++ {
command := "invalid_command_" + strconv.Itoa(i+1)

testCase := test_cases.CommandResponseTestCase{
Command: command,
ExpectedOutput: fmt.Sprintf("%s: command not found", command),
FallbackPatterns: []*regexp.Regexp{
regexp.MustCompile(fmt.Sprintf(`^bash: %s: command not found$`, command)),
regexp.MustCompile(fmt.Sprintf(`^%s: command not found$`, command)),
},
SuccessMessage: "✓ Received command not found message",
}
numberOfCommands := random.RandomInt(3, 6)

if err := testCase.Run(asserter, shell, logger); err != nil {
return err
}
if err := invalid_command.TestCommandResponses(asserter, shell, logger, numberOfCommands); err != nil {
return err
}

// AssertWithPrompt() already makes sure that the prompt is present in the last row
Expand Down
14 changes: 2 additions & 12 deletions internal/stage4.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package internal
import (
"errors"
"fmt"
"regexp"
"strings"

"github.com/codecrafters-io/shell-tester/internal/invalid_command"
"github.com/codecrafters-io/shell-tester/internal/logged_shell_asserter"
"github.com/codecrafters-io/shell-tester/internal/shell_executable"
"github.com/codecrafters-io/shell-tester/internal/test_cases"
Expand All @@ -23,17 +23,7 @@ func testExit(stageHarness *test_case_harness.TestCaseHarness) error {
return err
}

invalidCommand := getRandomInvalidCommand()

// We test a nonexistent command first, just to make sure the logic works in a "loop"
testCase := test_cases.CommandResponseTestCase{
Command: invalidCommand,
ExpectedOutput: invalidCommand + ": command not found",
FallbackPatterns: []*regexp.Regexp{regexp.MustCompile(`^(bash: )?` + invalidCommand + `: (command )?not found$`)},
SuccessMessage: "✓ Received command not found message",
}

if err := testCase.Run(asserter, shell, logger); err != nil {
if err := invalid_command.TestCommandResponse(asserter, shell, logger); err != nil {
return err
}

Expand Down
17 changes: 3 additions & 14 deletions internal/stage6.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"regexp"

"github.com/codecrafters-io/shell-tester/internal/invalid_command"
"github.com/codecrafters-io/shell-tester/internal/logged_shell_asserter"
"github.com/codecrafters-io/shell-tester/internal/shell_executable"
"github.com/codecrafters-io/shell-tester/internal/test_cases"
Expand Down Expand Up @@ -35,20 +36,8 @@ func testType1(stageHarness *test_case_harness.TestCaseHarness) error {
}
}

invalidCommands := getRandomInvalidCommands(2)

for _, invalidCommand := range invalidCommands {
command := fmt.Sprintf("type %s", invalidCommand)

testCase := test_cases.CommandResponseTestCase{
Command: command,
ExpectedOutput: fmt.Sprintf("%s: not found", invalidCommand),
FallbackPatterns: []*regexp.Regexp{regexp.MustCompile(fmt.Sprintf(`^(bash: type: )?%s[:]? not found$`, invalidCommand))},
SuccessMessage: "✓ Received expected response",
}
if err := testCase.Run(asserter, shell, logger); err != nil {
return err
}
if err := invalid_command.TestTypeResponses(asserter, shell, logger, 2); err != nil {
return err
}

return logAndQuit(asserter, nil)
Expand Down
16 changes: 3 additions & 13 deletions internal/stage7.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"regexp"

"github.com/codecrafters-io/shell-tester/internal/custom_executable"
"github.com/codecrafters-io/shell-tester/internal/invalid_command"
"github.com/codecrafters-io/shell-tester/internal/logged_shell_asserter"
"github.com/codecrafters-io/shell-tester/internal/shell_executable"
"github.com/codecrafters-io/shell-tester/internal/test_cases"
Expand Down Expand Up @@ -66,19 +67,8 @@ func testType2(stageHarness *test_case_harness.TestCaseHarness) error {
}
}

nonAvailableExecutables := getRandomInvalidCommands(2)

for _, executable := range nonAvailableExecutables {
command := fmt.Sprintf("type %s", executable)
testCase := test_cases.CommandResponseTestCase{
Command: command,
ExpectedOutput: fmt.Sprintf(`%s: not found`, executable),
FallbackPatterns: []*regexp.Regexp{regexp.MustCompile(fmt.Sprintf(`^(bash: type: )?%s: not found$`, executable))},
SuccessMessage: "✓ Received expected response",
}
if err := testCase.Run(asserter, shell, logger); err != nil {
return err
}
if err := invalid_command.TestTypeResponses(asserter, shell, logger, 2); err != nil {
return err
}

return logAndQuit(asserter, nil)
Expand Down
26 changes: 16 additions & 10 deletions internal/test_helpers/fixtures/base/pass
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ Debug = true

[stage-4] Running tests for Stage #4: pn5
[stage-4] Running ./your_shell.sh
[your-program] $ invalid_apple_command
[your-program] bash: invalid_apple_command: command not found
[your-program] $ invalid_banana_command
[your-program] bash: invalid_banana_command: command not found
[stage-4] ✓ Received command not found message
[your-program] $ exit 0
[stage-4] ✓ Program exited successfully
Expand All @@ -75,22 +75,28 @@ Debug = true

[stage-3] Running tests for Stage #3: ff0
[stage-3] Running ./your_shell.sh
[your-program] $ invalid_command_1
[your-program] bash: invalid_command_1: command not found
[your-program] $ invalid_orange_command
[your-program] bash: invalid_orange_command: command not found
[stage-3] ✓ Received command not found message
[your-program] $ invalid_strawberry_command
[your-program] bash: invalid_strawberry_command: command not found
[stage-3] ✓ Received command not found message
[your-program] $ invalid_pineapple_command
[your-program] bash: invalid_pineapple_command: command not found
[stage-3] ✓ Received command not found message
[your-program] $ invalid_command_2
[your-program] bash: invalid_command_2: command not found
[your-program] $ invalid_banana_command
[your-program] bash: invalid_banana_command: command not found
[stage-3] ✓ Received command not found message
[your-program] $ invalid_command_3
[your-program] bash: invalid_command_3: command not found
[your-program] $ invalid_mango_command
[your-program] bash: invalid_mango_command: command not found
[stage-3] ✓ Received command not found message
[your-program] $
[stage-3] Test passed.

[stage-2] Running tests for Stage #2: cz2
[stage-2] Running ./your_shell.sh
[your-program] $ invalid_banana_command
[your-program] bash: invalid_banana_command: command not found
[your-program] $ invalid_blueberry_command
[your-program] bash: invalid_blueberry_command: command not found
[stage-2] ✓ Received command not found message
[your-program] $
[stage-2] Test passed.
Expand Down
23 changes: 10 additions & 13 deletions internal/test_helpers/fixtures/navigation/pass
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ Debug = true

[stage-4] Running tests for Stage #4: pn5
[stage-4] Running ./your_shell.sh
[your-program] $ invalid_banana_command
[your-program] bash: invalid_banana_command: command not found
[your-program] $ invalid_blueberry_command
[your-program] bash: invalid_blueberry_command: command not found
[stage-4] ✓ Received command not found message
[your-program] $ exit 0
[stage-4] ✓ Program exited successfully
Expand All @@ -131,25 +131,22 @@ Debug = true

[stage-3] Running tests for Stage #3: ff0
[stage-3] Running ./your_shell.sh
[your-program] $ invalid_command_1
[your-program] bash: invalid_command_1: command not found
[your-program] $ invalid_strawberry_command
[your-program] bash: invalid_strawberry_command: command not found
[stage-3] ✓ Received command not found message
[your-program] $ invalid_command_2
[your-program] bash: invalid_command_2: command not found
[your-program] $ invalid_orange_command
[your-program] bash: invalid_orange_command: command not found
[stage-3] ✓ Received command not found message
[your-program] $ invalid_command_3
[your-program] bash: invalid_command_3: command not found
[stage-3] ✓ Received command not found message
[your-program] $ invalid_command_4
[your-program] bash: invalid_command_4: command not found
[your-program] $ invalid_apple_command
[your-program] bash: invalid_apple_command: command not found
[stage-3] ✓ Received command not found message
[your-program] $
[stage-3] Test passed.

[stage-2] Running tests for Stage #2: cz2
[stage-2] Running ./your_shell.sh
[your-program] $ invalid_apple_command
[your-program] bash: invalid_apple_command: command not found
[your-program] $ invalid_pineapple_command
[your-program] bash: invalid_pineapple_command: command not found
[stage-2] ✓ Received command not found message
[your-program] $
[stage-2] Test passed.
Expand Down
Loading

0 comments on commit 391f94b

Please sign in to comment.