Skip to content

Commit

Permalink
Merge pull request #73 from digitalghost-dev/0.7.2
Browse files Browse the repository at this point in the history
0.7.2
  • Loading branch information
digitalghost-dev authored Nov 21, 2024
2 parents b836db0 + a7382b6 commit c56f096
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 110 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ on:
branches:
- main
env:
VERSION_NUMBER: 'v0.7.1'
VERSION_NUMBER: 'v0.7.2'
REGISTRY_NAME: digitalghostdev/poke-cli

jobs:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img height="250" width="350" src="https://cdn.simpleicons.org/pokemon/FFCC00" alt="pokemon-logo"/>
<h1>Pokémon CLI</h1>
<img src="https://img.shields.io/github/v/release/digitalghost-dev/poke-cli?style=flat-square&logo=git&logoColor=FFCC00&label=Release%20Version&labelColor=EEE&color=FFCC00" alt="version-label">
<img src="https://img.shields.io/docker/image-size/digitalghostdev/poke-cli/v0.7.1?arch=arm64&style=flat-square&logo=docker&logoColor=FFCC00&labelColor=EEE&color=FFCC00" alt="docker-image-size">
<img src="https://img.shields.io/docker/image-size/digitalghostdev/poke-cli/v0.7.2?arch=arm64&style=flat-square&logo=docker&logoColor=FFCC00&labelColor=EEE&color=FFCC00" alt="docker-image-size">
<img src="https://img.shields.io/github/actions/workflow/status/digitalghost-dev/poke-cli/ci.yml?branch=main&style=flat-square&logo=github&logoColor=FFCC00&label=CI&labelColor=EEE&color=FFCC00">
</div>

Expand Down Expand Up @@ -40,7 +40,7 @@ _Taskfile can build the executable for you_
_Use a Docker Image_

```bash
docker run --rm -it digitalghostdev/poke-cli:v0.7.1 [command] [subcommand] [flag]
docker run --rm -it digitalghostdev/poke-cli:v0.7.2 [command] [subcommand] [flag]
```

### Go Build
Expand Down
163 changes: 77 additions & 86 deletions cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,63 @@ package main

import (
"bytes"
"fmt"
"io"
"os"
"regexp"
"testing"
)

// Strip ANSI color codes
var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*m`)

func stripANSI(input string) string {
return ansiRegex.ReplaceAllString(input, "")
}
func captureOutput(f func()) string {
var buf bytes.Buffer
stdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

func TestMainFunction(t *testing.T) {
version := "v0.7.0"
f()

// Backup the original exit function and stdout/stderr
originalExit := exit
originalStdout := os.Stdout
originalStderr := os.Stderr
defer func() {
exit = originalExit // Restore exit
os.Stdout = originalStdout // Restore stdout
os.Stderr = originalStderr // Restore stderr
}()
_ = w.Close()
os.Stdout = stdout
_, _ = buf.ReadFrom(r)

// Replace exit with a function that captures the exit code
exitCode := 0
exit = func(code int) { exitCode = code }
return buf.String()
}

func stripANSI(input string) string {
return ansiRegex.ReplaceAllString(input, "")
}

func TestRunCLI(t *testing.T) {
tests := []struct {
name string
args []string
expectedOutput string
expectedExit int
expectedCode int
}{
{
args: []string{"pokemons"},
name: "No Arguments",
args: []string{},
expectedOutput: "╭──────────────────────────────────────────────────────╮\n" +
"│Error! │\n" +
"│ 'pokemons' is not a valid command. │\n" +
"│Welcome! This tool displays data related to Pokémon! │\n" +
"│ │\n" +
"│Available Commands: │\n" +
"│ USAGE: │\n" +
"│ poke-cli [flag] │\n" +
"│ poke-cli <command> [flag] │\n" +
"│ poke-cli <command> <subcommand> [flag] │\n" +
"│ │\n" +
"│ FLAGS: │\n" +
"│ -h, --help Shows the help menu │\n" +
"│ -l, --latest Prints the latest available │\n" +
"│ version of the program │\n" +
"│ │\n" +
"│ AVAILABLE COMMANDS: │\n" +
"│ pokemon Get details of a specific Pokémon │\n" +
"│ types Get details of a specific typing │\n" +
"│ │\n" +
"│Also run [poke-cli -h] for more info! │\n" +
"╰──────────────────────────────────────────────────────╯\n",
expectedExit: 1,
},
{
args: []string{"-l"},
expectedOutput: fmt.Sprintf("Latest Docker image version: %s\nLatest release tag: %s\n", version, version),
expectedExit: 0,
},
{
args: []string{"--latest"},
expectedOutput: fmt.Sprintf("Latest Docker image version: %s\nLatest release tag: %s\n", version, version),
expectedExit: 0,
expectedCode: 0,
},
{
name: "Help Flag Short",
args: []string{"-h"},
expectedOutput: "╭──────────────────────────────────────────────────────╮\n" +
"│Welcome! This tool displays data related to Pokémon! │\n" +
Expand All @@ -81,64 +77,59 @@ func TestMainFunction(t *testing.T) {
"│ pokemon Get details of a specific Pokémon │\n" +
"│ types Get details of a specific typing │\n" +
"╰──────────────────────────────────────────────────────╯\n",
expectedExit: 0,
},
{
args: []string{"pokemon", "kingambit"},
expectedOutput: "Your selected Pokémon: Kingambit\nNational Pokédex #: 983\n",
expectedExit: 0,
expectedCode: 0,
},
{
args: []string{"pokemon", "cradily", "--types"},
expectedOutput: "Your selected Pokémon: Cradily\nNational Pokédex #: 346\n──────\nTyping\nType 1: rock\nType 2: grass\n",
expectedExit: 0,
name: "Help Flag Long",
args: []string{"--help"},
expectedOutput: "╭──────────────────────────────────────────────────────╮\n" +
"│Welcome! This tool displays data related to Pokémon! │\n" +
"│ │\n" +
"│ USAGE: │\n" +
"│ poke-cli [flag] │\n" +
"│ poke-cli <command> [flag] │\n" +
"│ poke-cli <command> <subcommand> [flag] │\n" +
"│ │\n" +
"│ FLAGS: │\n" +
"│ -h, --help Shows the help menu │\n" +
"│ -l, --latest Prints the latest available │\n" +
"│ version of the program │\n" +
"│ │\n" +
"│ AVAILABLE COMMANDS: │\n" +
"│ pokemon Get details of a specific Pokémon │\n" +
"│ types Get details of a specific typing │\n" +
"╰──────────────────────────────────────────────────────╯\n",
expectedCode: 0,
},
{
args: []string{"pokemon", "giratina-altered", "--abilities"},
expectedOutput: "Your selected Pokémon: Giratina-Altered\nNational Pokédex #: 487\n─────────\nAbilities\nAbility 1: pressure\nHidden Ability: telepathy\n",
expectedExit: 0,
name: "Invalid Command",
args: []string{"invalid"},
expectedOutput: "Error!",
expectedCode: 1,
},
{
args: []string{"pokemon", "coPPeraJAH", "-t", "-a"},
expectedOutput: "Your selected Pokémon: Copperajah\nNational Pokédex #: 879\n──────\nTyping\nType 1: steel\n─────────\nAbilities\nAbility 1: sheer-force\nHidden Ability: heavy-metal\n",
expectedExit: 0,
name: "Latest Flag",
args: []string{"-l"},
expectedOutput: "Latest Docker image version: v0.7.1\nLatest release tag: v0.7.1\n",
expectedCode: 0,
},
}

for _, test := range tests {
// Create a pipe to capture output
r, w, _ := os.Pipe()
os.Stdout = w
os.Stderr = w

// Set os.Args for the test case
os.Args = append([]string{"poke-cli"}, test.args...)

// Run the main function
main()

// Close the writer and restore stdout and stderr
err := w.Close()
if err != nil {
t.Fatalf("Error closing pipe writer: %v", err)
}
os.Stdout = originalStdout
os.Stderr = originalStderr

// Read from the pipe
var buf bytes.Buffer
if _, err := io.Copy(&buf, r); err != nil {
t.Errorf("Error copying output: %v", err)
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
exit = func(code int) {}
output := captureOutput(func() {
code := runCLI(tt.args)
if code != tt.expectedCode {
t.Errorf("Expected exit code %d, got %d", tt.expectedCode, code)
}
})

// Strip ANSI color codes from the actual output
actualOutput := stripANSI(buf.String())
if actualOutput != test.expectedOutput {
t.Errorf("Args: %v\nExpected output: %q\nGot: %q\n", test.args, test.expectedOutput, actualOutput)
}
output = stripANSI(output)

if exitCode != test.expectedExit {
t.Errorf("Args: %v\nExpected exit code: %d\nGot: %d\n", test.args, test.expectedExit, exitCode)
}
if !bytes.Contains([]byte(output), []byte(tt.expectedOutput)) {
t.Errorf("Expected output to contain %q, got %q", tt.expectedOutput, output)
}
})
}
}
37 changes: 37 additions & 0 deletions cmd/pokemon_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cmd

import (
"bytes"
"github.com/stretchr/testify/assert"
"os"
"testing"
)

Expand Down Expand Up @@ -49,3 +51,38 @@ func TestValidatePokemonArgs_TooManyArgs(t *testing.T) {
assert.NotEqual(t, expectedError, err.Error())
}
}

func TestPokemonCommand(t *testing.T) {
// Capture standard output
var output bytes.Buffer
stdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

// Set up test arguments (focus only on Pokémon name and command)
os.Args = []string{"poke-cli", "pokemon", "bulbasaur"}

// Call the function
PokemonCommand()

// Close and restore stdout
if closeErr := w.Close(); closeErr != nil {
t.Fatalf("Failed to close pipe writer: %v", closeErr)
}
os.Stdout = stdout

_, readErr := output.ReadFrom(r)
if readErr != nil {
t.Fatalf("Failed to read from pipe: %v", readErr)
}

// Define expected output based on actual API response
expectedName := "Bulbasaur"
expectedID := "1"

// Assert output contains expected Pokémon details
assert.Contains(t, output.String(), "Your selected Pokémon:", "Output should contain Pokémon details header")
assert.Contains(t, output.String(), expectedName, "Output should contain the Pokémon name")
assert.Contains(t, output.String(), "National Pokédex #:", "Output should contain Pokémon ID header")
assert.Contains(t, output.String(), expectedID, "Output should contain the Pokémon ID")
}
7 changes: 7 additions & 0 deletions cmd/styles.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,10 @@ var (
"fairy": "#EE99EE",
}
)

// Helper function to get color for a given type name from colorMap
func getTypeColor(typeName string) string {
color := colorMap[typeName]

return color
}
22 changes: 22 additions & 0 deletions cmd/styles_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cmd

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestGetTypeColor(t *testing.T) {
// Test known types
for typeName, expectedColor := range colorMap {
t.Run(typeName, func(t *testing.T) {
color := getTypeColor(typeName)
assert.Equal(t, expectedColor, color, "Expected color for type %s to be %s", typeName, expectedColor)
})
}

// Test unknown type
t.Run("unknown type", func(t *testing.T) {
color := getTypeColor("unknown")
assert.Equal(t, "", color, "Expected color for unknown type to be an empty string")
})
}
7 changes: 0 additions & 7 deletions cmd/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,6 @@ func (m model) View() string {
return "Select a type! Hit 'Q' or 'CTRL-C' to quit.\n" + typesTableBorder.Render(m.table.View()) + "\n"
}

// Helper function to get color for a given type name from colorMap
func getTypeColor(typeName string) string {
color := colorMap[typeName]

return color
}

// Function to display type details after a type is selected
func displayTypeDetails(typesName string, endpoint string) {

Expand Down
24 changes: 24 additions & 0 deletions cmd/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,27 @@ func TestValidateTypesArgs_TooManyArgs(t *testing.T) {
assert.NotEqual(t, expectedError, err.Error())
}
}

func TestModelInit(t *testing.T) {
m := model{}
result := m.Init()

assert.Nil(t, result, "Expected Init() to return nil")
}

func TestModelView_SelectedOption(t *testing.T) {
m := model{selectedOption: "someOption"}

output := m.View()

assert.Equal(t, "", output, "Expected output to be an empty string when selectedOption is set")
}

func TestModelView_DisplayTable(t *testing.T) {
m := model{selectedOption: ""}
expectedOutput := "Select a type! Hit 'Q' or 'CTRL-C' to quit.\n" + typesTableBorder.Render(m.table.View()) + "\n"

output := m.View()

assert.Equal(t, expectedOutput, output, "Expected View output to include table view")
}
3 changes: 1 addition & 2 deletions connections/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,12 @@ type TypesJSONStruct struct {
} `json:"damage_relations"`
}

var httpGet = http.Get
var red = lipgloss.Color("#F2055C")
var errorColor = lipgloss.NewStyle().Foreground(red)

// ApiCallSetup Helper function to handle API calls and JSON unmarshalling
func ApiCallSetup(url string, target interface{}) error {
res, err := httpGet(url)
res, err := http.Get(url)
if err != nil {
return fmt.Errorf("error making GET request: %w", err)
}
Expand Down
Loading

0 comments on commit c56f096

Please sign in to comment.