Skip to content

Commit

Permalink
refactor: Abstract invalid command test cases to separate files and a…
Browse files Browse the repository at this point in the history
…dd reflection handling
  • Loading branch information
andy1li committed Dec 26, 2024
1 parent caa1360 commit cd67de2
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 66 deletions.
27 changes: 3 additions & 24 deletions internal/stage2.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package internal

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"
Expand All @@ -20,27 +16,10 @@ 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
testCase := test_cases.InvalidCommandTestCase{
Command: getRandomInvalidCommand(),
}

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 := testCase.RunAndTestReflection(asserter, shell, logger); err != nil {
return err
}

Expand Down
21 changes: 5 additions & 16 deletions internal/stage3.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package internal

import (
"fmt"
"regexp"
"strconv"

"github.com/codecrafters-io/shell-tester/internal/logged_shell_asserter"
Expand All @@ -17,26 +15,17 @@ 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)
numberOfCommands := random.RandomInt(3, 6)

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",
for i := 0; i < numberOfCommands; i++ {
testCase := test_cases.InvalidCommandTestCase{
Command: "invalid_command_" + strconv.Itoa(i+1),
}

if err := testCase.Run(asserter, shell, logger); err != nil {
if err := testCase.RunAndTestResponse(asserter, shell, logger); err != nil {
return err
}
}
Expand Down
14 changes: 3 additions & 11 deletions internal/stage4.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package internal
import (
"errors"
"fmt"
"regexp"
"strings"

"github.com/codecrafters-io/shell-tester/internal/logged_shell_asserter"
Expand All @@ -23,17 +22,10 @@ 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",
testCase := test_cases.InvalidCommandTestCase{
Command: getRandomInvalidCommand(),
}

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

Expand Down
9 changes: 2 additions & 7 deletions internal/stage6.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,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",
testCase := test_cases.InvalidCommandTypeTestCase{
Command: invalidCommand,
}
if err := testCase.Run(asserter, shell, logger); err != nil {
return err
Expand Down
12 changes: 4 additions & 8 deletions internal/stage7.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,11 @@ func testType2(stageHarness *test_case_harness.TestCaseHarness) error {
}
}

nonAvailableExecutables := getRandomInvalidCommands(2)
invalidCommands := 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",
for _, command := range invalidCommands {
testCase := test_cases.InvalidCommandTypeTestCase{
Command: command,
}
if err := testCase.Run(asserter, shell, logger); err != nil {
return err
Expand Down
59 changes: 59 additions & 0 deletions internal/test_cases/invalid_command_test_case.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package test_cases

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/tester-utils/logger"
)

type InvalidCommandTestCase struct {
Command string
}

func (t *InvalidCommandTestCase) RunAndTestReflection(asserter *logged_shell_asserter.LoggedShellAsserter, shell *shell_executable.ShellExecutable, logger *logger.Logger) error {
testCase := CommandReflectionTestCase{
Command: t.Command,
SkipPromptAssertion: true,
}
if err := testCase.Run(asserter, shell, logger, true); err != nil {
return err
}

asserter.AddAssertion(assertions.SingleLineAssertion{
ExpectedOutput: t.getExpectedOutput(),
FallbackPatterns: t.getFallbackPatterns(),
})

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

return nil
}

func (t *InvalidCommandTestCase) RunAndTestResponse(asserter *logged_shell_asserter.LoggedShellAsserter, shell *shell_executable.ShellExecutable, logger *logger.Logger) error {
testCase := CommandResponseTestCase{
Command: t.Command,
ExpectedOutput: t.getExpectedOutput(),
FallbackPatterns: t.getFallbackPatterns(),
SuccessMessage: "✓ Received command not found message",
}

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

return nil
}

func (t *InvalidCommandTestCase) getExpectedOutput() string {
return fmt.Sprintf("%s: command not found", t.Command)
}

func (t *InvalidCommandTestCase) getFallbackPatterns() []*regexp.Regexp {
return []*regexp.Regexp{regexp.MustCompile(`^(bash: )?` + t.Command + `: (command )?not found$`)}
}
37 changes: 37 additions & 0 deletions internal/test_cases/invalid_command_type_test_case.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package test_cases

import (
"fmt"
"regexp"

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

type InvalidCommandTypeTestCase struct {
Command string
}

func (t *InvalidCommandTypeTestCase) Run(asserter *logged_shell_asserter.LoggedShellAsserter, shell *shell_executable.ShellExecutable, logger *logger.Logger) error {
testCase := CommandResponseTestCase{
Command: "type " + t.Command,
ExpectedOutput: t.getExpectedOutput(),
FallbackPatterns: t.getFallbackPatterns(),
SuccessMessage: "✓ Received command not found message",
}

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

return nil
}

func (t *InvalidCommandTypeTestCase) getExpectedOutput() string {
return fmt.Sprintf("%s: not found", t.Command)
}

func (t *InvalidCommandTypeTestCase) getFallbackPatterns() []*regexp.Regexp {
return []*regexp.Regexp{regexp.MustCompile(fmt.Sprintf(`^(bash: type: )?%s[:]? not found$`, t.Command))}
}

0 comments on commit cd67de2

Please sign in to comment.