diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 274a82b..a7ab943 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ on: branches: - main env: - VERSION_NUMBER: 'v0.7.2' + VERSION_NUMBER: 'v0.8.0' REGISTRY_NAME: digitalghostdev/poke-cli jobs: diff --git a/README.md b/README.md index c6cd511..2cd321b 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,13 @@ pokemon-logo

Pokémon CLI

version-label - docker-image-size + docker-image-size ci-status-badge -
tests-label go-version - +
## Overview @@ -20,7 +19,7 @@ My aim is to have four commands finished for `v1.0.0`. Read more in the [Roadmap --- ## Demo -![demo](https://pokemon-objects.nyc3.digitaloceanspaces.com/demo_0.7.2.gif) +![demo](https://pokemon-objects.nyc3.digitaloceanspaces.com/demo-v0.8.0.gif) --- ## Install @@ -35,7 +34,19 @@ _Download a pre-built binary_ 5. Either change directories into the extracted folder or move the binary to a chosen directory. 6. Run the tool! -* Example usage: +> [!IMPORTANT] +> For macOS, you may have to allow the executable to run as it is not signed. Head to System Settings > Privacy & Security > scroll down and allow executable to run. + +
+ +View Image of Settings + +![settings](https://pokemon-objects.nyc3.digitaloceanspaces.com/macos_settings.png) + +
+ + + #### Example usage ```bash # Windows .\poke-cli.exe pokemon charizard --types --abilities @@ -57,7 +68,7 @@ _Use a Docker Image_ * Necessary. ```bash -docker run --rm -i -t digitalghostdev/poke-cli:v0.7.2 [subcommand] flag] +docker run --rm -i -t digitalghostdev/poke-cli:v0.8.0 [subcommand] flag] ``` ### Go Install @@ -103,11 +114,10 @@ The architecture behind how the tool works is straight forward. _Not 100% up-to-date, may add or remove some of these choices_ - [ ] `pokemon`: get data about a specific Pokémon. - - [x] `--abilities | -a`: display the Pokémon's abilities. - - [x] `--types | -t`: display the Pokémon's typing. - - [ ] `--stats | -s`: display the Pokémon's base stats. - - [ ] `--metrics | -m`: display the Pokémon's metrics. (height, weight, etc.) -- [ ] `types`: get data about a specific typing. - - [ ] `--chart | -c`: display the type's damage chart. Undecided. + - [x] `-a | --abilities`: display the Pokémon's abilities. + - [x] `-s | --stats`: display the Pokémon's base stats. + - [x] `-t | --types`: display the Pokémon's typing. + - [ ] `-m | --moves`: display learnable moves. +- [x] `types`: get data about a specific typing. - [ ] `ability`: get data about a specific ability. -- [ ] `moves`: get data about a specific move. \ No newline at end of file +- [ ] `move`: get data about a specific move. \ No newline at end of file diff --git a/cli_test.go b/cli_test.go index e797a2e..ad5f0d5 100644 --- a/cli_test.go +++ b/cli_test.go @@ -110,7 +110,7 @@ func TestRunCLI(t *testing.T) { { name: "Latest Flag", args: []string{"-l"}, - expectedOutput: "Latest Docker image version: v0.7.1\nLatest release tag: v0.7.1\n", + expectedOutput: "Latest Docker image version: v0.7.2\nLatest release tag: v0.7.2\n", expectedCode: 0, }, } diff --git a/cmd/pokemon.go b/cmd/pokemon.go index 6996866..32f56ee 100644 --- a/cmd/pokemon.go +++ b/cmd/pokemon.go @@ -7,6 +7,7 @@ import ( "github.com/digitalghost-dev/poke-cli/flags" "golang.org/x/text/cases" "golang.org/x/text/language" + "math" "os" "strings" ) @@ -22,16 +23,17 @@ func PokemonCommand() { fmt.Sprintf("\n\t%-30s", styleItalic.Render("Use a hyphen when typing a name with a space.")), "\n\n", styleBold.Render("FLAGS:"), - fmt.Sprintf("\n\t%-30s %s", "-a, --abilities", "Prints out the Pokémon's abilities."), - fmt.Sprintf("\n\t%-30s %s", "-t, --types", "Prints out the Pokémon's typing."), - fmt.Sprintf("\n\t%-30s %s", "-h, --help", "Prints out the help menu."), + fmt.Sprintf("\n\t%-30s %s", "-a, --abilities", "Prints the Pokémon's abilities."), + fmt.Sprintf("\n\t%-30s %s", "-s, --stats", "Prints the Pokémon's base stats."), + fmt.Sprintf("\n\t%-30s %s", "-t, --types", "Prints the Pokémon's typing."), + fmt.Sprintf("\n\t%-30s %s", "-h, --help", "Prints the help menu."), ) fmt.Println(helpMessage) } flag.Parse() - pokeFlags, typesFlag, shortTypesFlag, abilitiesFlag, shortAbilitiesFlag := flags.SetupPokemonFlagSet() + pokeFlags, abilitiesFlag, shortAbilitiesFlag, statsFlag, shortStatsFlag, typesFlag, shortTypesFlag := flags.SetupPokemonFlagSet() args := os.Args @@ -50,10 +52,36 @@ func PokemonCommand() { os.Exit(1) } - _, pokemonName, pokemonID := connections.PokemonApiCall(endpoint, pokemonName, "https://pokeapi.co/api/v2/") + _, pokemonName, pokemonID, pokemonWeight, pokemonHeight := connections.PokemonApiCall(endpoint, pokemonName, "https://pokeapi.co/api/v2/") capitalizedString := cases.Title(language.English).String(pokemonName) - fmt.Printf("Your selected Pokémon: %s\nNational Pokédex #: %d\n", capitalizedString, pokemonID) + // Weight calculation + weightKilograms := float64(pokemonWeight) / 10 + weightPounds := float64(weightKilograms) * 2.20462 + + // Height calculation + heightMeters := float64(pokemonHeight) / 10 + heightFeet := heightMeters * 3.28084 + feet := int(heightFeet) + inches := int(math.Round((heightFeet - float64(feet)) * 12)) // Use math.Round to avoid truncation + + // Adjust for rounding to 12 inches (carry over to the next foot) + if inches == 12 { + feet++ + inches = 0 + } + + fmt.Printf( + "Your selected Pokémon: %s\nNational Pokédex #: %d\nWeight: %.1fkg (%.1f lbs)\nHeight: %.1fm (%d′%02d″)\n", + capitalizedString, pokemonID, weightKilograms, weightPounds, heightFeet, feet, inches, + ) + + if *abilitiesFlag || *shortAbilitiesFlag { + if err := flags.AbilitiesFlag(endpoint, pokemonName); err != nil { + fmt.Printf("Error: %s\n", err) + os.Exit(1) + } + } if *typesFlag || *shortTypesFlag { if err := flags.TypesFlag(endpoint, pokemonName); err != nil { @@ -62,8 +90,8 @@ func PokemonCommand() { } } - if *abilitiesFlag || *shortAbilitiesFlag { - if err := flags.AbilitiesFlag(endpoint, pokemonName); err != nil { + if *statsFlag || *shortStatsFlag { + if err := flags.StatsFlag(endpoint, pokemonName); err != nil { fmt.Printf("Error: %s\n", err) os.Exit(1) } diff --git a/cmd/pokemon_test.go b/cmd/pokemon_test.go index 7eb5140..ed4b723 100644 --- a/cmd/pokemon_test.go +++ b/cmd/pokemon_test.go @@ -76,13 +76,6 @@ func TestPokemonCommand(t *testing.T) { 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") + assert.Equal(t, output.String(), "Your selected Pokémon: Bulbasaur\nNational Pokédex #: 1\nWeight: 6.9kg (15.2 lbs)\nHeight: 2.3m (2′04″)\n") } diff --git a/cmd/validateargs.go b/cmd/validateargs.go index 16c4d91..5355e87 100644 --- a/cmd/validateargs.go +++ b/cmd/validateargs.go @@ -31,7 +31,7 @@ func ValidatePokemonArgs(args []string) error { return fmt.Errorf("%s", errMessage) } - if len(args) > 5 { + if len(args) > 6 { errMessage := errorBorder.Render(errorColor.Render("Error!"), "\nToo many arguments") return fmt.Errorf("%s", errMessage) } diff --git a/connections/connection.go b/connections/connection.go index fab11e8..df2c12f 100644 --- a/connections/connection.go +++ b/connections/connection.go @@ -11,15 +11,10 @@ import ( ) type PokemonJSONStruct struct { - Name string `json:"name"` - ID int `json:"id"` - Types []struct { - Slot int `json:"slot"` - Type struct { - Name string `json:"name"` - URL string `json:"url"` - } `json:"type"` - } `json:"types"` + Name string `json:"name"` + ID int `json:"id"` + Weight int `json:"weight"` + Height int `json:"height"` Abilities []struct { Ability struct { Name string `json:"name"` @@ -28,6 +23,19 @@ type PokemonJSONStruct struct { Hidden bool `json:"hidden"` Slot int `json:"slot"` } `json:"abilities"` + Types []struct { + Slot int `json:"slot"` + Type struct { + Name string `json:"name"` + URL string `json:"url"` + } `json:"type"` + } `json:"types"` + Stats []struct { + BaseStat int `json:"base_stat"` + Stat struct { + Name string `json:"name"` + } `json:"stat"` + } `json:"stats"` } type TypesJSONStruct struct { @@ -102,17 +110,17 @@ func ApiCallSetup(url string, target interface{}) error { return nil } -func PokemonApiCall(endpoint string, pokemonName string, baseURL string) (PokemonJSONStruct, string, int) { +func PokemonApiCall(endpoint string, pokemonName string, baseURL string) (PokemonJSONStruct, string, int, int, int) { url := baseURL + endpoint + "/" + pokemonName var pokemonStruct PokemonJSONStruct err := ApiCallSetup(url, &pokemonStruct) if err != nil { - return PokemonJSONStruct{}, "", 0 + return PokemonJSONStruct{}, "", 0, 0, 0 } - return pokemonStruct, pokemonStruct.Name, pokemonStruct.ID + return pokemonStruct, pokemonStruct.Name, pokemonStruct.ID, pokemonStruct.Weight, pokemonStruct.Height } func TypesApiCall(endpoint string, typesName string, baseURL string) (TypesJSONStruct, string, int) { diff --git a/connections/connection_test.go b/connections/connection_test.go index b2e0cf5..05f2f9d 100644 --- a/connections/connection_test.go +++ b/connections/connection_test.go @@ -9,8 +9,8 @@ import ( "testing" ) -// TestBaseApiCallSuccess - Test for the ApiCallSetup function -func TestBaseApiCallSuccess(t *testing.T) { +// TestBaseApiCall - Test for the ApiCallSetup function +func TestBaseApiCall(t *testing.T) { expectedData := map[string]string{"key": "value"} ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -30,11 +30,13 @@ func TestBaseApiCallSuccess(t *testing.T) { assert.Equal(t, expectedData, target) } -// TestPokemonApiCallSuccess - Test for the PokemonApiCall function -func TestPokemonApiCallSuccess(t *testing.T) { +// TestPokemonApiCall - Test for the PokemonApiCall function +func TestPokemonApiCall(t *testing.T) { expectedPokemon := PokemonJSONStruct{ - Name: "pikachu", - ID: 25, + Name: "pikachu", + ID: 25, + Weight: 60, + Height: 4, Types: []struct { Slot int `json:"slot"` Type struct { @@ -56,15 +58,17 @@ func TestPokemonApiCallSuccess(t *testing.T) { })) defer ts.Close() - pokemon, name, id := PokemonApiCall("/pokemon", "pikachu", ts.URL) + pokemon, name, id, weight, height := PokemonApiCall("/pokemon", "pikachu", ts.URL) assert.Equal(t, expectedPokemon, pokemon) assert.Equal(t, "pikachu", name) assert.Equal(t, 25, id) + assert.Equal(t, 60, weight) + assert.Equal(t, 4, height) } -// TestTypesApiCallSuccess - Test for the TypesApiCall function -func TestTypesApiCallSuccess(t *testing.T) { +// TestTypesApiCall - Test for the TypesApiCall function +func TestTypesApiCall(t *testing.T) { expectedTypes := TypesJSONStruct{ Name: "electric", ID: 13, diff --git a/demo.gif b/demo.gif index 2b2d24c..c5792bb 100644 Binary files a/demo.gif and b/demo.gif differ diff --git a/demo.tape b/demo.tape index 1d195ca..16eccb7 100644 --- a/demo.tape +++ b/demo.tape @@ -62,9 +62,9 @@ Require echo Set Shell "bash" Set FontSize 32 Set Width 2100 -Set Height 825 +Set Height 1100 -Type "poke-cli pokemon charizard --types --abilities" +Type "poke-cli pokemon charizard --abilities --stats --types" Sleep 1s diff --git a/flags/pokemonflagset.go b/flags/pokemonflagset.go index 28431ec..81550f8 100644 --- a/flags/pokemonflagset.go +++ b/flags/pokemonflagset.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/charmbracelet/lipgloss" "github.com/digitalghost-dev/poke-cli/connections" + "strings" ) var ( @@ -16,38 +17,47 @@ var ( styleBold = lipgloss.NewStyle().Bold(true) ) -func SetupPokemonFlagSet() (*flag.FlagSet, *bool, *bool, *bool, *bool) { +func header(header string) { + HeaderBold := lipgloss.NewStyle(). + BorderStyle(lipgloss.NormalBorder()). + BorderForeground(lipgloss.Color("#FFCC00")). + BorderTop(true). + Bold(true). + Render(header) + + fmt.Println(HeaderBold) +} + +func SetupPokemonFlagSet() (*flag.FlagSet, *bool, *bool, *bool, *bool, *bool, *bool) { pokeFlags := flag.NewFlagSet("pokeFlags", flag.ExitOnError) - typesFlag := pokeFlags.Bool("types", false, "Print the declared Pokémon's typing") - shortTypesFlag := pokeFlags.Bool("t", false, "Prints the declared Pokémon's typing") + abilitiesFlag := pokeFlags.Bool("abilities", false, "Print the Pokémon's abilities") + shortAbilitiesFlag := pokeFlags.Bool("a", false, "Print the Pokémon's abilities") + + statsFlag := pokeFlags.Bool("stats", false, "Print the Pokémon's base stats") + shortStatsFlag := pokeFlags.Bool("s", false, "Print the Pokémon's base stats") - abilitiesFlag := pokeFlags.Bool("abilities", false, "Print the declared Pokémon's abilities") - shortAbilitiesFlag := pokeFlags.Bool("a", false, "Print the declared Pokémon's abilities") + typesFlag := pokeFlags.Bool("types", false, "Print the Pokémon's typing") + shortTypesFlag := pokeFlags.Bool("t", false, "Prints the Pokémon's typing") pokeFlags.Usage = func() { fmt.Println( helpBorder.Render("poke-cli pokemon [flags]", styleBold.Render("\n\nFLAGS:"), "\n\t", "-a, --abilities", "\t", "Prints out the Pokémon's abilities.", - "\n\t", "-t, --types", "\t\t", "Prints out the Pokémon's typing."), + "\n\t", "-t, --types", "\t\t", "Prints out the Pokémon's typing.", "\n\t", "-s, --stats", "\t\t", + "Prints out the Pokémon's base stats."), ) } - return pokeFlags, typesFlag, shortTypesFlag, abilitiesFlag, shortAbilitiesFlag + return pokeFlags, abilitiesFlag, shortAbilitiesFlag, statsFlag, shortStatsFlag, typesFlag, shortTypesFlag } func AbilitiesFlag(endpoint string, pokemonName string) error { baseURL := "https://pokeapi.co/api/v2/" - pokemonStruct, _, _ := connections.PokemonApiCall(endpoint, pokemonName, baseURL) + pokemonStruct, _, _, _, _ := connections.PokemonApiCall(endpoint, pokemonName, baseURL) - abilitiesHeaderBold := lipgloss.NewStyle(). - BorderStyle(lipgloss.NormalBorder()). - BorderForeground(lipgloss.Color("#FFCC00")). - BorderTop(true). - Bold(true). - Render("Abilities") + header("Abilities") - fmt.Println(abilitiesHeaderBold) for _, pokeAbility := range pokemonStruct.Abilities { if pokeAbility.Slot == 1 { fmt.Printf("Ability %d: %s\n", pokeAbility.Slot, pokeAbility.Ability.Name) @@ -61,9 +71,88 @@ func AbilitiesFlag(endpoint string, pokemonName string) error { return nil } +func StatsFlag(endpoint string, pokemonName string) error { + baseURL := "https://pokeapi.co/api/v2/" + pokemonStruct, _, _, _, _ := connections.PokemonApiCall(endpoint, pokemonName, baseURL) + + header("Base Stats") + + // Helper function to map stat values to categories + getStatCategory := func(value int) string { + switch { + case value < 20: + return "lowest" + case value < 60: + return "lower" + case value < 90: + return "low" + case value < 120: + return "high" + case value < 150: + return "higher" + default: + return "highest" + } + } + + // Helper function to print the bar for a stat + printBar := func(label string, value, maxWidth, maxValue int, style lipgloss.Style) { + scaledValue := (value * maxWidth) / maxValue + bar := strings.Repeat("▇", scaledValue) + coloredBar := style.Render(bar) + fmt.Printf("%-10s %s %d\n", label, coloredBar, value) + } + + // Mapping from API stat names to custom display names + nameMapping := map[string]string{ + "hp": "HP", + "attack": "Atk", + "defense": "Def", + "special-attack": "Sp. Atk", + "special-defense": "Sp. Def", + "speed": "Speed", + } + + statColorMap := map[string]string{ + "lowest": "#F34444", + "lower": "#FF7F0F", + "low": "#FFDD57", + "high": "#A0E515", + "higher": "#22C65A", + "highest": "#00C2B8", + } + + // Find the maxium stat value + maxValue := 0 + for _, stat := range pokemonStruct.Stats { + if stat.BaseStat > maxValue { + maxValue = stat.BaseStat + } + } + + maxWidth := 45 + + // Print bars for each stat + for _, stat := range pokemonStruct.Stats { + apiName := stat.Stat.Name + customName, exists := nameMapping[apiName] + if !exists { + continue + } + + category := getStatCategory(stat.BaseStat) + color := statColorMap[category] + style := lipgloss.NewStyle().Foreground(lipgloss.Color(color)) + + printBar(customName, stat.BaseStat, maxWidth, maxValue, style) + } + + return nil +} + func TypesFlag(endpoint string, pokemonName string) error { baseURL := "https://pokeapi.co/api/v2/" - pokemonStruct, _, _ := connections.PokemonApiCall(endpoint, pokemonName, baseURL) + pokemonStruct, _, _, _, _ := connections.PokemonApiCall(endpoint, pokemonName, baseURL) colorMap := map[string]string{ "normal": "#B7B7A9", @@ -86,14 +175,8 @@ func TypesFlag(endpoint string, pokemonName string) error { "fairy": "#EE99EE", } - typingHeaderBold := lipgloss.NewStyle(). - BorderStyle(lipgloss.NormalBorder()). - BorderForeground(lipgloss.Color("#FFCC00")). - BorderTop(true). - Bold(true). - Render("Typing") + header("Typing") - fmt.Println(typingHeaderBold) for _, pokeType := range pokemonStruct.Types { colorHex, exists := colorMap[pokeType.Type.Name] if exists { diff --git a/flags/pokemonflagset_test.go b/flags/pokemonflagset_test.go index aaa1569..8fd797e 100644 --- a/flags/pokemonflagset_test.go +++ b/flags/pokemonflagset_test.go @@ -4,18 +4,32 @@ import ( "bytes" "github.com/stretchr/testify/assert" "os" + "regexp" "testing" ) +func stripANSI(input string) string { + ansiRegex := regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`) + return ansiRegex.ReplaceAllString(input, "") +} + func TestSetupPokemonFlagSet(t *testing.T) { // Call the function to get the flag set and types flag - pokeFlags, typesFlag, shortTypesFlag, abilitiesFlag, shortAbilitiesFlag := SetupPokemonFlagSet() + pokeFlags, abilitiesFlag, shortAbilitiesFlag, statsFlag, shortStatsFlag, typesFlag, shortTypesFlag := SetupPokemonFlagSet() // Assertions assert.NotNil(t, pokeFlags, "Flag set should not be nil") assert.Equal(t, "pokeFlags", pokeFlags.Name(), "Flag set name should be 'pokeFlags'") //assert.Equal(t, flag.ExitOnError, pokeFlags.NFlag(), "Flag set should have ExitOnError behavior") + // Check abilities flag + assert.NotNil(t, abilitiesFlag, "Abilities flag should not be nil") + assert.Equal(t, false, *abilitiesFlag, "Abilities flag name should be 'abilities'") + + // Check short abilities flag + assert.NotNil(t, shortAbilitiesFlag, "Short abilities flag should not be nil") + assert.Equal(t, false, *shortAbilitiesFlag, "Short abilities flag name should be 'a'") + // Check types flag assert.NotNil(t, typesFlag, "Types flag should not be nil") assert.Equal(t, false, *typesFlag, "Types flag name should be 'types'") @@ -25,12 +39,12 @@ func TestSetupPokemonFlagSet(t *testing.T) { assert.Equal(t, false, *shortTypesFlag, "Short types flag name should be 't'") // Check abilities flag - assert.NotNil(t, abilitiesFlag, "Abilities flag should not be nil") - assert.Equal(t, false, *abilitiesFlag, "Abilities flag name should be 'abilities'") + assert.NotNil(t, statsFlag, "Stats flag should not be nil") + assert.Equal(t, false, *statsFlag, "Stats flag name should be 'abilities'") // Check short abilities flag - assert.NotNil(t, shortAbilitiesFlag, "Short abilities flag should not be nil") - assert.Equal(t, false, *shortAbilitiesFlag, "Short abilities flag name should be 'a'") + assert.NotNil(t, shortStatsFlag, "Short stats flag should not be nil") + assert.Equal(t, false, *shortStatsFlag, "Short stats flag name should be 'a'") } func TestAbilitiesFlag(t *testing.T) { @@ -65,10 +79,51 @@ Hidden Ability: chlorophyll ` // Assert the actual output matches the expected output - assert.Contains(t, output.String(), "Abilities", "Output should contain 'Abilities'") - assert.Contains(t, output.String(), "Ability 1: overgrow", "Output should contain 'Ability 1: overgrow'") - assert.Contains(t, output.String(), "Hidden Ability: chlorophyll", "Output should contain 'Ability 2: chlorophyll'") - assert.Equal(t, expectedOutput, output.String(), "Output does not match the expected formatting") + actualOutput := stripANSI(output.String()) + + assert.Equal(t, expectedOutput, actualOutput, "Output should contain data for the abilities flag") +} + +func TestStatsFlag(t *testing.T) { + // Capture standard output + var output bytes.Buffer + stdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + // Call the StatsFlag function with a valid Pokémon + err := StatsFlag("pokemon", "bulbasaur") + + // 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) + } + + // Assert no errors occurred + assert.NoError(t, err, "StatsFlag should not return an error for a valid Pokémon") + + // Define expected output components + expectedOutput := `────────── +Base Stats +HP ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 45 +Atk ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 49 +Def ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 49 +Sp. Atk ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 65 +Sp. Def ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 65 +Speed ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 45 +` + + // Assert output contains the expected header and typing information + actualOutput := stripANSI(output.String()) + + assert.Equal(t, expectedOutput, actualOutput, "Output should contain data for the stats flag") + } func TestTypesFlag(t *testing.T) { @@ -96,12 +151,14 @@ func TestTypesFlag(t *testing.T) { assert.NoError(t, err, "TypesFlag should not return an error for a valid Pokémon") // Define expected output components - expectedHeader := "Typing" - expectedType1 := "Type 1: grass" - expectedType2 := "Type 2: poison" + expectedOutput := `────── +Typing +Type 1: grass +Type 2: poison +` // Assert output contains the expected header and typing information - assert.Contains(t, output.String(), expectedHeader, "Output should contain the 'Typing' header") - assert.Contains(t, output.String(), expectedType1, "Output should contain the Pokémon's first type") - assert.Contains(t, output.String(), expectedType2, "Output should contain the Pokémon's second type") + actualOutput := stripANSI(output.String()) + + assert.Equal(t, expectedOutput, actualOutput, "Output should contain data for the types flag") }