Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.7.2 #73

Merged
merged 7 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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