Skip to content
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
20 changes: 9 additions & 11 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,26 @@ package cmd

import (
"context"
"log"
"os"
"fmt"
"io"
"strconv"

"github.com/urfave/cli/v3"
)

func Execute() {
func Execute(stdout, stderr io.Writer, args []string) {
cmd := &cli.Command{
Name: "cider",
Usage: "cli tool to help with common IP related tasks",
Commands: []*cli.Command{
newRanges(),
newIn(),
newSubnet(),
newInfo(),
newVersion(),
newRanges(stdout),
newIn(stdout),
newSubnet(stdout),
newInfo(stdout),
newVersion(stdout),
},
}

args := os.Args

// if the first arg is a number, treat it as the "ranges" command
if len(args) == 2 {
maybeNumber := args[1]
Expand All @@ -34,6 +32,6 @@ func Execute() {
}

if err := cmd.Run(context.Background(), args); err != nil {
log.Fatal(err)
fmt.Fprint(stderr, err)
}
}
44 changes: 44 additions & 0 deletions cmd/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cmd_test

import (
"bytes"
"cider/cmd"
"testing"

"github.com/stretchr/testify/assert"
)

type testCase struct {
name string
input []string
stdOutput string
stdErr string
}

func executeTestCases(t *testing.T, testCases []testCase) {
executeTestCasesWithCustomAssertion(
t,
testCases,
func(t *testing.T, tc testCase, stdout, stderr string) {
assert.Equal(t, tc.stdOutput, stdout, "std output not as expected")
assert.Equal(t, tc.stdErr, stderr, "err output not as expected")
},
)
}

func executeTestCasesWithCustomAssertion(
t *testing.T,
testCases []testCase,
assertion func(t *testing.T, tc testCase, stdout, stderr string),
) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
stdOut := new(bytes.Buffer)
stdErr := new(bytes.Buffer)

cmd.Execute(stdOut, stdErr, tc.input)

assertion(t, tc, stdOut.String(), stdErr.String())
})
}
}
5 changes: 3 additions & 2 deletions cmd/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ package cmd
import (
"cider/internal/commands/in"
"context"
"io"

"github.com/urfave/cli/v3"
)

func newIn() *cli.Command {
func newIn(stdout io.Writer) *cli.Command {
return &cli.Command{
Name: "in",
Usage: "Determine if an ip or range falls within one or more ranges",
Aliases: []string{"i"},
Action: func(_ context.Context, command *cli.Command) error {
args := command.Args().Slice()

handler := in.New()
handler := in.New(stdout)

return handler.Handle(args)
},
Expand Down
27 changes: 27 additions & 0 deletions cmd/in_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package cmd_test

import "testing"

func TestIn(t *testing.T) {
testCases := []testCase{
{
name: "missing args",
input: []string{"cider", "in"},
stdOutput: "",
stdErr: "command expects at least 2 arguments",
},
{
name: "ip inside range",
input: []string{"cider", "in", "10.164.214.32", "10.164.214.0/26"},
stdOutput: "10.164.214.0/26\n",
stdErr: "",
},
{
name: "ip outside range",
input: []string{"cider", "in", "10.164.215.0", "10.164.214.0/26"},
stdOutput: "10.164.215.0 is not in any of the provided ranges\n",
stdErr: "",
},
}
executeTestCases(t, testCases)
}
5 changes: 3 additions & 2 deletions cmd/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ package cmd
import (
"cider/internal/commands/info"
"context"
"io"

"github.com/urfave/cli/v3"
)

func newInfo() *cli.Command {
func newInfo(stdout io.Writer) *cli.Command {
return &cli.Command{
Name: "info",
Usage: "Display information about a range",
Aliases: []string{"f"},
Action: func(_ context.Context, command *cli.Command) error {
args := command.Args().Slice()

handler := info.New()
handler := info.New(stdout)

return handler.Handle(args)
},
Expand Down
21 changes: 21 additions & 0 deletions cmd/info_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cmd_test

import "testing"

func TestInfo(t *testing.T) {
testCases := []testCase{
{
name: "missing args",
input: []string{"cider", "info"},
stdOutput: "",
stdErr: "command expects exactly one argument",
},
{
name: "prints info",
input: []string{"cider", "info", "10.0.64.0/18"},
stdOutput: "Address range : 10.0.64.0 - 10.0.127.255\nStart of next block : 10.0.128.0\nMask : /18 (255.255.192.0)\nAddresses : 16384\nAzure addresses : 16379\nBinary : 00001010.00000000.01000000.00000000\nDecimal : 167788544\n",
stdErr: "",
},
}
executeTestCases(t, testCases)
}
5 changes: 3 additions & 2 deletions cmd/ranges.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ package cmd
import (
"cider/internal/commands/ranges"
"context"
"io"

"github.com/urfave/cli/v3"
)

func newRanges() *cli.Command {
func newRanges(stdout io.Writer) *cli.Command {
return &cli.Command{
Name: "ranges",
Usage: "Display all CIDR ranges",
Aliases: []string{"r"},
Action: func(_ context.Context, command *cli.Command) error {
arg := command.Args().First()

handler := ranges.New()
handler := ranges.New(stdout)

return handler.Handle(arg)
},
Expand Down
41 changes: 41 additions & 0 deletions cmd/ranges_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cmd_test

import (
"testing"
)

func TestRanges(t *testing.T) {
testCases := []testCase{
{
name: "single range",
input: []string{"cider", "ranges", "21"},
stdOutput: "Cidr Mask Addresses Azure addresses\n/21 255.255.248.0 2048 2043\n",
stdErr: "",
},
{
name: "single range shorthand",
input: []string{"cider", "r", "21"},
stdOutput: "Cidr Mask Addresses Azure addresses\n/21 255.255.248.0 2048 2043\n",
stdErr: "",
},
{
name: "single range no command",
input: []string{"cider", "21"},
stdOutput: "Cidr Mask Addresses Azure addresses\n/21 255.255.248.0 2048 2043\n",
stdErr: "",
},
{
name: "all ranges",
input: []string{"cider", "ranges"},
stdOutput: "Cidr Mask Addresses Azure addresses\n/0 0.0.0.0 4294967296 4294967291\n/1 128.0.0.0 2147483648 2147483643\n/2 192.0.0.0 1073741824 1073741819\n/3 224.0.0.0 536870912 536870907\n/4 240.0.0.0 268435456 268435451\n/5 248.0.0.0 134217728 134217723\n/6 252.0.0.0 67108864 67108859\n/7 254.0.0.0 33554432 33554427\n/8 255.0.0.0 16777216 16777211\n/9 255.128.0.0 8388608 8388603\n/10 255.192.0.0 4194304 4194299\n/11 255.224.0.0 2097152 2097147\n/12 255.240.0.0 1048576 1048571\n/13 255.248.0.0 524288 524283\n/14 255.252.0.0 262144 262139\n/15 255.254.0.0 131072 131067\n/16 255.255.0.0 65536 65531\n/17 255.255.128.0 32768 32763\n/18 255.255.192.0 16384 16379\n/19 255.255.224.0 8192 8187\n/20 255.255.240.0 4096 4091\n/21 255.255.248.0 2048 2043\n/22 255.255.252.0 1024 1019\n/23 255.255.254.0 512 507\n/24 255.255.255.0 256 251\n/25 255.255.255.128 128 123\n/26 255.255.255.192 64 59\n/27 255.255.255.224 32 27\n/28 255.255.255.240 16 11\n/29 255.255.255.248 8 3\n/30 255.255.255.252 4 N/A\n/31 255.255.255.254 2 N/A\n/32 255.255.255.255 1 N/A\n",
stdErr: "",
},
{
name: "string as range",
input: []string{"cider", "ranges", "not a range"},
stdOutput: "",
stdErr: "not a range is not a valid integer",
},
}
executeTestCases(t, testCases)
}
5 changes: 3 additions & 2 deletions cmd/subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ package cmd
import (
"cider/internal/commands/subnet"
"context"
"io"

"github.com/urfave/cli/v3"
)

func newSubnet() *cli.Command {
func newSubnet(stdout io.Writer) *cli.Command {
return &cli.Command{
Name: "subnet",
Usage: "Split a range into multiple smaller ranges",
Aliases: []string{"s"},
Action: func(_ context.Context, command *cli.Command) error {
args := command.Args().Slice()

handler := subnet.New()
handler := subnet.New(stdout)

return handler.Handle(args)
},
Expand Down
27 changes: 27 additions & 0 deletions cmd/subnet_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package cmd_test

import "testing"

func TestSubnet(t *testing.T) {
testCases := []testCase{
{
name: "missing args",
input: []string{"cider", "subnet"},
stdOutput: "",
stdErr: "command expects at least 2 arguments",
},
{
name: "single arg",
input: []string{"cider", "subnet", "10.163.0.0/16"},
stdOutput: "",
stdErr: "command expects at least 2 arguments",
},
{
name: "valid range",
input: []string{"cider", "subnet", "10.163.0.0/16", "19", "19", "19", "19"},
stdOutput: "10.163.0.0/19\n10.163.32.0/19\n10.163.64.0/19\n10.163.96.0/19\n",
stdErr: "",
},
}
executeTestCases(t, testCases)
}
7 changes: 4 additions & 3 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ package cmd
import (
"context"
"fmt"
"io"

"github.com/urfave/cli/v3"
)

var version string
var version string = "version"

func newVersion() *cli.Command {
func newVersion(stdout io.Writer) *cli.Command {
return &cli.Command{
Name: "version",
Aliases: []string{"v"},
Usage: "Show version",
Action: func(_ context.Context, command *cli.Command) error {
fmt.Println(version)
fmt.Fprintln(stdout, version)

return nil
},
Expand Down
17 changes: 17 additions & 0 deletions cmd/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmd_test

import (
"testing"
)

func TestVersion(t *testing.T) {
testCases := []testCase{
{
name: "returns version",
input: []string{"cider", "version"},
stdOutput: "version\n",
stdErr: "",
},
}
executeTestCases(t, testCases)
}
11 changes: 10 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,13 @@ module cider

go 1.24

require github.com/urfave/cli/v3 v3.0.0-beta1
require (
github.com/stretchr/testify v1.10.0
github.com/urfave/cli/v3 v3.0.0-beta1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading