Skip to content

Commit

Permalink
refactor: command - better encapsulation and simpler tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nalgeon committed Apr 30, 2024
1 parent 21951bc commit bd8208b
Show file tree
Hide file tree
Showing 121 changed files with 2,038 additions and 2,498 deletions.
19 changes: 0 additions & 19 deletions internal/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,6 @@ import (
"github.com/nalgeon/redka/internal/redis"
)

func MustParse[T redis.Cmd](s string) T {
parts := strings.Split(s, " ")
args := BuildArgs(parts[0], parts[1:]...)
cmd, err := Parse(args)
if err != nil {
panic(err)
}
return cmd.(T)
}

func BuildArgs(name string, args ...string) [][]byte {
rargs := make([][]byte, len(args)+1)
rargs[0] = []byte(name)
for i, arg := range args {
rargs[i+1] = []byte(arg)
}
return rargs
}

// Parse parses a text representation of a command into a Cmd.
func Parse(args [][]byte) (redis.Cmd, error) {
name := strings.ToLower(string(args[0]))
Expand Down
2 changes: 1 addition & 1 deletion internal/command/conn/conn_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package conn_test
package conn

import (
"testing"
Expand Down
6 changes: 3 additions & 3 deletions internal/command/conn/echo.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import (
// https://redis.io/commands/echo
type Echo struct {
redis.BaseCmd
Parts []string
parts []string
}

func ParseEcho(b redis.BaseCmd) (*Echo, error) {
cmd := &Echo{BaseCmd: b}
err := parser.New(
parser.Strings(&cmd.Parts),
parser.Strings(&cmd.parts),
).Required(1).Run(cmd.Args())
if err != nil {
return cmd, err
Expand All @@ -27,7 +27,7 @@ func ParseEcho(b redis.BaseCmd) (*Echo, error) {
}

func (c *Echo) Run(w redis.Writer, _ redis.Redka) (any, error) {
out := strings.Join(c.Parts, " ")
out := strings.Join(c.parts, " ")
w.WriteAny(out)
return out, nil
}
47 changes: 20 additions & 27 deletions internal/command/conn/echo_test.go
Original file line number Diff line number Diff line change
@@ -1,47 +1,42 @@
package conn_test
package conn

import (
"testing"

"github.com/nalgeon/redka/internal/command"
"github.com/nalgeon/redka/internal/command/conn"
"github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
)

func TestEchoParse(t *testing.T) {
tests := []struct {
name string
cmd string
args [][]byte
want []string
err error
}{
{
name: "echo",
args: command.BuildArgs("echo"),
cmd: "echo",
want: []string{},
err: redis.ErrInvalidArgNum,
},
{
name: "echo hello",
args: command.BuildArgs("echo", "hello"),
cmd: "echo hello",
want: []string{"hello"},
err: nil,
},
{
name: "echo one two",
args: command.BuildArgs("echo", "one", "two"),
cmd: "echo one two",
want: []string{"one", "two"},
err: nil,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
cmd, err := command.Parse(test.args)
t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseEcho, test.cmd)
testx.AssertEqual(t, err, test.err)
if err == nil {
testx.AssertEqual(t, cmd.(*conn.Echo).Parts, test.want)
testx.AssertEqual(t, cmd.parts, test.want)
}
})
}
Expand All @@ -52,29 +47,27 @@ func TestEchoExec(t *testing.T) {
defer db.Close()

tests := []struct {
name string
cmd *conn.Echo
res any
out string
cmd string
res any
out string
}{
{
name: "echo hello",
cmd: command.MustParse[*conn.Echo]("echo hello"),
res: "hello",
out: "hello",
cmd: "echo hello",
res: "hello",
out: "hello",
},
{
name: "echo one two",
cmd: command.MustParse[*conn.Echo]("echo one two"),
res: "one two",
out: "one two",
cmd: "echo one two",
res: "one two",
out: "one two",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Run(test.cmd, func(t *testing.T) {
conn := redis.NewFakeConn()
res, err := test.cmd.Run(conn, red)
cmd := redis.MustParse(ParseEcho, test.cmd)
res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err)
testx.AssertEqual(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out)
Expand Down
78 changes: 37 additions & 41 deletions internal/command/conn/ping.go
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
package conn

import (
"strings"

"github.com/nalgeon/redka/internal/parser"
"github.com/nalgeon/redka/internal/redis"
)

const (
PONG = "PONG"
)

// Returns PONG if no argument is provided, otherwise return a copy of the argument as a bulk
// https://redis.io/commands/ping
type Ping struct {
redis.BaseCmd
Parts []string
}


func ParsePing(b redis.BaseCmd) (*Ping, error) {
cmd := &Ping{BaseCmd: b}
err := parser.New(
parser.Strings(&cmd.Parts),
).Required(0).Run(cmd.Args())
if err != nil {
return cmd, err
}
return cmd, nil
}

func (c *Ping) Run(w redis.Writer, _ redis.Redka) (any, error) {
if len(c.Parts) == 0 {
w.WriteAny(PONG)
return PONG, nil
}
out := strings.Join(c.Parts, " ")
w.WriteAny(out)
return out, nil
}
package conn

import (
"github.com/nalgeon/redka/internal/parser"
"github.com/nalgeon/redka/internal/redis"
)

const (
PONG = "PONG"
)

// Returns the server's liveliness response.
// https://redis.io/commands/ping
type Ping struct {
redis.BaseCmd
message string
}

func ParsePing(b redis.BaseCmd) (*Ping, error) {
cmd := &Ping{BaseCmd: b}
err := parser.New(
parser.String(&cmd.message),
).Required(0).Run(cmd.Args())
if err != nil {
return cmd, err
}
return cmd, nil
}

func (c *Ping) Run(w redis.Writer, _ redis.Redka) (any, error) {
if c.message == "" {
w.WriteAny(PONG)
return PONG, nil
}
w.WriteBulkString(c.message)
return c.message, nil
}
164 changes: 75 additions & 89 deletions internal/command/conn/ping_test.go
Original file line number Diff line number Diff line change
@@ -1,89 +1,75 @@
package conn_test

import (
"testing"

"github.com/nalgeon/redka/internal/command"
"github.com/nalgeon/redka/internal/command/conn"
"github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
)

func TestPingParse(t *testing.T) {
tests := []struct {
name string
args [][]byte
want []string
err error
}{
{
name: "ping",
args: command.BuildArgs("ping"),
want: []string(nil),
err: nil,
},
{
name: "ping hello",
args: command.BuildArgs("ping", "hello"),
want: []string{"hello"},
err: nil,
},
{
name: "ping one two",
args: command.BuildArgs("ping", "one", "two"),
want: []string{"one", "two"},
err: nil,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
cmd, err := command.Parse(test.args)
testx.AssertEqual(t, err, test.err)
if err == nil {
testx.AssertEqual(t, cmd.(*conn.Ping).Parts, test.want)
}
})
}
}

func TestPingExec(t *testing.T) {
db, red := getDB(t)
defer db.Close()

tests := []struct {
name string
cmd *conn.Ping
res any
out string
}{
{
name: "ping",
cmd: command.MustParse[*conn.Ping]("ping"),
res: "PONG",
out: "PONG",
},
{
name: "ping hello",
cmd: command.MustParse[*conn.Ping]("ping hello"),
res: "hello",
out: "hello",
},
{
name: "ping one two",
cmd: command.MustParse[*conn.Ping]("ping one two"),
res: "one two",
out: "one two",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
conn := redis.NewFakeConn()
res, err := test.cmd.Run(conn, red)
testx.AssertNoErr(t, err)
testx.AssertEqual(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out)
})
}
}
package conn

import (
"testing"

"github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
)

func TestPingParse(t *testing.T) {
tests := []struct {
cmd string
want string
err error
}{
{
cmd: "ping",
want: "",
err: nil,
},
{
cmd: "ping hello",
want: "hello",
err: nil,
},
{
cmd: "ping one two",
want: "",
err: redis.ErrSyntaxError,
},
}

for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParsePing, test.cmd)
testx.AssertEqual(t, err, test.err)
if err == nil {
testx.AssertEqual(t, cmd.message, test.want)
}
})
}
}

func TestPingExec(t *testing.T) {
db, red := getDB(t)
defer db.Close()

tests := []struct {
cmd string
res any
out string
}{
{
cmd: "ping",
res: "PONG",
out: "PONG",
},
{
cmd: "ping hello",
res: "hello",
out: "hello",
},
}

for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) {
conn := redis.NewFakeConn()
cmd := redis.MustParse(ParsePing, test.cmd)
res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err)
testx.AssertEqual(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out)
})
}
}
Loading

0 comments on commit bd8208b

Please sign in to comment.