postgres backend (#48)

This commit is contained in:
Anton Zhiyanov
2025-07-13 13:05:18 +05:00
committed by GitHub
parent 7c532df931
commit 2178c81fca
179 changed files with 8084 additions and 7408 deletions

View File

@@ -13,6 +13,20 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
services:
postgres:
image: postgres:17-alpine
env:
POSTGRES_USER: redka
POSTGRES_PASSWORD: redka
POSTGRES_DB: redka
options: >-
--health-cmd "pg_isready --username=redka --dbname=redka --quiet"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -20,7 +34,7 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: "stable" go-version-file: "go.mod"
- name: Install dependencies - name: Install dependencies
run: | run: |
@@ -28,8 +42,15 @@ jobs:
sudo apt-get install -y libsqlite3-dev sudo apt-get install -y libsqlite3-dev
go get . go get .
- name: Test and build - name: Install linter
run: make test build uses: golangci/golangci-lint-action@v8
- name: Build and test
run: |
make build
make vet lint
make test-sqlite
make test-postgres
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4

View File

@@ -3,7 +3,7 @@ name: docker
on: on:
push: push:
tags: tags:
- "*" - "v*.*.*"
workflow_dispatch: workflow_dispatch:
jobs: jobs:

View File

@@ -3,7 +3,7 @@ name: publish
on: on:
push: push:
tags: tags:
- "*" - "v*.*.*"
workflow_dispatch: workflow_dispatch:
permissions: permissions:
@@ -33,7 +33,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: "stable" go-version-file: "go.mod"
- name: Build binary - name: Build binary
run: GOOS=${{ matrix.goos }} make build run: GOOS=${{ matrix.goos }} make build
@@ -85,3 +85,4 @@ jobs:
file: release/* file: release/*
file_glob: true file_glob: true
tag: ${{ github.ref }} tag: ${{ github.ref }}
draft: true

View File

@@ -1,4 +1,4 @@
.PHONY: setup lint vet test build run .PHONY: build
has_git := $(shell command -v git 2>/dev/null) has_git := $(shell command -v git 2>/dev/null)
@@ -20,21 +20,60 @@ build_date := $(shell date -u '+%Y-%m-%dT%H:%M:%S')
setup: setup:
@go mod download @go mod download
lint:
@golangci-lint run --print-issued-lines=false --out-format=colored-line-number ./...
vet: vet:
@echo "> running vet..."
@go vet ./... @go vet ./...
@echo "✓ finished vet"
lint:
@echo "> running lint..."
@golangci-lint run ./...
@echo "✓ finished lint"
test: test:
@go test ./... -v @echo "> running tests with $(driver) driver..."
@go test -tags=$(driver) ./...
@echo "✓ finished tests"
test-sqlite:
@echo "> running tests with sqlite driver..."
@go test -tags=sqlite3 ./...
@echo "✓ finished tests"
test-postgres:
@echo "> running tests with postgres driver..."
@go test -tags=postgres -p=1 ./...
@echo "✓ finished tests"
build: build:
@echo "> running build..."
@CGO_ENABLED=1 go build -ldflags "-s -w -X main.version=$(build_ver) -X main.commit=$(build_rev) -X main.date=$(build_date)" -trimpath -o build/redka -v cmd/redka/main.go @CGO_ENABLED=1 go build -ldflags "-s -w -X main.version=$(build_ver) -X main.commit=$(build_rev) -X main.date=$(build_date)" -trimpath -o build/redka -v cmd/redka/main.go
@echo "✓ finished build"
build-cli: build-cli:
@CGO_ENABLED=1 go build -ldflags "-s -w" -trimpath -o build/redka-cli -v cmd/cli/main.go @CGO_ENABLED=1 go build -ldflags "-s -w" -trimpath -o build/redka-cli -v cmd/cli/main.go
run: run:
@./build/redka @./build/redka
postgres-start:
@echo "> starting postgres..."
@docker run --rm --detach --name=redka-postgres \
--env=POSTGRES_DB=redka \
--env=POSTGRES_USER=redka \
--env=POSTGRES_PASSWORD=redka \
--publish=5432:5432 \
--tmpfs /var/lib/postgresql/data \
postgres:17-alpine
@until docker exec redka-postgres \
pg_isready --username=redka --dbname=redka --quiet --quiet; \
do sleep 1; done
@echo "✓ started postgres"
postgres-stop:
@echo "> stopping postgres..."
@docker stop redka-postgres
@echo "✓ stopped postgres"
postgres-shell:
@docker exec -it redka-postgres psql --username=redka --dbname=redka

View File

@@ -1,17 +1,28 @@
<img alt="Redka" src="logo.svg" height="80" align="center"> <img alt="Redka" src="logo.svg" height="80" align="center">
Redka aims to reimplement the core parts of Redis with SQLite, while remaining compatible with Redis API. Redka aims to reimplement the core parts of Redis with SQL, while remaining compatible with Redis API.
Notable features: Notable features:
- Data does not have to fit in RAM. - Data doesn't have to fit in RAM.
- ACID transactions. - Supports ACID transactions.
- SQL views for better introspection and reporting. - SQL views for easier analysis and reporting.
- Both in-process (Go API) and standalone (RESP) servers. - Works with both SQLite and PostgreSQL (coming v0.6.0) backends.
- Redis-compatible commands and wire protocol. - Runs in-process (Go API) or as a standalone server.
- Redis-compatible commands and wire protocol (RESP).
Redka is [functionally ready](docs/roadmap.md) for 1.0. Feel free to try it in non-critical production scenarios and provide feedback in the issues. Redka is [functionally ready](docs/roadmap.md) for 1.0. Feel free to try it in non-critical production scenarios and provide feedback in the issues.
## Use cases
Here are some situations where Redka might be helpful:
_Embedded cache for Go applications_. If your Go app already uses SQLite or just needs a simple, built-in key-value store, Redka is a natural fit. It gives you Redis-like features without the hassle of running a separate server. The cache persists across application restarts, and backup is as easy as copying a file.
_Lightweight testing environment_. Your app uses Redis in production, but setting up a Redis server for local development or integration tests can be a hassle. Redka, when used with an in-memory SQLite database, gives you a fast alternative with complete isolation for each test run.
_Postgres-first data structures_. If you prefer to use PostgreSQL for everything but need Redis-like data structures (like lists and sorted sets), Redka can use your existing database as the backend. This way, you can manage both relational data and specialized data structures with the same tools and transactional guarantees.
## Commands ## Commands
Redka supports five core Redis data types: Redka supports five core Redis data types:
@@ -31,17 +42,21 @@ Redka comes in two flavors:
- Standalone Redis-compatible server: [installation](docs/install-standalone.md), [usage](docs/usage-standalone.md). - Standalone Redis-compatible server: [installation](docs/install-standalone.md), [usage](docs/usage-standalone.md).
- Go module for in-process use: [installation](docs/install-module.md), [usage](docs/usage-module.md). - Go module for in-process use: [installation](docs/install-module.md), [usage](docs/usage-module.md).
## Storage
Redka can use either SQLite or PostgreSQL as its backend. It stores data in a [SQL database](docs/persistence.md) with a simple schema and provides views for better introspection.
## Performance ## Performance
According to the [benchmarks](docs/performance.md), Redka is several times slower than Redis. Still, it can do up to 100K op/sec on a Macbook Air, which is pretty good if you ask me (and probably 10x more than most applications will ever need). Redka is not about raw performance. You can't beat a specialized data store like Redis with a general-purpose relational backend like SQLite. However, Redka can still handle tens of thousands of operations per second, which should be more than enough for many apps.
Redka stores data in a [SQLite database](docs/persistence.md) with a simple schema and provides views for better introspection. See the [benchmarks](docs/performance.md) for more details.
## Contributing ## Contributing
Contributions are welcome. For anything other than bugfixes, please first open an issue to discuss what you want to change. Contributions are welcome. For anything other than bugfixes, please first open an issue to discuss what you want to change.
Be sure to add or update tests as appropriate. Make sure to add or update tests as needed.
## Acknowledgements ## Acknowledgements

View File

@@ -17,7 +17,7 @@ const dbURI = "file:/data.db?vfs=memdb"
func init() { func init() {
flag.Usage = func() { flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage: redka-cli <filename>\n") _, _ = fmt.Fprintf(flag.CommandLine.Output(), "Usage: redka-cli <filename>\n")
flag.PrintDefaults() flag.PrintDefaults()
} }
} }

View File

@@ -1,24 +1,29 @@
// Redka server. // Redka server.
// Example usage: //
// Example usage (SQLite):
// //
// ./redka -h localhost -p 6379 redka.db // ./redka -h localhost -p 6379 redka.db
// //
// Example usage (client): // Example usage (PostgreSQL):
// //
// docker run --rm -it redis redis-cli -h host.docker.internal -p 6379 // ./redka -h localhost -p 6379 "postgres://redka:redka@localhost:5432/redka?sslmode=disable"
package main package main
import ( import (
"cmp"
"context" "context"
"database/sql" "database/sql"
"flag" "flag"
"fmt" "fmt"
"log/slog" "log/slog"
"net" "net"
"net/url"
"os" "os"
"os/signal" "os/signal"
"strings"
"syscall" "syscall"
_ "github.com/lib/pq"
"github.com/mattn/go-sqlite3" "github.com/mattn/go-sqlite3"
"github.com/nalgeon/redka" "github.com/nalgeon/redka"
"github.com/nalgeon/redka/internal/server" "github.com/nalgeon/redka/internal/server"
@@ -31,9 +36,10 @@ var (
date = "unknown" date = "unknown"
) )
const driverName = "redka" const debugPort = 6060
const memoryURI = "file:/data.db?vfs=memdb" const sqliteDriverName = "sqlite-redka"
const pragma = ` const sqliteMemoryURI = "file:/redka.db?vfs=memdb"
const sqlitePragma = `
pragma journal_mode = wal; pragma journal_mode = wal;
pragma synchronous = normal; pragma synchronous = normal;
pragma temp_store = memory; pragma temp_store = memory;
@@ -53,100 +59,41 @@ func (c *Config) Addr() string {
return net.JoinHostPort(c.Host, c.Port) return net.JoinHostPort(c.Host, c.Port)
} }
var config Config
func init() { func init() {
// Set up command line flags. // Set up flag usage message.
flag.Usage = func() { flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage: redka [options] <data-source>\n") _, _ = fmt.Fprintf(flag.CommandLine.Output(), "Usage: redka [options] <data-source>\n")
flag.PrintDefaults() flag.PrintDefaults()
} }
flag.StringVar(&config.Host, "h", "localhost", "server host")
flag.StringVar(&config.Port, "p", "6379", "server port")
flag.StringVar(&config.Sock, "s", "", "server socket (overrides host and port)")
flag.BoolVar(&config.Verbose, "v", false, "verbose logging")
// Register an SQLite driver with custom pragmas. // Register an SQLite driver with custom pragmas.
// Ensures that the PRAGMA settings apply to // Ensures that the PRAGMA settings apply to
// all connections opened by the driver. // all connections opened by the driver.
sql.Register(driverName, &sqlite3.SQLiteDriver{ sql.Register(sqliteDriverName, &sqlite3.SQLiteDriver{
ConnectHook: func(conn *sqlite3.SQLiteConn) error { ConnectHook: func(conn *sqlite3.SQLiteConn) error {
_, err := conn.Exec(pragma, nil) _, err := conn.Exec(sqlitePragma, nil)
return err return err
}, },
}) })
} }
func main() { func main() {
// Parse command line arguments. config := mustReadConfig()
flag.Parse() logger := setupLogger(config)
if len(flag.Args()) > 1 {
flag.Usage()
os.Exit(1)
}
// Set the data source. slog.Info("starting redka", "version", version, "commit", commit, "built_at", date)
if len(flag.Args()) == 0 {
config.Path = memoryURI
} else {
config.Path = flag.Arg(0)
}
// Prepare a context to handle shutdown signals. // Prepare a context to handle shutdown signals.
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop() defer stop()
// Set up logging.
logLevel := new(slog.LevelVar)
logHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: logLevel})
logger := slog.New(logHandler)
slog.SetDefault(logger)
if config.Verbose {
logLevel.Set(slog.LevelDebug)
}
// Print version information.
slog.Info("starting redka", "version", version, "commit", commit, "built_at", date)
// Open the database. // Open the database.
opts := redka.Options{ db := mustOpenDB(config, logger)
DriverName: driverName,
Logger: logger,
Pragma: map[string]string{},
}
db, err := redka.Open(config.Path, &opts)
if err != nil {
slog.Error("data source", "error", err)
os.Exit(1)
}
slog.Info("data source", "path", config.Path)
// Create the server. // Start application and debug servers.
var srv *server.Server errCh := make(chan error, 1)
if config.Sock != "" { srv := startServer(config, db, errCh)
srv = server.New("unix", config.Sock, db) debugSrv := startDebugServer(config, errCh)
} else {
srv = server.New("tcp", config.Addr(), db)
}
// Start the server.
var errCh = make(chan error, 1)
go func() {
if err := srv.Start(); err != nil {
errCh <- fmt.Errorf("start server: %w", err)
}
}()
// Start the debug server.
var debugSrv *server.DebugServer
if config.Verbose {
debugSrv = server.NewDebug("localhost", 6060)
go func() {
if err := debugSrv.Start(); err != nil {
errCh <- fmt.Errorf("start debug server: %w", err)
}
}()
}
// Wait for a shutdown signal or a startup error. // Wait for a shutdown signal or a startup error.
select { select {
@@ -159,6 +106,120 @@ func main() {
} }
} }
// mustReadConfig reads the configuration from
// command line arguments and environment variables.
func mustReadConfig() Config {
if len(flag.Args()) > 1 {
flag.Usage()
os.Exit(1)
}
var config Config
flag.StringVar(
&config.Host, "h",
cmp.Or(os.Getenv("REDKA_HOST"), "localhost"),
"server host",
)
flag.StringVar(
&config.Port, "p",
cmp.Or(os.Getenv("REDKA_PORT"), "6379"),
"server port",
)
flag.StringVar(
&config.Sock, "s",
cmp.Or(os.Getenv("REDKA_SOCK"), ""),
"server socket (overrides host and port)",
)
flag.BoolVar(&config.Verbose, "v", false, "verbose logging")
flag.Parse()
config.Path = cmp.Or(flag.Arg(0), os.Getenv("REDKA_DB_URL"), sqliteMemoryURI)
return config
}
// setupLogger setups a logger for the application.
func setupLogger(config Config) *slog.Logger {
logLevel := new(slog.LevelVar)
logHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: logLevel})
logger := slog.New(logHandler)
slog.SetDefault(logger)
if config.Verbose {
logLevel.Set(slog.LevelDebug)
}
return logger
}
// mustOpenDB connects to the database.
func mustOpenDB(config Config, logger *slog.Logger) *redka.DB {
// Connect to the database using the inferred driver.
driverName := inferDriverName(config.Path)
opts := redka.Options{
DriverName: driverName,
Logger: logger,
// Using nil for pragma sets the default options.
// We don't want any options, so pass an empty map instead.
Pragma: map[string]string{},
}
db, err := redka.Open(config.Path, &opts)
if err != nil {
slog.Error("data source", "error", err)
os.Exit(1)
}
// Hide password when logging.
maskedPath := config.Path
if u, err := url.Parse(maskedPath); err == nil && u.User != nil {
u.User = url.User(u.User.Username())
maskedPath = u.String()
}
slog.Info("data source", "driver", driverName, "path", maskedPath)
return db
}
// inferDriverName infers the driver name from the data source URI.
func inferDriverName(path string) string {
// Infer the driver name based on the data source URI.
if strings.HasPrefix(path, "postgres://") {
return "postgres"
}
return sqliteDriverName
}
// startServer starts the application server.
func startServer(config Config, db *redka.DB, errCh chan<- error) *server.Server {
// Create the server.
var srv *server.Server
if config.Sock != "" {
srv = server.New("unix", config.Sock, db)
} else {
srv = server.New("tcp", config.Addr(), db)
}
// Start the server.
go func() {
if err := srv.Start(); err != nil {
errCh <- fmt.Errorf("start server: %w", err)
}
}()
return srv
}
// startDebugServer starts the debug server.
func startDebugServer(config Config, errCh chan<- error) *server.DebugServer {
if !config.Verbose {
return nil
}
srv := server.NewDebug("localhost", debugPort)
go func() {
if err := srv.Start(); err != nil {
errCh <- fmt.Errorf("start debug server: %w", err)
}
}()
return srv
}
// shutdown stops the main server and the debug server. // shutdown stops the main server and the debug server.
func shutdown(srv *server.Server, debugSrv *server.DebugServer) { func shutdown(srv *server.Server, debugSrv *server.DebugServer) {
// Stop the debug server. // Stop the debug server.

View File

@@ -6,12 +6,18 @@ Install the module as follows:
go get github.com/nalgeon/redka go get github.com/nalgeon/redka
``` ```
You'll also need an SQLite driver. Use one of the following: You'll also need an SQLite or PostgreSQL driver.
Use one of the following for SQLite:
- `github.com/mattn/go-sqlite3` (CGO, fastest) - `github.com/mattn/go-sqlite3` (CGO, fastest)
- `github.com/ncruces/go-sqlite3` (pure Go, WASM) - `github.com/ncruces/go-sqlite3` (pure Go, WASM)
- `github.com/tursodatabase/go-libsql` (CGO) - `modernc.org/sqlite` (pure Go, libc port)
- `modernc.org/sqlite` (pure Go)
Or one of the following for PostgreSQL:
- `github.com/lib/pq`
- `github.com/jackc/pgx/v5`
Install a driver with `go get` like this: Install a driver with `go get` like this:

View File

@@ -7,21 +7,11 @@ I've compared Redka with Redis using [redis-benchmark](https://redis.io/docs/man
- 10000 randomized keys - 10000 randomized keys
- GET/SET commands - GET/SET commands
SQLite settings: ## Results
```
pragma journal_mode = wal;
pragma synchronous = normal;
pragma temp_store = memory;
pragma mmap_size = 268435456;
pragma foreign_keys = on;
```
Hardware: Apple M1 8-core CPU, 16GB RAM
Redis: Redis:
``` ```text
redis-server --appendonly no redis-server --appendonly no
redis-benchmark -p 6379 -q -c 10 -n 1000000 -r 10000 -t get,set redis-benchmark -p 6379 -q -c 10 -n 1000000 -r 10000 -t get,set
@@ -29,9 +19,9 @@ SET: 133262.25 requests per second, p50=0.055 msec
GET: 139217.59 requests per second, p50=0.055 msec GET: 139217.59 requests per second, p50=0.055 msec
``` ```
Redka (in-memory): Redka (SQLite, in-memory):
``` ```text
./redka -p 6380 ./redka -p 6380
redis-benchmark -p 6380 -q -c 10 -n 1000000 -r 10000 -t get,set redis-benchmark -p 6380 -q -c 10 -n 1000000 -r 10000 -t get,set
@@ -39,14 +29,50 @@ SET: 36188.62 requests per second, p50=0.167 msec
GET: 104405.93 requests per second, p50=0.063 msec GET: 104405.93 requests per second, p50=0.063 msec
``` ```
Redka (persisted to disk): Redka (SQLite, persisted to disk):
``` ```text
./redka -p 6380 data.db ./redka -p 6380 redka.db
redis-benchmark -p 6380 -q -c 10 -n 1000000 -r 10000 -t get,set redis-benchmark -p 6380 -q -c 10 -n 1000000 -r 10000 -t get,set
SET: 26773.76 requests per second, p50=0.215 msec SET: 26773.76 requests per second, p50=0.215 msec
GET: 103092.78 requests per second, p50=0.063 msec GET: 103092.78 requests per second, p50=0.063 msec
``` ```
So while Redka is 2-5 times slower than Redis (not surprising, since we are comparing a relational database to a key-value data store), it can still do 26K writes/sec and 94K reads/sec, which is pretty good if you ask me. Redka (PostgreSQL):
```text
./redka -p 6380 "postgres://redka:redka@localhost:5432/redka?sslmode=disable"
redis-benchmark -p 6380 -q -c 10 -n 100000 -r 10000 -t get,set
SET: 11941.72 requests per second, p50=0.775 msec
GET: 25766.55 requests per second, p50=0.359 msec
```
So while Redka is noticeably slower than Redis (not surprising, since we are comparing a relational database to a key-value data store), it can still handle tens of thousands of operations per second. That should be more than enough for many apps.
## Environment
Hardware: Apple M1 8-core CPU, 16GB RAM
SQLite settings:
```text
pragma journal_mode = wal;
pragma synchronous = normal;
pragma temp_store = memory;
pragma mmap_size = 268435456;
pragma foreign_keys = on;
```
PostgreSQL settings:
```text
checkpoint_completion_target=0.9
effective_cache_size=4GB
maintenance_work_mem=512MB
max_wal_size=1GB
random_page_cost=1.1
shared_buffers=1GB
wal_buffers=16MB
```

View File

@@ -1,6 +1,6 @@
# Persistence # Persistence
Redka stores data in a SQLite database using the following tables: Redka stores data in a SQL database using the following tables:
``` ```
rkey rkey

View File

@@ -47,19 +47,19 @@ After opening the database, call `redka.DB` methods to run individual commands:
db.Str().Set("name", "alice") db.Str().Set("name", "alice")
db.Str().Set("age", 25) db.Str().Set("age", 25)
count, err := db.Key().Count("name", "age", "city")
slog.Info("count", "count", count, "err", err)
name, err := db.Str().Get("name") name, err := db.Str().Get("name")
slog.Info("get", "name", name, "err", err) slog.Info("get", "name", name, "err", err)
age, err := db.Str().Get("age")
slog.Info("get", "age", age, "err", err)
``` ```
``` ```text
count count=2 err=<nil>
get name="alice" err=<nil> get name="alice" err=<nil>
get age="25" err=<nil>
``` ```
See the full example in [example/simple/main.go](../example/simple/main.go). See the full example in [example/mattn/main.go](../example/mattn/main.go).
## Transactions ## Transactions
@@ -84,7 +84,7 @@ err := db.Update(func(tx *redka.Tx) error {
slog.Info("updated", "count", updCount, "err", err) slog.Info("updated", "count", updCount, "err", err)
``` ```
``` ```text
updated count=2 err=<nil> updated count=2 err=<nil>
``` ```
@@ -94,7 +94,11 @@ See the full example in [example/tx/main.go](../example/tx/main.go).
Redka supports the following SQLite drivers: Redka supports the following SQLite drivers:
- `github.com/mattn/go-sqlite3` ([example](../example/simple/main.go)) - `github.com/mattn/go-sqlite3` ([example](../example/mattn/main.go))
- `github.com/ncruces/go-sqlite3` ([example](../example/ncruces/main.go)) - `github.com/ncruces/go-sqlite3` ([example](../example/ncruces/main.go))
- `github.com/tursodatabase/go-libsql` ([example](../example/libsql/main.go))
- `modernc.org/sqlite` ([example](../example/modernc/main.go)) - `modernc.org/sqlite` ([example](../example/modernc/main.go))
And the following Postgres drivers:
- `github.com/lib/pq` ([example](../example/postgres/main.go))
- `github.com/jackc/pgx/v5`

View File

@@ -9,10 +9,20 @@ redka [-h host] [-p port] [-s unix-socket] [db-path]
For example: For example:
```shell ```shell
# use in-memory sqlite database
./redka ./redka
# use file sqlite database
./redka data.db ./redka data.db
# listen on all network interfaces
./redka -h 0.0.0.0 -p 6379 data.db ./redka -h 0.0.0.0 -p 6379 data.db
# listen on unix socket
./redka -s /tmp/redka.sock data.db ./redka -s /tmp/redka.sock data.db
# use postgres database
./redka -p 6379 "postgres://redka:redka@localhost:5432/redka?sslmode=disable"
``` ```
Server defaults are host `localhost`, port `6379` and empty DB path. The unix socket path, if given, overrides the host/port arguments. Server defaults are host `localhost`, port `6379` and empty DB path. The unix socket path, if given, overrides the host/port arguments.
@@ -42,7 +52,7 @@ Once the server is running, connect to it using `redis-cli` or an API client lik
redis-cli -h localhost -p 6379 redis-cli -h localhost -p 6379
``` ```
``` ```text
127.0.0.1:6379> echo hello 127.0.0.1:6379> echo hello
"hello" "hello"
127.0.0.1:6379> set name alice 127.0.0.1:6379> set name alice

View File

@@ -2,29 +2,29 @@ module github.com/nalgeon/redka/example
replace github.com/nalgeon/redka => ../ replace github.com/nalgeon/redka => ../
go 1.22 go 1.23.0
toolchain go1.24.0
require ( require (
github.com/mattn/go-sqlite3 v1.14.22 github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.28
github.com/nalgeon/redka v0.0.0-00010101000000-000000000000 github.com/nalgeon/redka v0.0.0-00010101000000-000000000000
github.com/ncruces/go-sqlite3 v0.16.2 github.com/ncruces/go-sqlite3 v0.16.2
github.com/tursodatabase/go-libsql v0.0.0-20240429120401-651096bbee0b
modernc.org/sqlite v1.29.5 modernc.org/sqlite v1.29.5
) )
require ( require (
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/libsql/sqlite-antlr4-parser v0.0.0-20240327125255-dbf53b6cbf06 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-isatty v0.0.16 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/ncruces/julianday v1.0.0 // indirect github.com/ncruces/julianday v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/tetratelabs/wazero v1.7.3 // indirect github.com/tetratelabs/wazero v1.7.3 // indirect
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/sys v0.21.0 // indirect golang.org/x/sys v0.21.0 // indirect
golang.org/x/tools v0.19.0 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.41.0 // indirect modernc.org/libc v1.41.0 // indirect
modernc.org/mathutil v1.6.0 // indirect modernc.org/mathutil v1.6.0 // indirect

View File

@@ -1,47 +1,33 @@
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/libsql/sqlite-antlr4-parser v0.0.0-20240327125255-dbf53b6cbf06 h1:JLvn7D+wXjH9g4Jsjo+VqmzTUpl/LX7vfr6VOfSWTdM= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/libsql/sqlite-antlr4-parser v0.0.0-20240327125255-dbf53b6cbf06/go.mod h1:FUkZ5OHjlGPjnM2UyGJz9TypXQFgYqw6AFNO1UiROTM= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/ncruces/go-sqlite3 v0.16.2-0.20240609232415-e7f8311e2e0d h1:pq4oCRorhPT5EFOyw7OFkGXtJHJ/ViMDjBSmJlPV61g= github.com/nalgeon/be v0.2.0 h1:i1Rsh0F+aNnHdbgph5Cy8Xm5uMVeWrUpm1olgzlPsMo=
github.com/ncruces/go-sqlite3 v0.16.2-0.20240609232415-e7f8311e2e0d/go.mod h1:feFXbBcbLtxNk6XWG1ROt8MS9+E45yCW3G8o4ixIqZ8= github.com/nalgeon/be v0.2.0/go.mod h1:PMwMuBLopwKJkSHnr2qHyLcZYUTqNejN7A8RAqNWO3E=
github.com/ncruces/go-sqlite3 v0.16.2 h1:HesVRr0BC6QSGSEQfEXOntFWS9wd4Z8ms4nJzfUv4Rg= github.com/ncruces/go-sqlite3 v0.16.2 h1:HesVRr0BC6QSGSEQfEXOntFWS9wd4Z8ms4nJzfUv4Rg=
github.com/ncruces/go-sqlite3 v0.16.2/go.mod h1:wkUIvOrAjFQnefVlivJfcowKUcfMHs4mvLfhVanzHHI= github.com/ncruces/go-sqlite3 v0.16.2/go.mod h1:wkUIvOrAjFQnefVlivJfcowKUcfMHs4mvLfhVanzHHI=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M= github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/tetratelabs/wazero v1.7.2 h1:1+z5nXJNwMLPAWaTePFi49SSTL0IMx/i3Fg8Yc25GDc=
github.com/tetratelabs/wazero v1.7.2/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
github.com/tetratelabs/wazero v1.7.3 h1:PBH5KVahrt3S2AHgEjKu4u+LlDbbk+nsGE3KLucy6Rw= github.com/tetratelabs/wazero v1.7.3 h1:PBH5KVahrt3S2AHgEjKu4u+LlDbbk+nsGE3KLucy6Rw=
github.com/tetratelabs/wazero v1.7.3/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y= github.com/tetratelabs/wazero v1.7.3/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
github.com/tursodatabase/go-libsql v0.0.0-20240429120401-651096bbee0b h1:R7hev4b96zgXjKbS2ZNbHBnDvyFZhH+LlMqtKH6hIkU=
github.com/tursodatabase/go-libsql v0.0.0-20240429120401-651096bbee0b/go.mod h1:TjsB2miB8RW2Sse8sdxzVTdeGlx74GloD5zJYUC38d8=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
@@ -49,8 +35,6 @@ golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=

View File

@@ -1,37 +0,0 @@
// An example of using Redka
// with github.com/tursodatabase/go-libsql driver.
package main
import (
"log"
"log/slog"
"github.com/nalgeon/redka"
_ "github.com/tursodatabase/go-libsql"
)
func main() {
// libSQL uses a different driver name ("libsql" instead of "sqlite3").
// It also does not support the journal_mode and mmap_size pragmas
// (see https://github.com/tursodatabase/go-libsql/issues/28),
// so we have to turn them off.
opts := redka.Options{
DriverName: "libsql",
Pragma: map[string]string{
"synchronous": "normal",
"temp_store": "memory",
"foreign_keys": "on",
},
}
db, err := redka.Open("data.db", &opts)
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Str().Set("name", "alice")
slog.Info("set", "err", err)
count, err := db.Key().Count("name", "age", "city")
slog.Info("count", "count", count, "err", err)
}

View File

@@ -11,24 +11,22 @@ import (
) )
func main() { func main() {
// Open a database. // Open the database.
db, err := redka.Open("data.db", nil) db, err := redka.Open("redka.db", nil)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer db.Close() defer func() { _ = db.Close() }()
// Set some string keys. // Set some values.
err = db.Str().Set("name", "alice") err = db.Str().Set("name", "alice")
slog.Info("set", "err", err) slog.Info("set", "err", err)
err = db.Str().Set("age", 25) err = db.Str().Set("age", 25)
slog.Info("set", "err", err) slog.Info("set", "err", err)
// Check if the keys exist. // Read them back.
count, err := db.Key().Count("name", "age", "city")
slog.Info("count", "count", count, "err", err)
// Get a key.
name, err := db.Str().Get("name") name, err := db.Str().Get("name")
slog.Info("get", "name", name, "err", err) slog.Info("get", "name", name, "err", err)
age, err := db.Str().Get("age")
slog.Info("get", "age", age, "err", err)
} }

View File

@@ -16,15 +16,23 @@ func main() {
opts := redka.Options{ opts := redka.Options{
DriverName: "sqlite", DriverName: "sqlite",
} }
db, err := redka.Open("data.db", &opts)
// Open the database.
db, err := redka.Open("redka.db", &opts)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer db.Close() defer func() { _ = db.Close() }()
// Set some values.
err = db.Str().Set("name", "alice") err = db.Str().Set("name", "alice")
slog.Info("set", "err", err) slog.Info("set", "err", err)
err = db.Str().Set("age", 25)
slog.Info("set", "err", err)
count, err := db.Key().Count("name", "age", "city") // Read them back.
slog.Info("count", "count", count, "err", err) name, err := db.Str().Get("name")
slog.Info("get", "name", name, "err", err)
age, err := db.Str().Get("age")
slog.Info("get", "age", age, "err", err)
} }

View File

@@ -12,15 +12,22 @@ import (
) )
func main() { func main() {
db, err := redka.Open("data.db", nil) // Open the database.
db, err := redka.Open("redka.db", nil)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer db.Close() defer func() { _ = db.Close() }()
// Set some values.
err = db.Str().Set("name", "alice") err = db.Str().Set("name", "alice")
slog.Info("set", "err", err) slog.Info("set", "err", err)
err = db.Str().Set("age", 25)
slog.Info("set", "err", err)
count, err := db.Key().Count("name", "age", "city") // Read them back.
slog.Info("count", "count", count, "err", err) name, err := db.Str().Get("name")
slog.Info("get", "name", name, "err", err)
age, err := db.Str().Get("age")
slog.Info("get", "age", age, "err", err)
} }

36
example/postgres/main.go Normal file
View File

@@ -0,0 +1,36 @@
// An example of using Redka
// with github.com/lib/pq driver.
package main
import (
"log"
"log/slog"
_ "github.com/lib/pq"
"github.com/nalgeon/redka"
)
func main() {
// Connections settings.
connString := "postgres://redka:redka@localhost:5432/redka?sslmode=disable"
opts := &redka.Options{DriverName: "postgres"}
// Open the database.
db, err := redka.Open(connString, opts)
if err != nil {
log.Fatal(err)
}
defer func() { _ = db.Close() }()
// Set some values.
err = db.Str().Set("name", "alice")
slog.Info("set", "err", err)
err = db.Str().Set("age", 25)
slog.Info("set", "err", err)
// Read them back.
name, err := db.Str().Get("name")
slog.Info("get", "name", name, "err", err)
age, err := db.Str().Get("age")
slog.Info("get", "age", age, "err", err)
}

View File

@@ -10,11 +10,12 @@ import (
) )
func main() { func main() {
db, err := redka.Open("data.db", nil) // Open the database.
db, err := redka.Open("redka.db", nil)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer db.Close() defer func() { _ = db.Close() }()
{ {
// Writable transaction. // Writable transaction.

13
go.mod
View File

@@ -1,10 +1,17 @@
module github.com/nalgeon/redka module github.com/nalgeon/redka
go 1.22 go 1.23.0
toolchain go1.24.0
// Main dependencies.
require github.com/tidwall/redcon v1.6.2
// Test dependencies.
require ( require (
github.com/mattn/go-sqlite3 v1.14.22 github.com/lib/pq v1.10.9
github.com/tidwall/redcon v1.6.2 github.com/mattn/go-sqlite3 v1.14.28
github.com/nalgeon/be v0.2.0
) )
require ( require (

8
go.sum
View File

@@ -1,5 +1,9 @@
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/nalgeon/be v0.2.0 h1:i1Rsh0F+aNnHdbgph5Cy8Xm5uMVeWrUpm1olgzlPsMo=
github.com/nalgeon/be v0.2.0/go.mod h1:PMwMuBLopwKJkSHnr2qHyLcZYUTqNejN7A8RAqNWO3E=
github.com/tidwall/btree v1.1.0/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4= github.com/tidwall/btree v1.1.0/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4=
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=

View File

@@ -3,15 +3,12 @@ package conn
import ( import (
"testing" "testing"
"github.com/nalgeon/redka"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func getDB(tb testing.TB) (*redka.DB, redis.Redka) { func getRedka(tb testing.TB) redis.Redka {
tb.Helper() tb.Helper()
db, err := redka.Open("file:/data.db?vfs=memdb", nil) db := testx.OpenDB(tb)
if err != nil { return redis.RedkaDB(db)
tb.Fatal(err)
}
return db, redis.RedkaDB(db)
} }

View File

@@ -3,8 +3,8 @@ package conn
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestEchoParse(t *testing.T) { func TestEchoParse(t *testing.T) {
@@ -34,19 +34,18 @@ func TestEchoParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseEcho, test.cmd) cmd, err := redis.Parse(ParseEcho, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.parts, test.want) be.Equal(t, cmd.parts, test.want)
} else { } else {
testx.AssertEqual(t, cmd, Echo{}) be.Equal(t, cmd, Echo{})
} }
}) })
} }
} }
func TestEchoExec(t *testing.T) { func TestEchoExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
tests := []struct { tests := []struct {
cmd string cmd string
@@ -70,9 +69,9 @@ func TestEchoExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseEcho, test.cmd) cmd := redis.MustParse(ParseEcho, test.cmd)
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.res) be.Equal(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
}) })
} }
} }

View File

@@ -3,8 +3,8 @@ package conn
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestPingParse(t *testing.T) { func TestPingParse(t *testing.T) {
@@ -33,19 +33,18 @@ func TestPingParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParsePing, test.cmd) cmd, err := redis.Parse(ParsePing, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.message, test.want) be.Equal(t, cmd.message, test.want)
} else { } else {
testx.AssertEqual(t, cmd, Ping{}) be.Equal(t, cmd, Ping{})
} }
}) })
} }
} }
func TestPingExec(t *testing.T) { func TestPingExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
tests := []struct { tests := []struct {
cmd string cmd string
@@ -69,9 +68,9 @@ func TestPingExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParsePing, test.cmd) cmd := redis.MustParse(ParsePing, test.cmd)
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.res) be.Equal(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
}) })
} }
} }

View File

@@ -3,8 +3,8 @@ package conn
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSelectParse(t *testing.T) { func TestSelectParse(t *testing.T) {
@@ -33,19 +33,18 @@ func TestSelectParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSelect, test.cmd) cmd, err := redis.Parse(ParseSelect, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.index, test.want.index) be.Equal(t, cmd.index, test.want.index)
} else { } else {
testx.AssertEqual(t, cmd, Select{}) be.Equal(t, cmd, Select{})
} }
}) })
} }
} }
func TestSelectExec(t *testing.T) { func TestSelectExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
tests := []struct { tests := []struct {
cmd string cmd string
@@ -64,9 +63,9 @@ func TestSelectExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseSelect, test.cmd) cmd := redis.MustParse(ParseSelect, test.cmd)
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.res) be.Equal(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
}) })
} }
} }

View File

@@ -3,15 +3,12 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/redka"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func getDB(tb testing.TB) (*redka.DB, redis.Redka) { func getRedka(tb testing.TB) redis.Redka {
tb.Helper() tb.Helper()
db, err := redka.Open("file:/data.db?vfs=memdb", nil) db := testx.OpenDB(tb)
if err != nil { return redis.RedkaDB(db)
tb.Fatal(err)
}
return db, redis.RedkaDB(db)
} }

View File

@@ -3,9 +3,9 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHDelParse(t *testing.T) { func TestHDelParse(t *testing.T) {
@@ -44,12 +44,12 @@ func TestHDelParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHDel, test.cmd) cmd, err := redis.Parse(ParseHDel, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.fields, test.fields) be.Equal(t, cmd.fields, test.fields)
} else { } else {
testx.AssertEqual(t, cmd, HDel{}) be.Equal(t, cmd, HDel{})
} }
}) })
} }
@@ -57,66 +57,63 @@ func TestHDelParse(t *testing.T) {
func TestHDelExec(t *testing.T) { func TestHDelExec(t *testing.T) {
t.Run("one", func(t *testing.T) { t.Run("one", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_, _ = db.Hash().Set("person", "name", "alice") _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25) _, _ = red.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHDel, "hdel person name") cmd := redis.MustParse(ParseHDel, "hdel person name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
_, err = db.Hash().Get("person", "name") _, err = red.Hash().Get("person", "name")
testx.AssertErr(t, err, core.ErrNotFound) be.Err(t, err, core.ErrNotFound)
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age.String(), "25") be.Equal(t, age.String(), "25")
}) })
t.Run("some", func(t *testing.T) { t.Run("some", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_, _ = db.Hash().Set("person", "name", "alice") _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25) _, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "happy", true) _, _ = red.Hash().Set("person", "happy", true)
cmd := redis.MustParse(ParseHDel, "hdel person name happy city") cmd := redis.MustParse(ParseHDel, "hdel person name happy city")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
_, err = db.Hash().Get("person", "name") _, err = red.Hash().Get("person", "name")
testx.AssertErr(t, err, core.ErrNotFound) be.Err(t, err, core.ErrNotFound)
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age.String(), "25") be.Equal(t, age.String(), "25")
_, err = db.Hash().Get("person", "happy") _, err = red.Hash().Get("person", "happy")
testx.AssertErr(t, err, core.ErrNotFound) be.Err(t, err, core.ErrNotFound)
}) })
t.Run("all", func(t *testing.T) { t.Run("all", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_, _ = db.Hash().Set("person", "name", "alice") _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25) _, _ = red.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHDel, "hdel person name age") cmd := redis.MustParse(ParseHDel, "hdel person name age")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
_, err = db.Hash().Get("person", "name") _, err = red.Hash().Get("person", "name")
testx.AssertErr(t, err, core.ErrNotFound) be.Err(t, err, core.ErrNotFound)
_, err = db.Hash().Get("person", "age") _, err = red.Hash().Get("person", "age")
testx.AssertErr(t, err, core.ErrNotFound) be.Err(t, err, core.ErrNotFound)
}) })
} }

View File

@@ -3,8 +3,8 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHExistsParse(t *testing.T) { func TestHExistsParse(t *testing.T) {
@@ -43,12 +43,12 @@ func TestHExistsParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHExists, test.cmd) cmd, err := redis.Parse(ParseHExists, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.field, test.field) be.Equal(t, cmd.field, test.field)
} else { } else {
testx.AssertEqual(t, cmd, HExists{}) be.Equal(t, cmd, HExists{})
} }
}) })
} }
@@ -56,43 +56,40 @@ func TestHExistsParse(t *testing.T) {
func TestHExistsExec(t *testing.T) { func TestHExistsExec(t *testing.T) {
t.Run("field found", func(t *testing.T) { t.Run("field found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_, _ = db.Hash().Set("person", "name", "alice") _, _ = red.Hash().Set("person", "name", "alice")
cmd := redis.MustParse(ParseHExists, "hexists person name") cmd := redis.MustParse(ParseHExists, "hexists person name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
}) })
t.Run("field not found", func(t *testing.T) { t.Run("field not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_, _ = db.Hash().Set("person", "name", "alice") _, _ = red.Hash().Set("person", "name", "alice")
cmd := redis.MustParse(ParseHExists, "hexists person age") cmd := redis.MustParse(ParseHExists, "hexists person age")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHExists, "hexists person name") cmd := redis.MustParse(ParseHExists, "hexists person name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHGetParse(t *testing.T) { func TestHGetParse(t *testing.T) {
@@ -44,12 +44,12 @@ func TestHGetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHGet, test.cmd) cmd, err := redis.Parse(ParseHGet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.field, test.field) be.Equal(t, cmd.field, test.field)
} else { } else {
testx.AssertEqual(t, cmd, HGet{}) be.Equal(t, cmd, HGet{})
} }
}) })
} }
@@ -57,43 +57,38 @@ func TestHGetParse(t *testing.T) {
func TestHGetExec(t *testing.T) { func TestHGetExec(t *testing.T) {
t.Run("field found", func(t *testing.T) { t.Run("field found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "name", "alice")
cmd := redis.MustParse(ParseHGet, "hget person name") cmd := redis.MustParse(ParseHGet, "hget person name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("alice")) be.Equal(t, res.(core.Value), core.Value("alice"))
testx.AssertEqual(t, conn.Out(), "alice") be.Equal(t, conn.Out(), "alice")
}) })
t.Run("field not found", func(t *testing.T) { t.Run("field not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "name", "alice")
cmd := redis.MustParse(ParseHGet, "hget person age") cmd := redis.MustParse(ParseHGet, "hget person age")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHGet, "hget person name") cmd := redis.MustParse(ParseHGet, "hget person name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
} }

View File

@@ -3,9 +3,9 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHGetAllParse(t *testing.T) { func TestHGetAllParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestHGetAllParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHGetAll, test.cmd) cmd, err := redis.Parse(ParseHGetAll, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
} else { } else {
testx.AssertEqual(t, cmd, HGetAll{}) be.Equal(t, cmd, HGetAll{})
} }
}) })
} }
@@ -46,34 +46,31 @@ func TestHGetAllParse(t *testing.T) {
func TestHGetAllExec(t *testing.T) { func TestHGetAllExec(t *testing.T) {
t.Run("key found", func(t *testing.T) { t.Run("key found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHGetAll, "hgetall person") cmd := redis.MustParse(ParseHGetAll, "hgetall person")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, map[string]core.Value{ be.Equal(t, res.(map[string]core.Value), map[string]core.Value{
"name": core.Value("alice"), "age": core.Value("25"), "name": core.Value("alice"), "age": core.Value("25"),
}) })
testx.AssertEqual(t, be.Equal(t,
conn.Out() == "4,name,alice,age,25" || conn.Out() == "4,age,25,name,alice", conn.Out() == "4,name,alice,age,25" || conn.Out() == "4,age,25,name,alice",
true) true)
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHGetAll, "hgetall person") cmd := redis.MustParse(ParseHGetAll, "hgetall person")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, map[string]core.Value{}) be.Equal(t, res.(map[string]core.Value), map[string]core.Value{})
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHIncrByParse(t *testing.T) { func TestHIncrByParse(t *testing.T) {
@@ -46,13 +46,13 @@ func TestHIncrByParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHIncrBy, test.cmd) cmd, err := redis.Parse(ParseHIncrBy, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.field, test.field) be.Equal(t, cmd.field, test.field)
testx.AssertEqual(t, cmd.delta, test.delta) be.Equal(t, cmd.delta, test.delta)
} else { } else {
testx.AssertEqual(t, cmd, HIncrBy{}) be.Equal(t, cmd, HIncrBy{})
} }
}) })
} }
@@ -60,69 +60,62 @@ func TestHIncrByParse(t *testing.T) {
func TestHIncrByExec(t *testing.T) { func TestHIncrByExec(t *testing.T) {
t.Run("incr field", func(t *testing.T) { t.Run("incr field", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHIncrBy, "hincrby person age 10") cmd := redis.MustParse(ParseHIncrBy, "hincrby person age 10")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 35) be.Equal(t, res, 35)
testx.AssertEqual(t, conn.Out(), "35") be.Equal(t, conn.Out(), "35")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age, core.Value("35")) be.Equal(t, age, core.Value("35"))
}) })
t.Run("decr field", func(t *testing.T) { t.Run("decr field", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHIncrBy, "hincrby person age -10") cmd := redis.MustParse(ParseHIncrBy, "hincrby person age -10")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 15) be.Equal(t, res, 15)
testx.AssertEqual(t, conn.Out(), "15") be.Equal(t, conn.Out(), "15")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age, core.Value("15")) be.Equal(t, age, core.Value("15"))
}) })
t.Run("create field", func(t *testing.T) { t.Run("create field", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "name", "alice")
cmd := redis.MustParse(ParseHIncrBy, "hincrby person age 10") cmd := redis.MustParse(ParseHIncrBy, "hincrby person age 10")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 10) be.Equal(t, res, 10)
testx.AssertEqual(t, conn.Out(), "10") be.Equal(t, conn.Out(), "10")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age, core.Value("10")) be.Equal(t, age, core.Value("10"))
}) })
t.Run("create key", func(t *testing.T) { t.Run("create key", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHIncrBy, "hincrby person age 10") cmd := redis.MustParse(ParseHIncrBy, "hincrby person age 10")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 10) be.Equal(t, res, 10)
testx.AssertEqual(t, conn.Out(), "10") be.Equal(t, conn.Out(), "10")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age, core.Value("10")) be.Equal(t, age, core.Value("10"))
}) })
} }

View File

@@ -3,9 +3,9 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHIncrByFloatParse(t *testing.T) { func TestHIncrByFloatParse(t *testing.T) {
@@ -46,13 +46,13 @@ func TestHIncrByFloatParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHIncrByFloat, test.cmd) cmd, err := redis.Parse(ParseHIncrByFloat, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.field, test.field) be.Equal(t, cmd.field, test.field)
testx.AssertEqual(t, cmd.delta, test.delta) be.Equal(t, cmd.delta, test.delta)
} else { } else {
testx.AssertEqual(t, cmd, HIncrByFloat{}) be.Equal(t, cmd, HIncrByFloat{})
} }
}) })
} }
@@ -60,69 +60,62 @@ func TestHIncrByFloatParse(t *testing.T) {
func TestHIncrByFloatExec(t *testing.T) { func TestHIncrByFloatExec(t *testing.T) {
t.Run("incr field", func(t *testing.T) { t.Run("incr field", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHIncrByFloat, "hincrbyfloat person age 10.5") cmd := redis.MustParse(ParseHIncrByFloat, "hincrbyfloat person age 10.5")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 35.5) be.Equal(t, res, 35.5)
testx.AssertEqual(t, conn.Out(), "35.5") be.Equal(t, conn.Out(), "35.5")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age, core.Value("35.5")) be.Equal(t, age, core.Value("35.5"))
}) })
t.Run("decr field", func(t *testing.T) { t.Run("decr field", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHIncrByFloat, "hincrbyfloat person age -10.5") cmd := redis.MustParse(ParseHIncrByFloat, "hincrbyfloat person age -10.5")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 14.5) be.Equal(t, res, 14.5)
testx.AssertEqual(t, conn.Out(), "14.5") be.Equal(t, conn.Out(), "14.5")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age, core.Value("14.5")) be.Equal(t, age, core.Value("14.5"))
}) })
t.Run("create field", func(t *testing.T) { t.Run("create field", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "name", "alice")
cmd := redis.MustParse(ParseHIncrByFloat, "hincrbyfloat person age 10.5") cmd := redis.MustParse(ParseHIncrByFloat, "hincrbyfloat person age 10.5")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 10.5) be.Equal(t, res, 10.5)
testx.AssertEqual(t, conn.Out(), "10.5") be.Equal(t, conn.Out(), "10.5")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age, core.Value("10.5")) be.Equal(t, age, core.Value("10.5"))
}) })
t.Run("create key", func(t *testing.T) { t.Run("create key", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHIncrByFloat, "hincrbyfloat person age 10.5") cmd := redis.MustParse(ParseHIncrByFloat, "hincrbyfloat person age 10.5")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 10.5) be.Equal(t, res, 10.5)
testx.AssertEqual(t, conn.Out(), "10.5") be.Equal(t, conn.Out(), "10.5")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age, core.Value("10.5")) be.Equal(t, age, core.Value("10.5"))
}) })
} }

View File

@@ -1,10 +1,11 @@
package hash package hash
import ( import (
"slices"
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHKeysParse(t *testing.T) { func TestHKeysParse(t *testing.T) {
@@ -33,11 +34,11 @@ func TestHKeysParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHKeys, test.cmd) cmd, err := redis.Parse(ParseHKeys, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
} else { } else {
testx.AssertEqual(t, cmd, HKeys{}) be.Equal(t, cmd, HKeys{})
} }
}) })
} }
@@ -45,32 +46,30 @@ func TestHKeysParse(t *testing.T) {
func TestHKeysExec(t *testing.T) { func TestHKeysExec(t *testing.T) {
t.Run("key found", func(t *testing.T) { t.Run("key found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_, _ = db.Hash().Set("person", "name", "alice") _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25) _, _ = red.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHKeys, "hkeys person") cmd := redis.MustParse(ParseHKeys, "hkeys person")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []string{"age", "name"}) got := res.([]string)
testx.AssertEqual(t, slices.Sort(got)
conn.Out() == "2,age,name" || conn.Out() == "2,name,age", be.Equal(t, got, []string{"age", "name"})
true) be.True(t, conn.Out() == "2,age,name" || conn.Out() == "2,name,age")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHKeys, "hkeys person") cmd := redis.MustParse(ParseHKeys, "hkeys person")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []string{}) be.Equal(t, res.([]string), []string{})
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,8 +3,8 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHLenParse(t *testing.T) { func TestHLenParse(t *testing.T) {
@@ -33,11 +33,11 @@ func TestHLenParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHLen, test.cmd) cmd, err := redis.Parse(ParseHLen, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
} else { } else {
testx.AssertEqual(t, cmd, HLen{}) be.Equal(t, cmd, HLen{})
} }
}) })
} }
@@ -45,30 +45,27 @@ func TestHLenParse(t *testing.T) {
func TestHLenExec(t *testing.T) { func TestHLenExec(t *testing.T) {
t.Run("key found", func(t *testing.T) { t.Run("key found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHLen, "hlen person") cmd := redis.MustParse(ParseHLen, "hlen person")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHLen, "hlen person") cmd := redis.MustParse(ParseHLen, "hlen person")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHMGetParse(t *testing.T) { func TestHMGetParse(t *testing.T) {
@@ -44,12 +44,12 @@ func TestHMGetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHMGet, test.cmd) cmd, err := redis.Parse(ParseHMGet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.fields, test.fields) be.Equal(t, cmd.fields, test.fields)
} else { } else {
testx.AssertEqual(t, cmd, HMGet{}) be.Equal(t, cmd, HMGet{})
} }
}) })
} }
@@ -57,58 +57,52 @@ func TestHMGetParse(t *testing.T) {
func TestHMGetExec(t *testing.T) { func TestHMGetExec(t *testing.T) {
t.Run("one field", func(t *testing.T) { t.Run("one field", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHMGet, "hmget person name") cmd := redis.MustParse(ParseHMGet, "hmget person name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, conn.Out(), "1,alice") be.Equal(t, conn.Out(), "1,alice")
items := res.([]core.Value) items := res.([]core.Value)
testx.AssertEqual(t, len(items), 1) be.Equal(t, len(items), 1)
testx.AssertEqual(t, items[0], core.Value("alice")) be.Equal(t, items[0], core.Value("alice"))
}) })
t.Run("some fields", func(t *testing.T) { t.Run("some fields", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "name", "alice") _, _ = red.Hash().Set("person", "happy", true)
_, _ = db.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "happy", true)
cmd := redis.MustParse(ParseHMGet, "hmget person name happy city") cmd := redis.MustParse(ParseHMGet, "hmget person name happy city")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, conn.Out(), "3,alice,1,(nil)") be.Equal(t, conn.Out(), "3,alice,1,(nil)")
items := res.([]core.Value) items := res.([]core.Value)
testx.AssertEqual(t, len(items), 3) be.Equal(t, len(items), 3)
testx.AssertEqual(t, items[0], core.Value("alice")) be.Equal(t, items[0], core.Value("alice"))
testx.AssertEqual(t, items[1], core.Value("1")) be.Equal(t, items[1], core.Value("1"))
testx.AssertEqual(t, items[2], core.Value(nil)) be.Equal(t, items[2], core.Value(nil))
}) })
t.Run("all fields", func(t *testing.T) { t.Run("all fields", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHMGet, "hmget person name age") cmd := redis.MustParse(ParseHMGet, "hmget person name age")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, conn.Out(), "2,alice,25") be.Equal(t, conn.Out(), "2,alice,25")
items := res.([]core.Value) items := res.([]core.Value)
testx.AssertEqual(t, len(items), 2) be.Equal(t, len(items), 2)
testx.AssertEqual(t, items[0], core.Value("alice")) be.Equal(t, items[0], core.Value("alice"))
testx.AssertEqual(t, items[1], core.Value("25")) be.Equal(t, items[1], core.Value("25"))
}) })
} }

View File

@@ -3,8 +3,8 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHMSetParse(t *testing.T) { func TestHMSetParse(t *testing.T) {
@@ -51,12 +51,12 @@ func TestHMSetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHMSet, test.cmd) cmd, err := redis.Parse(ParseHMSet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.items, test.want.items) be.Equal(t, cmd.items, test.want.items)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -64,73 +64,67 @@ func TestHMSetParse(t *testing.T) {
func TestHMSetExec(t *testing.T) { func TestHMSetExec(t *testing.T) {
t.Run("create single", func(t *testing.T) { t.Run("create single", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHMSet, "hmset person name alice") cmd := redis.MustParse(ParseHMSet, "hmset person name alice")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
}) })
t.Run("create multiple", func(t *testing.T) { t.Run("create multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHMSet, "hmset person name alice age 25") cmd := redis.MustParse(ParseHMSet, "hmset person name alice age 25")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age.String(), "25") be.Equal(t, age.String(), "25")
}) })
t.Run("create/update", func(t *testing.T) { t.Run("create/update", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "name", "alice")
cmd := redis.MustParse(ParseHMSet, "hmset person name bob age 50") cmd := redis.MustParse(ParseHMSet, "hmset person name bob age 50")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "bob") be.Equal(t, name.String(), "bob")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age.String(), "50") be.Equal(t, age.String(), "50")
}) })
t.Run("update multiple", func(t *testing.T) { t.Run("update multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHMSet, "hmset person name bob age 50") cmd := redis.MustParse(ParseHMSet, "hmset person name bob age 50")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "bob") be.Equal(t, name.String(), "bob")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age.String(), "50") be.Equal(t, age.String(), "50")
}) })
} }

View File

@@ -1,12 +1,13 @@
package hash package hash
import ( import (
"fmt"
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/rhash" "github.com/nalgeon/redka/internal/rhash"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHScanParse(t *testing.T) { func TestHScanParse(t *testing.T) {
@@ -103,57 +104,62 @@ func TestHScanParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHScan, test.cmd) cmd, err := redis.Parse(ParseHScan, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.cursor, test.cursor) be.Equal(t, cmd.cursor, test.cursor)
testx.AssertEqual(t, cmd.match, test.match) be.Equal(t, cmd.match, test.match)
testx.AssertEqual(t, cmd.count, test.count) be.Equal(t, cmd.count, test.count)
} else { } else {
testx.AssertEqual(t, cmd, HScan{}) be.Equal(t, cmd, HScan{})
} }
}) })
} }
} }
func TestHScanExec(t *testing.T) { func TestHScanExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_, _ = db.Hash().Set("key", "f11", "11") _, _ = red.Hash().Set("key", "f11", "11")
_, _ = db.Hash().Set("key", "f12", "12") _, _ = red.Hash().Set("key", "f12", "12")
_, _ = db.Hash().Set("key", "f21", "21") _, _ = red.Hash().Set("key", "f21", "21")
_, _ = db.Hash().Set("key", "f22", "22") _, _ = red.Hash().Set("key", "f22", "22")
_, _ = db.Hash().Set("key", "f31", "31") _, _ = red.Hash().Set("key", "f31", "31")
t.Run("hscan all", func(t *testing.T) { t.Run("hscan all", func(t *testing.T) {
var cursor int
{ {
// page 1
cmd := redis.MustParse(ParseHScan, "hscan key 0") cmd := redis.MustParse(ParseHScan, "hscan key 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rhash.ScanResult) sres := res.(rhash.ScanResult)
testx.AssertEqual(t, sres.Cursor, 5) be.True(t, sres.Cursor > 0)
testx.AssertEqual(t, len(sres.Items), 5) be.Equal(t, len(sres.Items), 5)
testx.AssertEqual(t, sres.Items[0].Field, "f11") be.Equal(t, sres.Items[0].Field, "f11")
testx.AssertEqual(t, sres.Items[0].Value, core.Value("11")) be.Equal(t, sres.Items[0].Value, core.Value("11"))
testx.AssertEqual(t, sres.Items[4].Field, "f31") be.Equal(t, sres.Items[4].Field, "f31")
testx.AssertEqual(t, sres.Items[4].Value, core.Value("31")) be.Equal(t, sres.Items[4].Value, core.Value("31"))
testx.AssertEqual(t, conn.Out(), "2,5,10,f11,11,f12,12,f21,21,f22,22,f31,31") wantOut := fmt.Sprintf("2,%d,10,f11,11,f12,12,f21,21,f22,22,f31,31", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
cmd := redis.MustParse(ParseHScan, "hscan key 5") // page 2 (empty)
next := fmt.Sprintf("hscan key %d", cursor)
cmd := redis.MustParse(ParseHScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rhash.ScanResult) sres := res.(rhash.ScanResult)
testx.AssertEqual(t, sres.Cursor, 0) be.Equal(t, sres.Cursor, 0)
testx.AssertEqual(t, len(sres.Items), 0) be.Equal(t, len(sres.Items), 0)
testx.AssertEqual(t, conn.Out(), "2,0,0") be.Equal(t, conn.Out(), "2,0,0")
} }
}) })
@@ -162,80 +168,91 @@ func TestHScanExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rhash.ScanResult) sres := res.(rhash.ScanResult)
testx.AssertEqual(t, sres.Cursor, 4) be.True(t, sres.Cursor > 0)
testx.AssertEqual(t, len(sres.Items), 2) be.Equal(t, len(sres.Items), 2)
testx.AssertEqual(t, sres.Items[0].Field, "f21") be.Equal(t, sres.Items[0].Field, "f21")
testx.AssertEqual(t, sres.Items[0].Value, core.Value("21")) be.Equal(t, sres.Items[0].Value, core.Value("21"))
testx.AssertEqual(t, sres.Items[1].Field, "f22") be.Equal(t, sres.Items[1].Field, "f22")
testx.AssertEqual(t, sres.Items[1].Value, core.Value("22")) be.Equal(t, sres.Items[1].Value, core.Value("22"))
testx.AssertEqual(t, conn.Out(), "2,4,4,f21,21,f22,22") wantOut := fmt.Sprintf("2,%d,4,f21,21,f22,22", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
}) })
t.Run("hscan count", func(t *testing.T) { t.Run("hscan count", func(t *testing.T) {
var cursor int
{ {
// page 1 // page 1
cmd := redis.MustParse(ParseHScan, "hscan key 0 match * count 2") cmd := redis.MustParse(ParseHScan, "hscan key 0 match * count 2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rhash.ScanResult) sres := res.(rhash.ScanResult)
testx.AssertEqual(t, sres.Cursor, 2) be.True(t, sres.Cursor > cursor)
testx.AssertEqual(t, len(sres.Items), 2) be.Equal(t, len(sres.Items), 2)
testx.AssertEqual(t, sres.Items[0].Field, "f11") be.Equal(t, sres.Items[0].Field, "f11")
testx.AssertEqual(t, sres.Items[0].Value, core.Value("11")) be.Equal(t, sres.Items[0].Value, core.Value("11"))
testx.AssertEqual(t, sres.Items[1].Field, "f12") be.Equal(t, sres.Items[1].Field, "f12")
testx.AssertEqual(t, sres.Items[1].Value, core.Value("12")) be.Equal(t, sres.Items[1].Value, core.Value("12"))
testx.AssertEqual(t, conn.Out(), "2,2,4,f11,11,f12,12") wantOut := fmt.Sprintf("2,%d,4,f11,11,f12,12", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
// page 2 // page 2
cmd := redis.MustParse(ParseHScan, "hscan key 2 match * count 2") next := fmt.Sprintf("hscan key %d match * count 2", cursor)
cmd := redis.MustParse(ParseHScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rhash.ScanResult) sres := res.(rhash.ScanResult)
testx.AssertEqual(t, sres.Cursor, 4) be.True(t, sres.Cursor > cursor)
testx.AssertEqual(t, len(sres.Items), 2) be.Equal(t, len(sres.Items), 2)
testx.AssertEqual(t, sres.Items[0].Field, "f21") be.Equal(t, sres.Items[0].Field, "f21")
testx.AssertEqual(t, sres.Items[0].Value, core.Value("21")) be.Equal(t, sres.Items[0].Value, core.Value("21"))
testx.AssertEqual(t, sres.Items[1].Field, "f22") be.Equal(t, sres.Items[1].Field, "f22")
testx.AssertEqual(t, sres.Items[1].Value, core.Value("22")) be.Equal(t, sres.Items[1].Value, core.Value("22"))
testx.AssertEqual(t, conn.Out(), "2,4,4,f21,21,f22,22") wantOut := fmt.Sprintf("2,%d,4,f21,21,f22,22", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
// page 3 // page 3
cmd := redis.MustParse(ParseHScan, "hscan key 4 match * count 2") next := fmt.Sprintf("hscan key %d match * count 2", cursor)
cmd := redis.MustParse(ParseHScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rhash.ScanResult) sres := res.(rhash.ScanResult)
testx.AssertEqual(t, sres.Cursor, 5) be.True(t, sres.Cursor > cursor)
testx.AssertEqual(t, len(sres.Items), 1) be.Equal(t, len(sres.Items), 1)
testx.AssertEqual(t, sres.Items[0].Field, "f31") be.Equal(t, sres.Items[0].Field, "f31")
testx.AssertEqual(t, sres.Items[0].Value, core.Value("31")) be.Equal(t, sres.Items[0].Value, core.Value("31"))
testx.AssertEqual(t, conn.Out(), "2,5,2,f31,31") wantOut := fmt.Sprintf("2,%d,2,f31,31", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
// no more pages // no more pages
cmd := redis.MustParse(ParseHScan, "hscan key 5 match * count 2") next := fmt.Sprintf("hscan key %d match * count 2", cursor)
cmd := redis.MustParse(ParseHScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rhash.ScanResult) sres := res.(rhash.ScanResult)
testx.AssertEqual(t, sres.Cursor, 0) be.Equal(t, sres.Cursor, 0)
testx.AssertEqual(t, len(sres.Items), 0) be.Equal(t, len(sres.Items), 0)
testx.AssertEqual(t, conn.Out(), "2,0,0") be.Equal(t, conn.Out(), "2,0,0")
} }
}) })
} }

View File

@@ -3,8 +3,8 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHSetParse(t *testing.T) { func TestHSetParse(t *testing.T) {
@@ -51,12 +51,12 @@ func TestHSetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHSet, test.cmd) cmd, err := redis.Parse(ParseHSet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.items, test.want.items) be.Equal(t, cmd.items, test.want.items)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -64,73 +64,67 @@ func TestHSetParse(t *testing.T) {
func TestHSetExec(t *testing.T) { func TestHSetExec(t *testing.T) {
t.Run("create single", func(t *testing.T) { t.Run("create single", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHSet, "hset person name alice") cmd := redis.MustParse(ParseHSet, "hset person name alice")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
}) })
t.Run("create multiple", func(t *testing.T) { t.Run("create multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHSet, "hset person name alice age 25") cmd := redis.MustParse(ParseHSet, "hset person name alice age 25")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age.String(), "25") be.Equal(t, age.String(), "25")
}) })
t.Run("create/update", func(t *testing.T) { t.Run("create/update", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "name", "alice")
cmd := redis.MustParse(ParseHSet, "hset person name bob age 50") cmd := redis.MustParse(ParseHSet, "hset person name bob age 50")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "bob") be.Equal(t, name.String(), "bob")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age.String(), "50") be.Equal(t, age.String(), "50")
}) })
t.Run("update multiple", func(t *testing.T) { t.Run("update multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHSet, "hset person name bob age 50") cmd := redis.MustParse(ParseHSet, "hset person name bob age 50")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "bob") be.Equal(t, name.String(), "bob")
age, _ := db.Hash().Get("person", "age") age, _ := red.Hash().Get("person", "age")
testx.AssertEqual(t, age.String(), "50") be.Equal(t, age.String(), "50")
}) })
} }

View File

@@ -3,8 +3,8 @@ package hash
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHSetNXParse(t *testing.T) { func TestHSetNXParse(t *testing.T) {
@@ -43,12 +43,12 @@ func TestHSetNXParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHSetNX, test.cmd) cmd, err := redis.Parse(ParseHSetNX, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.value, test.want.value) be.Equal(t, cmd.value, test.want.value)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -56,34 +56,31 @@ func TestHSetNXParse(t *testing.T) {
func TestHSetNXExec(t *testing.T) { func TestHSetNXExec(t *testing.T) {
t.Run("create", func(t *testing.T) { t.Run("create", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHSetNX, "hsetnx person name alice") cmd := redis.MustParse(ParseHSetNX, "hsetnx person name alice")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
}) })
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "name", "alice")
cmd := redis.MustParse(ParseHSetNX, "hsetnx person name bob") cmd := redis.MustParse(ParseHSetNX, "hsetnx person name bob")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
name, _ := db.Hash().Get("person", "name") name, _ := red.Hash().Get("person", "name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
}) })
} }

View File

@@ -1,11 +1,12 @@
package hash package hash
import ( import (
"slices"
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestHValsParse(t *testing.T) { func TestHValsParse(t *testing.T) {
@@ -34,11 +35,11 @@ func TestHValsParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseHVals, test.cmd) cmd, err := redis.Parse(ParseHVals, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
} else { } else {
testx.AssertEqual(t, cmd, HVals{}) be.Equal(t, cmd, HVals{})
} }
}) })
} }
@@ -46,30 +47,32 @@ func TestHValsParse(t *testing.T) {
func TestHValsExec(t *testing.T) { func TestHValsExec(t *testing.T) {
t.Run("key found", func(t *testing.T) { t.Run("key found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Hash().Set("person", "name", "alice")
_, _ = red.Hash().Set("person", "age", 25)
_, _ = db.Hash().Set("person", "name", "alice")
_, _ = db.Hash().Set("person", "age", 25)
cmd := redis.MustParse(ParseHVals, "hvals person") cmd := redis.MustParse(ParseHVals, "hvals person")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value{core.Value("25"), core.Value("alice")}) var got []string
testx.AssertEqual(t, conn.Out(), "2,25,alice") for _, val := range res.([]core.Value) {
got = append(got, val.String())
}
slices.Sort(got)
be.Equal(t, got, []string{"25", "alice"})
be.True(t, conn.Out() == "2,25,alice" || conn.Out() == "2,alice,25")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseHVals, "hvals person") cmd := redis.MustParse(ParseHVals, "hvals person")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value{}) be.Equal(t, res.([]core.Value), []core.Value{})
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package key
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestDelParse(t *testing.T) { func TestDelParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestDelParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseDel, test.cmd) cmd, err := redis.Parse(ParseDel, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.keys, test.want) be.Equal(t, cmd.keys, test.want)
} else { } else {
testx.AssertEqual(t, cmd, Del{}) be.Equal(t, cmd, Del{})
} }
}) })
} }
@@ -69,24 +69,23 @@ func TestDelExec(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("name", "alice") _ = red.Str().Set("name", "alice")
_ = db.Str().Set("age", 50) _ = red.Str().Set("age", 50)
_ = db.Str().Set("city", "paris") _ = red.Str().Set("city", "paris")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseDel, test.cmd) cmd := redis.MustParse(ParseDel, test.cmd)
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.res) be.Equal(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
_, err = db.Str().Get("name") _, err = red.Str().Get("name")
testx.AssertErr(t, err, core.ErrNotFound) be.Err(t, err, core.ErrNotFound)
city, _ := db.Str().Get("city") city, _ := red.Str().Get("city")
testx.AssertEqual(t, city.String(), "paris") be.Equal(t, city.String(), "paris")
}) })
} }
} }

View File

@@ -3,8 +3,8 @@ package key
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestExistsParse(t *testing.T) { func TestExistsParse(t *testing.T) {
@@ -33,23 +33,22 @@ func TestExistsParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseExists, test.cmd) cmd, err := redis.Parse(ParseExists, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.keys, test.want) be.Equal(t, cmd.keys, test.want)
} else { } else {
testx.AssertEqual(t, cmd, Exists{}) be.Equal(t, cmd, Exists{})
} }
}) })
} }
} }
func TestExistsExec(t *testing.T) { func TestExistsExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("name", "alice") _ = red.Str().Set("name", "alice")
_ = db.Str().Set("age", 50) _ = red.Str().Set("age", 50)
_ = db.Str().Set("city", "paris") _ = red.Str().Set("city", "paris")
tests := []struct { tests := []struct {
cmd string cmd string
@@ -78,9 +77,9 @@ func TestExistsExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseExists, test.cmd) cmd := redis.MustParse(ParseExists, test.cmd)
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.res) be.Equal(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
}) })
} }
} }

View File

@@ -4,8 +4,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestExpireParse(t *testing.T) { func TestExpireParse(t *testing.T) {
@@ -54,12 +54,12 @@ func TestExpireParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(parse, test.cmd) cmd, err := redis.Parse(parse, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.ttl, test.ttl) be.Equal(t, cmd.ttl, test.ttl)
} else { } else {
testx.AssertEqual(t, cmd, Expire{}) be.Equal(t, cmd, Expire{})
} }
}) })
} }
@@ -70,89 +70,79 @@ func TestExpireExec(t *testing.T) {
return ParseExpire(b, 1000) return ParseExpire(b, 1000)
} }
t.Run("create expire", func(t *testing.T) { t.Run("create expire", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "expire name 60") cmd := redis.MustParse(parse, "expire name 60")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
expireAt := time.Now().Add(60 * time.Second) expireAt := time.Now().Add(60 * time.Second)
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, *key.ETime/1000, expireAt.UnixMilli()/1000) be.Equal(t, *key.ETime/1000, expireAt.UnixMilli()/1000)
}) })
t.Run("update expire", func(t *testing.T) { t.Run("update expire", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().SetExpires("name", "alice", 60*time.Second)
_ = db.Str().SetExpires("name", "alice", 60*time.Second)
cmd := redis.MustParse(parse, "expire name 30") cmd := redis.MustParse(parse, "expire name 30")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
expireAt := time.Now().Add(30 * time.Second) expireAt := time.Now().Add(30 * time.Second)
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, *key.ETime/1000, expireAt.UnixMilli()/1000) be.Equal(t, *key.ETime/1000, expireAt.UnixMilli()/1000)
}) })
t.Run("set to zero", func(t *testing.T) { t.Run("set to zero", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "expire name 0") cmd := redis.MustParse(parse, "expire name 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
t.Run("negative", func(t *testing.T) { t.Run("negative", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "expire name -10") cmd := redis.MustParse(parse, "expire name -10")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "expire age 60") cmd := redis.MustParse(parse, "expire age 60")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
key, _ := db.Key().Get("age") key, _ := red.Key().Get("age")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
} }

View File

@@ -5,8 +5,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestExpireAtParse(t *testing.T) { func TestExpireAtParse(t *testing.T) {
@@ -55,12 +55,12 @@ func TestExpireAtParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(parse, test.cmd) cmd, err := redis.Parse(parse, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.at.Unix(), test.at.Unix()) be.Equal(t, cmd.at.Unix(), test.at.Unix())
} else { } else {
testx.AssertEqual(t, cmd, ExpireAt{}) be.Equal(t, cmd, ExpireAt{})
} }
}) })
} }
@@ -71,96 +71,86 @@ func TestExpireAtExec(t *testing.T) {
return ParseExpireAt(b, 1000) return ParseExpireAt(b, 1000)
} }
t.Run("create expireat", func(t *testing.T) { t.Run("create expireat", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
expireAt := time.Now().Add(60 * time.Second) expireAt := time.Now().Add(60 * time.Second)
cmd := redis.MustParse(parse, fmt.Sprintf("expireat name %d", expireAt.Unix())) cmd := redis.MustParse(parse, fmt.Sprintf("expireat name %d", expireAt.Unix()))
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, *key.ETime/1000, expireAt.UnixMilli()/1000) be.Equal(t, *key.ETime/1000, expireAt.UnixMilli()/1000)
}) })
t.Run("update expire", func(t *testing.T) { t.Run("update expire", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
expireAt := time.Now() expireAt := time.Now()
cmd := redis.MustParse(parse, fmt.Sprintf("expireat name %d", expireAt.Add(60*time.Second).Unix())) cmd := redis.MustParse(parse, fmt.Sprintf("expireat name %d", expireAt.Add(60*time.Second).Unix()))
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
cmd = redis.MustParse(parse, fmt.Sprintf("expireat name %d", expireAt.Add(20*time.Second).Unix())) cmd = redis.MustParse(parse, fmt.Sprintf("expireat name %d", expireAt.Add(20*time.Second).Unix()))
conn = redis.NewFakeConn() conn = redis.NewFakeConn()
res, err = cmd.Run(conn, red) res, err = cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, *key.ETime/1000, expireAt.Add(20*time.Second).UnixMilli()/1000) be.Equal(t, *key.ETime/1000, expireAt.Add(20*time.Second).UnixMilli()/1000)
}) })
t.Run("set to zero", func(t *testing.T) { t.Run("set to zero", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "expireat name 0") cmd := redis.MustParse(parse, "expireat name 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
t.Run("negative", func(t *testing.T) { t.Run("negative", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "expireat name -10") cmd := redis.MustParse(parse, "expireat name -10")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "expireat age 1700000000") cmd := redis.MustParse(parse, "expireat age 1700000000")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
key, _ := db.Key().Get("age") key, _ := red.Key().Get("age")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
} }

View File

@@ -3,8 +3,8 @@ package key
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestFlushDBParse(t *testing.T) { func TestFlushDBParse(t *testing.T) {
@@ -29,9 +29,9 @@ func TestFlushDBParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseFlushDB, test.cmd) cmd, err := redis.Parse(ParseFlushDB, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err != nil { if err != nil {
testx.AssertEqual(t, cmd, FlushDB{}) be.Equal(t, cmd, FlushDB{})
} }
}) })
} }
@@ -39,35 +39,32 @@ func TestFlushDBParse(t *testing.T) {
func TestFlushDBExec(t *testing.T) { func TestFlushDBExec(t *testing.T) {
t.Run("full", func(t *testing.T) { t.Run("full", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = red.Str().Set("age", 25)
_ = db.Str().Set("name", "alice")
_ = db.Str().Set("age", 25)
cmd := redis.MustParse(ParseFlushDB, "flushdb") cmd := redis.MustParse(ParseFlushDB, "flushdb")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
keys, _ := db.Key().Keys("*") keys, _ := red.Key().Keys("*")
testx.AssertEqual(t, len(keys), 0) be.Equal(t, len(keys), 0)
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseFlushDB, "flushdb") cmd := redis.MustParse(ParseFlushDB, "flushdb")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
keys, _ := db.Key().Keys("*") keys, _ := red.Key().Keys("*")
testx.AssertEqual(t, len(keys), 0) be.Equal(t, len(keys), 0)
}) })
} }

View File

@@ -3,15 +3,12 @@ package key
import ( import (
"testing" "testing"
"github.com/nalgeon/redka"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func getDB(tb testing.TB) (*redka.DB, redis.Redka) { func getRedka(tb testing.TB) redis.Redka {
tb.Helper() tb.Helper()
db, err := redka.Open("file:/data.db?vfs=memdb", nil) db := testx.OpenDB(tb)
if err != nil { return redis.RedkaDB(db)
tb.Fatal(err)
}
return db, redis.RedkaDB(db)
} }

View File

@@ -3,9 +3,9 @@ package key
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestKeysParse(t *testing.T) { func TestKeysParse(t *testing.T) {
@@ -39,25 +39,24 @@ func TestKeysParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseKeys, test.cmd) cmd, err := redis.Parse(ParseKeys, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.pattern, test.want) be.Equal(t, cmd.pattern, test.want)
} else { } else {
testx.AssertEqual(t, cmd, Keys{}) be.Equal(t, cmd, Keys{})
} }
}) })
} }
} }
func TestKeysExec(t *testing.T) { func TestKeysExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("k11", "11") _ = red.Str().Set("k11", "11")
_ = db.Str().Set("k12", "12") _ = red.Str().Set("k12", "12")
_ = db.Str().Set("k21", "21") _ = red.Str().Set("k21", "21")
_ = db.Str().Set("k22", "22") _ = red.Str().Set("k22", "22")
_ = db.Str().Set("k31", "31") _ = red.Str().Set("k31", "31")
tests := []struct { tests := []struct {
cmd string cmd string
@@ -91,11 +90,11 @@ func TestKeysExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseKeys, test.cmd) cmd := redis.MustParse(ParseKeys, test.cmd)
keys, err := cmd.Run(conn, red) keys, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
for i, key := range keys.([]core.Key) { for i, key := range keys.([]core.Key) {
testx.AssertEqual(t, key.Key, test.res[i]) be.Equal(t, key.Key, test.res[i])
} }
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
}) })
} }
} }

View File

@@ -4,8 +4,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestPersistParse(t *testing.T) { func TestPersistParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestPersistParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParsePersist, test.cmd) cmd, err := redis.Parse(ParsePersist, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
} else { } else {
testx.AssertEqual(t, cmd, Persist{}) be.Equal(t, cmd, Persist{})
} }
}) })
} }
@@ -46,53 +46,47 @@ func TestPersistParse(t *testing.T) {
func TestPersistExec(t *testing.T) { func TestPersistExec(t *testing.T) {
t.Run("persist to persist", func(t *testing.T) { t.Run("persist to persist", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(ParsePersist, "persist name") cmd := redis.MustParse(ParsePersist, "persist name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.ETime, (*int64)(nil)) be.Equal(t, key.ETime, (*int64)(nil))
}) })
t.Run("volatile to persist", func(t *testing.T) { t.Run("volatile to persist", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().SetExpires("name", "alice", 60*time.Second)
_ = db.Str().SetExpires("name", "alice", 60*time.Second)
cmd := redis.MustParse(ParsePersist, "persist name") cmd := redis.MustParse(ParsePersist, "persist name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.ETime, (*int64)(nil)) be.Equal(t, key.ETime, (*int64)(nil))
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(ParsePersist, "persist age") cmd := redis.MustParse(ParsePersist, "persist age")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
key, _ := db.Key().Get("age") key, _ := red.Key().Get("age")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
} }

View File

@@ -4,8 +4,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestPExpireParse(t *testing.T) { func TestPExpireParse(t *testing.T) {
@@ -54,12 +54,12 @@ func TestPExpireParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(parse, test.cmd) cmd, err := redis.Parse(parse, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.ttl, test.ttl) be.Equal(t, cmd.ttl, test.ttl)
} else { } else {
testx.AssertEqual(t, cmd, Expire{}) be.Equal(t, cmd, Expire{})
} }
}) })
} }
@@ -71,84 +71,79 @@ func TestPExpireExec(t *testing.T) {
} }
t.Run("create pexpire", func(t *testing.T) { t.Run("create pexpire", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "pexpire name 60000") cmd := redis.MustParse(parse, "pexpire name 60000")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
expireAt := time.Now().Add(60 * time.Second) expireAt := time.Now().Add(60 * time.Second)
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, *key.ETime/1000, expireAt.UnixMilli()/1000) be.Equal(t, *key.ETime/1000, expireAt.UnixMilli()/1000)
}) })
t.Run("update pexpire", func(t *testing.T) { t.Run("update pexpire", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().SetExpires("name", "alice", 60*time.Second)
_ = db.Str().SetExpires("name", "alice", 60*time.Second)
cmd := redis.MustParse(parse, "pexpire name 30000") cmd := redis.MustParse(parse, "pexpire name 30000")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
expireAt := time.Now().Add(30 * time.Second) expireAt := time.Now().Add(30 * time.Second)
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, *key.ETime/1000, expireAt.UnixMilli()/1000) be.Equal(t, *key.ETime/1000, expireAt.UnixMilli()/1000)
}) })
t.Run("set to zero", func(t *testing.T) { t.Run("set to zero", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "pexpire name 0") cmd := redis.MustParse(parse, "pexpire name 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
t.Run("negative", func(t *testing.T) { t.Run("negative", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "pexpire name -1000") cmd := redis.MustParse(parse, "pexpire name -1000")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "pexpire age 1000") cmd := redis.MustParse(parse, "pexpire age 1000")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
key, _ := db.Key().Get("age") key, _ := red.Key().Get("age")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
}) })
} }

View File

@@ -4,9 +4,9 @@ import (
"slices" "slices"
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestRandomKeyParse(t *testing.T) { func TestRandomKeyParse(t *testing.T) {
@@ -31,9 +31,9 @@ func TestRandomKeyParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseRandomKey, test.cmd) cmd, err := redis.Parse(ParseRandomKey, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err != nil { if err != nil {
testx.AssertEqual(t, cmd, RandomKey{}) be.Equal(t, cmd, RandomKey{})
} }
}) })
} }
@@ -41,28 +41,26 @@ func TestRandomKeyParse(t *testing.T) {
func TestRandomKeyExec(t *testing.T) { func TestRandomKeyExec(t *testing.T) {
t.Run("found", func(t *testing.T) { t.Run("found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice") _ = red.Str().Set("age", 25)
_ = db.Str().Set("age", 25) _ = red.Str().Set("city", "paris")
_ = db.Str().Set("city", "paris")
keys := []string{"name", "age", "city"}
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseRandomKey, "randomkey") cmd := redis.MustParse(ParseRandomKey, "randomkey")
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, slices.Contains(keys, res.(core.Key).Key), true) keys := []string{"name", "age", "city"}
testx.AssertEqual(t, slices.Contains(keys, conn.Out()), true) be.True(t, slices.Contains(keys, res.(core.Key).Key))
be.True(t, slices.Contains(keys, conn.Out()))
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseRandomKey, "randomkey") cmd := redis.MustParse(ParseRandomKey, "randomkey")
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
} }

View File

@@ -3,9 +3,9 @@ package key
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestRenameParse(t *testing.T) { func TestRenameParse(t *testing.T) {
@@ -38,12 +38,12 @@ func TestRenameParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseRename, test.cmd) cmd, err := redis.Parse(ParseRename, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.newKey, test.newKey) be.Equal(t, cmd.newKey, test.newKey)
} else { } else {
testx.AssertEqual(t, cmd, Rename{}) be.Equal(t, cmd, Rename{})
} }
}) })
} }
@@ -51,83 +51,75 @@ func TestRenameParse(t *testing.T) {
func TestRenameExec(t *testing.T) { func TestRenameExec(t *testing.T) {
t.Run("create new", func(t *testing.T) { t.Run("create new", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(ParseRename, "rename name title") cmd := redis.MustParse(ParseRename, "rename name title")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
key, _ = db.Key().Get("title") key, _ = red.Key().Get("title")
testx.AssertEqual(t, key.Exists(), true) be.Equal(t, key.Exists(), true)
}) })
t.Run("replace existing", func(t *testing.T) { t.Run("replace existing", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = red.Str().Set("title", "bob")
_ = db.Str().Set("name", "alice")
_ = db.Str().Set("title", "bob")
cmd := redis.MustParse(ParseRename, "rename name title") cmd := redis.MustParse(ParseRename, "rename name title")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
key, _ = db.Key().Get("title") key, _ = red.Key().Get("title")
testx.AssertEqual(t, key.Exists(), true) be.Equal(t, key.Exists(), true)
val, _ := db.Str().Get("title") val, _ := red.Str().Get("title")
testx.AssertEqual(t, val.String(), "alice") be.Equal(t, val.String(), "alice")
}) })
t.Run("rename to self", func(t *testing.T) { t.Run("rename to self", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(ParseRename, "rename name name") cmd := redis.MustParse(ParseRename, "rename name name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), true) be.Equal(t, key.Exists(), true)
val, _ := db.Str().Get("name") val, _ := red.Str().Get("name")
testx.AssertEqual(t, val.String(), "alice") be.Equal(t, val.String(), "alice")
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("title", "bob")
_ = db.Str().Set("title", "bob")
cmd := redis.MustParse(ParseRename, "rename name title") cmd := redis.MustParse(ParseRename, "rename name title")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertEqual(t, err, core.ErrNotFound) be.Equal(t, err, core.ErrNotFound)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), redis.ErrNotFound.Error()+" (rename)") be.Equal(t, conn.Out(), redis.ErrNotFound.Error()+" (rename)")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
key, _ = db.Key().Get("title") key, _ = red.Key().Get("title")
testx.AssertEqual(t, key.Exists(), true) be.Equal(t, key.Exists(), true)
val, _ := db.Str().Get("title") val, _ := red.Str().Get("title")
testx.AssertEqual(t, val.String(), "bob") be.Equal(t, val.String(), "bob")
}) })
} }

View File

@@ -3,9 +3,9 @@ package key
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestRenameNXParse(t *testing.T) { func TestRenameNXParse(t *testing.T) {
@@ -38,12 +38,12 @@ func TestRenameNXParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseRenameNX, test.cmd) cmd, err := redis.Parse(ParseRenameNX, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.newKey, test.newKey) be.Equal(t, cmd.newKey, test.newKey)
} else { } else {
testx.AssertEqual(t, cmd, RenameNX{}) be.Equal(t, cmd, RenameNX{})
} }
}) })
} }
@@ -51,85 +51,77 @@ func TestRenameNXParse(t *testing.T) {
func TestRenameNXExec(t *testing.T) { func TestRenameNXExec(t *testing.T) {
t.Run("create new", func(t *testing.T) { t.Run("create new", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(ParseRenameNX, "renamenx name title") cmd := redis.MustParse(ParseRenameNX, "renamenx name title")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
key, _ = db.Key().Get("title") key, _ = red.Key().Get("title")
testx.AssertEqual(t, key.Exists(), true) be.Equal(t, key.Exists(), true)
}) })
t.Run("replace existing", func(t *testing.T) { t.Run("replace existing", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = red.Str().Set("title", "bob")
_ = db.Str().Set("name", "alice")
_ = db.Str().Set("title", "bob")
cmd := redis.MustParse(ParseRenameNX, "renamenx name title") cmd := redis.MustParse(ParseRenameNX, "renamenx name title")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), true) be.Equal(t, key.Exists(), true)
val, _ := db.Str().Get("name") val, _ := red.Str().Get("name")
testx.AssertEqual(t, val.String(), "alice") be.Equal(t, val.String(), "alice")
key, _ = db.Key().Get("title") key, _ = red.Key().Get("title")
testx.AssertEqual(t, key.Exists(), true) be.Equal(t, key.Exists(), true)
val, _ = db.Str().Get("title") val, _ = red.Str().Get("title")
testx.AssertEqual(t, val.String(), "bob") be.Equal(t, val.String(), "bob")
}) })
t.Run("rename to self", func(t *testing.T) { t.Run("rename to self", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(ParseRenameNX, "renamenx name name") cmd := redis.MustParse(ParseRenameNX, "renamenx name name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), true) be.Equal(t, key.Exists(), true)
val, _ := db.Str().Get("name") val, _ := red.Str().Get("name")
testx.AssertEqual(t, val.String(), "alice") be.Equal(t, val.String(), "alice")
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("title", "bob")
_ = db.Str().Set("title", "bob")
cmd := redis.MustParse(ParseRenameNX, "renamenx name title") cmd := redis.MustParse(ParseRenameNX, "renamenx name title")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertEqual(t, err, core.ErrNotFound) be.Equal(t, err, core.ErrNotFound)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), redis.ErrNotFound.Error()+" (renamenx)") be.Equal(t, conn.Out(), redis.ErrNotFound.Error()+" (renamenx)")
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, key.Exists(), false) be.Equal(t, key.Exists(), false)
key, _ = db.Key().Get("title") key, _ = red.Key().Get("title")
testx.AssertEqual(t, key.Exists(), true) be.Equal(t, key.Exists(), true)
val, _ := db.Str().Get("title") val, _ := red.Str().Get("title")
testx.AssertEqual(t, val.String(), "bob") be.Equal(t, val.String(), "bob")
}) })
} }

View File

@@ -1,11 +1,12 @@
package key package key
import ( import (
"fmt"
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/rkey" "github.com/nalgeon/redka/internal/rkey"
"github.com/nalgeon/redka/internal/testx"
) )
func TestScanParse(t *testing.T) { func TestScanParse(t *testing.T) {
@@ -108,14 +109,14 @@ func TestScanParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseScan, test.cmd) cmd, err := redis.Parse(ParseScan, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.cursor, test.cursor) be.Equal(t, cmd.cursor, test.cursor)
testx.AssertEqual(t, cmd.match, test.match) be.Equal(t, cmd.match, test.match)
testx.AssertEqual(t, cmd.ktype, test.ktype) be.Equal(t, cmd.ktype, test.ktype)
testx.AssertEqual(t, cmd.count, test.count) be.Equal(t, cmd.count, test.count)
} else { } else {
testx.AssertEqual(t, cmd, Scan{}) be.Equal(t, cmd, Scan{})
} }
}) })
} }
@@ -123,152 +124,164 @@ func TestScanParse(t *testing.T) {
func TestScanExec(t *testing.T) { func TestScanExec(t *testing.T) {
t.Run("scan all", func(t *testing.T) { t.Run("scan all", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("k11", "11") _ = red.Str().Set("k11", "11")
_ = db.Str().Set("k12", "12") _ = red.Str().Set("k12", "12")
_ = db.Str().Set("k21", "21") _ = red.Str().Set("k21", "21")
_ = db.Str().Set("k22", "22") _ = red.Str().Set("k22", "22")
_ = db.Str().Set("k31", "31") _ = red.Str().Set("k31", "31")
var cursor int
{ {
cmd := redis.MustParse(ParseScan, "scan 0") cmd := redis.MustParse(ParseScan, "scan 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rkey.ScanResult) sres := res.(rkey.ScanResult)
testx.AssertEqual(t, sres.Cursor, 5) be.True(t, sres.Cursor > 0)
testx.AssertEqual(t, len(sres.Keys), 5) be.Equal(t, len(sres.Keys), 5)
testx.AssertEqual(t, sres.Keys[0].Key, "k11") be.Equal(t, sres.Keys[0].Key, "k11")
testx.AssertEqual(t, sres.Keys[4].Key, "k31") be.Equal(t, sres.Keys[4].Key, "k31")
testx.AssertEqual(t, conn.Out(), "2,5,5,k11,k12,k21,k22,k31") wantOut := fmt.Sprintf("2,%d,5,k11,k12,k21,k22,k31", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
cmd := redis.MustParse(ParseScan, "scan 5") next := fmt.Sprintf("scan %d", cursor)
cmd := redis.MustParse(ParseScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rkey.ScanResult) sres := res.(rkey.ScanResult)
testx.AssertEqual(t, sres.Cursor, 0) be.Equal(t, sres.Cursor, 0)
testx.AssertEqual(t, len(sres.Keys), 0) be.Equal(t, len(sres.Keys), 0)
testx.AssertEqual(t, conn.Out(), "2,0,0") be.Equal(t, conn.Out(), "2,0,0")
} }
}) })
t.Run("scan pattern", func(t *testing.T) { t.Run("scan pattern", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("k11", "11") _ = red.Str().Set("k11", "11")
_ = db.Str().Set("k12", "12") _ = red.Str().Set("k12", "12")
_ = db.Str().Set("k21", "21") _ = red.Str().Set("k21", "21")
_ = db.Str().Set("k22", "22") _ = red.Str().Set("k22", "22")
_ = db.Str().Set("k31", "31") _ = red.Str().Set("k31", "31")
cmd := redis.MustParse(ParseScan, "scan 0 match k2*") cmd := redis.MustParse(ParseScan, "scan 0 match k2*")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rkey.ScanResult) sres := res.(rkey.ScanResult)
testx.AssertEqual(t, sres.Cursor, 4) be.True(t, sres.Cursor > 0)
testx.AssertEqual(t, len(sres.Keys), 2) be.Equal(t, len(sres.Keys), 2)
testx.AssertEqual(t, sres.Keys[0].Key, "k21") be.Equal(t, sres.Keys[0].Key, "k21")
testx.AssertEqual(t, sres.Keys[1].Key, "k22") be.Equal(t, sres.Keys[1].Key, "k22")
testx.AssertEqual(t, conn.Out(), "2,4,2,k21,k22") wantOut := fmt.Sprintf("2,%d,2,k21,k22", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
}) })
t.Run("scan type", func(t *testing.T) { t.Run("scan type", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("t1", "str") _ = red.Str().Set("t1", "str")
_, _ = db.List().PushBack("t2", "elem") _, _ = red.List().PushBack("t2", "elem")
_, _ = db.Hash().Set("t4", "field", "value") _, _ = red.Hash().Set("t4", "field", "value")
_, _ = db.ZSet().Add("t5", "elem", 11) _, _ = red.ZSet().Add("t5", "elem", 11)
cmd := redis.MustParse(ParseScan, "scan 0 match t* type hash") cmd := redis.MustParse(ParseScan, "scan 0 match t* type hash")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rkey.ScanResult) sres := res.(rkey.ScanResult)
testx.AssertEqual(t, sres.Cursor, 3) be.True(t, sres.Cursor > 0)
testx.AssertEqual(t, len(sres.Keys), 1) be.Equal(t, len(sres.Keys), 1)
testx.AssertEqual(t, sres.Keys[0].Key, "t4") be.Equal(t, sres.Keys[0].Key, "t4")
testx.AssertEqual(t, conn.Out(), "2,3,1,t4") wantOut := fmt.Sprintf("2,%d,1,t4", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
}) })
t.Run("scan count", func(t *testing.T) { t.Run("scan count", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("k11", "11") _ = red.Str().Set("k11", "11")
_ = db.Str().Set("k12", "12") _ = red.Str().Set("k12", "12")
_ = db.Str().Set("k21", "21") _ = red.Str().Set("k21", "21")
_ = db.Str().Set("k22", "22") _ = red.Str().Set("k22", "22")
_ = db.Str().Set("k31", "31") _ = red.Str().Set("k31", "31")
var cursor int
{ {
// page 1 // page 1
cmd := redis.MustParse(ParseScan, "scan 0 match * count 2") cmd := redis.MustParse(ParseScan, "scan 0 match * count 2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rkey.ScanResult) sres := res.(rkey.ScanResult)
testx.AssertEqual(t, sres.Cursor, 2) be.True(t, sres.Cursor > cursor)
testx.AssertEqual(t, len(sres.Keys), 2) be.Equal(t, len(sres.Keys), 2)
testx.AssertEqual(t, sres.Keys[0].Key, "k11") be.Equal(t, sres.Keys[0].Key, "k11")
testx.AssertEqual(t, sres.Keys[1].Key, "k12") be.Equal(t, sres.Keys[1].Key, "k12")
testx.AssertEqual(t, conn.Out(), "2,2,2,k11,k12") wantOut := fmt.Sprintf("2,%d,2,k11,k12", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
// page 2 // page 2
cmd := redis.MustParse(ParseScan, "scan 2 match * count 2") next := fmt.Sprintf("scan %d match * count 2", cursor)
cmd := redis.MustParse(ParseScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rkey.ScanResult) sres := res.(rkey.ScanResult)
testx.AssertEqual(t, sres.Cursor, 4) be.True(t, sres.Cursor > cursor)
testx.AssertEqual(t, len(sres.Keys), 2) be.Equal(t, len(sres.Keys), 2)
testx.AssertEqual(t, sres.Keys[0].Key, "k21") be.Equal(t, sres.Keys[0].Key, "k21")
testx.AssertEqual(t, sres.Keys[1].Key, "k22") be.Equal(t, sres.Keys[1].Key, "k22")
testx.AssertEqual(t, conn.Out(), "2,4,2,k21,k22") wantOut := fmt.Sprintf("2,%d,2,k21,k22", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
// page 3 // page 3
cmd := redis.MustParse(ParseScan, "scan 4 match * count 2") next := fmt.Sprintf("scan %d match * count 2", cursor)
cmd := redis.MustParse(ParseScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rkey.ScanResult) sres := res.(rkey.ScanResult)
testx.AssertEqual(t, sres.Cursor, 5) be.True(t, sres.Cursor > cursor)
testx.AssertEqual(t, len(sres.Keys), 1) be.Equal(t, len(sres.Keys), 1)
testx.AssertEqual(t, sres.Keys[0].Key, "k31") be.Equal(t, sres.Keys[0].Key, "k31")
testx.AssertEqual(t, conn.Out(), "2,5,1,k31") wantOut := fmt.Sprintf("2,%d,1,k31", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
// no more pages // no more pages
cmd := redis.MustParse(ParseScan, "scan 5 match * count 2") next := fmt.Sprintf("scan %d match * count 2", cursor)
cmd := redis.MustParse(ParseScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rkey.ScanResult) sres := res.(rkey.ScanResult)
testx.AssertEqual(t, sres.Cursor, 0) be.Equal(t, sres.Cursor, 0)
testx.AssertEqual(t, len(sres.Keys), 0) be.Equal(t, len(sres.Keys), 0)
testx.AssertEqual(t, conn.Out(), "2,0,0") be.Equal(t, conn.Out(), "2,0,0")
} }
}) })
} }

View File

@@ -4,8 +4,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestTTLParse(t *testing.T) { func TestTTLParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestTTLParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseTTL, test.cmd) cmd, err := redis.Parse(ParseTTL, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
} else { } else {
testx.AssertEqual(t, cmd, TTL{}) be.Equal(t, cmd, TTL{})
} }
}) })
} }
@@ -46,42 +46,37 @@ func TestTTLParse(t *testing.T) {
func TestTTLExec(t *testing.T) { func TestTTLExec(t *testing.T) {
t.Run("has ttl", func(t *testing.T) { t.Run("has ttl", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().SetExpires("name", "alice", 60*time.Second)
_ = db.Str().SetExpires("name", "alice", 60*time.Second)
cmd := redis.MustParse(ParseTTL, "ttl name") cmd := redis.MustParse(ParseTTL, "ttl name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 60) be.Equal(t, res, 60)
testx.AssertEqual(t, conn.Out(), "60") be.Equal(t, conn.Out(), "60")
}) })
t.Run("no ttl", func(t *testing.T) { t.Run("no ttl", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(ParseTTL, "ttl name") cmd := redis.MustParse(ParseTTL, "ttl name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, -1) be.Equal(t, res, -1)
testx.AssertEqual(t, conn.Out(), "-1") be.Equal(t, conn.Out(), "-1")
}) })
t.Run("not found", func(t *testing.T) { t.Run("not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseTTL, "ttl name") cmd := redis.MustParse(ParseTTL, "ttl name")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, -2) be.Equal(t, res, -2)
testx.AssertEqual(t, conn.Out(), "-2") be.Equal(t, conn.Out(), "-2")
}) })
} }

View File

@@ -3,8 +3,8 @@ package key
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestTypeParse(t *testing.T) { func TestTypeParse(t *testing.T) {
@@ -33,24 +33,23 @@ func TestTypeParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseType, test.cmd) cmd, err := redis.Parse(ParseType, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
} else { } else {
testx.AssertEqual(t, cmd, Type{}) be.Equal(t, cmd, Type{})
} }
}) })
} }
} }
func TestTypeExec(t *testing.T) { func TestTypeExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("kstr", "string") _ = red.Str().Set("kstr", "string")
_, _ = db.List().PushBack("klist", "list") _, _ = red.List().PushBack("klist", "list")
_, _ = db.Hash().Set("khash", "field", "hash") _, _ = red.Hash().Set("khash", "field", "hash")
_, _ = db.ZSet().Add("kzset", "zset", 1) _, _ = red.ZSet().Add("kzset", "zset", 1)
tests := []struct { tests := []struct {
key string key string
@@ -68,9 +67,9 @@ func TestTypeExec(t *testing.T) {
cmd := redis.MustParse(ParseType, "type "+test.key) cmd := redis.MustParse(ParseType, "type "+test.key)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.want) be.Equal(t, res.(string), test.want)
testx.AssertEqual(t, conn.Out(), test.want) be.Equal(t, conn.Out(), test.want)
}) })
} }
} }

View File

@@ -3,9 +3,9 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLIndexParse(t *testing.T) { func TestLIndexParse(t *testing.T) {
@@ -39,12 +39,12 @@ func TestLIndexParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLIndex, test.cmd) cmd, err := redis.Parse(ParseLIndex, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.index, test.want.index) be.Equal(t, cmd.index, test.want.index)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -52,78 +52,72 @@ func TestLIndexParse(t *testing.T) {
func TestLIndexExec(t *testing.T) { func TestLIndexExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLIndex, "lindex key 0") cmd := redis.MustParse(ParseLIndex, "lindex key 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
t.Run("single elem", func(t *testing.T) { t.Run("single elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseLIndex, "lindex key 0") cmd := redis.MustParse(ParseLIndex, "lindex key 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("elem")) be.Equal(t, res.(core.Value), core.Value("elem"))
testx.AssertEqual(t, conn.Out(), "elem") be.Equal(t, conn.Out(), "elem")
}) })
t.Run("multiple elems", func(t *testing.T) { t.Run("multiple elems", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLIndex, "lindex key 1") cmd := redis.MustParse(ParseLIndex, "lindex key 1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("two")) be.Equal(t, res.(core.Value), core.Value("two"))
testx.AssertEqual(t, conn.Out(), "two") be.Equal(t, conn.Out(), "two")
}) })
t.Run("list index out of bounds", func(t *testing.T) { t.Run("list index out of bounds", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseLIndex, "lindex key 1") cmd := redis.MustParse(ParseLIndex, "lindex key 1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
t.Run("negative index", func(t *testing.T) { t.Run("negative index", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLIndex, "lindex key -2") cmd := redis.MustParse(ParseLIndex, "lindex key -2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("two")) be.Equal(t, res.(core.Value), core.Value("two"))
testx.AssertEqual(t, conn.Out(), "two") be.Equal(t, conn.Out(), "two")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseLIndex, "lindex key 0") cmd := redis.MustParse(ParseLIndex, "lindex key 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
} }

View File

@@ -3,9 +3,9 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLInsertParse(t *testing.T) { func TestLInsertParse(t *testing.T) {
@@ -55,14 +55,14 @@ func TestLInsertParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLInsert, test.cmd) cmd, err := redis.Parse(ParseLInsert, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.where, test.want.where) be.Equal(t, cmd.where, test.want.where)
testx.AssertEqual(t, cmd.pivot, test.want.pivot) be.Equal(t, cmd.pivot, test.want.pivot)
testx.AssertEqual(t, cmd.elem, test.want.elem) be.Equal(t, cmd.elem, test.want.elem)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -70,90 +70,84 @@ func TestLInsertParse(t *testing.T) {
func TestLInsertExec(t *testing.T) { func TestLInsertExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLInsert, "linsert key before pivot elem") cmd := redis.MustParse(ParseLInsert, "linsert key before pivot elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
_, err = db.List().Get("key", 0) _, err = red.List().Get("key", 0)
testx.AssertEqual(t, err, core.ErrNotFound) be.Equal(t, err, core.ErrNotFound)
}) })
t.Run("insert before first", func(t *testing.T) { t.Run("insert before first", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, err := red.List().PushBack("key", "pivot")
_, err := db.List().PushBack("key", "pivot") be.Err(t, err, nil)
testx.AssertNoErr(t, err)
cmd := redis.MustParse(ParseLInsert, "linsert key before pivot elem") cmd := redis.MustParse(ParseLInsert, "linsert key before pivot elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
elem, _ := db.List().Get("key", 0) elem, _ := red.List().Get("key", 0)
testx.AssertEqual(t, elem, core.Value("elem")) be.Equal(t, elem, core.Value("elem"))
}) })
t.Run("insert before middle", func(t *testing.T) { t.Run("insert before middle", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLInsert, "linsert key before thr two") cmd := redis.MustParse(ParseLInsert, "linsert key before thr two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 3) be.Equal(t, res, 3)
testx.AssertEqual(t, conn.Out(), "3") be.Equal(t, conn.Out(), "3")
elem, _ := db.List().Get("key", 1) elem, _ := red.List().Get("key", 1)
testx.AssertEqual(t, elem, core.Value("two")) be.Equal(t, elem, core.Value("two"))
}) })
t.Run("insert after middle", func(t *testing.T) { t.Run("insert after middle", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLInsert, "linsert key after thr two") cmd := redis.MustParse(ParseLInsert, "linsert key after thr two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 3) be.Equal(t, res, 3)
testx.AssertEqual(t, conn.Out(), "3") be.Equal(t, conn.Out(), "3")
elem, _ := db.List().Get("key", 2) elem, _ := red.List().Get("key", 2)
testx.AssertEqual(t, elem, core.Value("two")) be.Equal(t, elem, core.Value("two"))
}) })
t.Run("elem not found", func(t *testing.T) { t.Run("elem not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two")
cmd := redis.MustParse(ParseLInsert, "linsert key before thr two") cmd := redis.MustParse(ParseLInsert, "linsert key before thr two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, -1) be.Equal(t, res, -1)
testx.AssertEqual(t, conn.Out(), "-1") be.Equal(t, conn.Out(), "-1")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseLInsert, "linsert key before pivot elem") cmd := redis.MustParse(ParseLInsert, "linsert key before pivot elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,15 +3,12 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/redka"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func getDB(tb testing.TB) (*redka.DB, redis.Redka) { func getRedka(tb testing.TB) redis.Redka {
tb.Helper() tb.Helper()
db, err := redka.Open("file:/data.db?vfs=memdb", nil) db := testx.OpenDB(tb)
if err != nil { return redis.RedkaDB(db)
tb.Fatal(err)
}
return db, redis.RedkaDB(db)
} }

View File

@@ -3,8 +3,8 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLLenParse(t *testing.T) { func TestLLenParse(t *testing.T) {
@@ -33,11 +33,11 @@ func TestLLenParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLLen, test.cmd) cmd, err := redis.Parse(ParseLLen, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -45,52 +45,48 @@ func TestLLenParse(t *testing.T) {
func TestLLenExec(t *testing.T) { func TestLLenExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLLen, "llen key") cmd := redis.MustParse(ParseLLen, "llen key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("single elem", func(t *testing.T) { t.Run("single elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseLLen, "llen key") cmd := redis.MustParse(ParseLLen, "llen key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
}) })
t.Run("multiple elems", func(t *testing.T) { t.Run("multiple elems", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLLen, "llen key") cmd := redis.MustParse(ParseLLen, "llen key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 3) be.Equal(t, res, 3)
testx.AssertEqual(t, conn.Out(), "3") be.Equal(t, conn.Out(), "3")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseLLen, "llen key") cmd := redis.MustParse(ParseLLen, "llen key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLPopParse(t *testing.T) { func TestLPopParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestLPopParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLPop, test.cmd) cmd, err := redis.Parse(ParseLPop, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -46,62 +46,58 @@ func TestLPopParse(t *testing.T) {
func TestLPopExec(t *testing.T) { func TestLPopExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLPop, "lpop key") cmd := redis.MustParse(ParseLPop, "lpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
t.Run("pop elem", func(t *testing.T) { t.Run("pop elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseLPop, "lpop key") cmd := redis.MustParse(ParseLPop, "lpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("elem")) be.Equal(t, res.(core.Value), core.Value("elem"))
testx.AssertEqual(t, conn.Out(), "elem") be.Equal(t, conn.Out(), "elem")
}) })
t.Run("pop multiple", func(t *testing.T) { t.Run("pop multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
{ {
cmd := redis.MustParse(ParseLPop, "lpop key") cmd := redis.MustParse(ParseLPop, "lpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("one")) be.Equal(t, res.(core.Value), core.Value("one"))
testx.AssertEqual(t, conn.Out(), "one") be.Equal(t, conn.Out(), "one")
} }
{ {
cmd := redis.MustParse(ParseLPop, "lpop key") cmd := redis.MustParse(ParseLPop, "lpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("two")) be.Equal(t, res.(core.Value), core.Value("two"))
testx.AssertEqual(t, conn.Out(), "two") be.Equal(t, conn.Out(), "two")
} }
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseLPop, "lpop key") cmd := redis.MustParse(ParseLPop, "lpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
} }

View File

@@ -3,9 +3,9 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLPushParse(t *testing.T) { func TestLPushParse(t *testing.T) {
@@ -39,10 +39,10 @@ func TestLPushParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLPush, test.cmd) cmd, err := redis.Parse(ParseLPush, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.elem, test.want.elem) be.Equal(t, cmd.elem, test.want.elem)
} }
}) })
} }
@@ -50,70 +50,66 @@ func TestLPushParse(t *testing.T) {
func TestLPushExec(t *testing.T) { func TestLPushExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLPush, "lpush key elem") cmd := redis.MustParse(ParseLPush, "lpush key elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
elem, _ := db.List().Get("key", 0) elem, _ := red.List().Get("key", 0)
testx.AssertEqual(t, elem.String(), "elem") be.Equal(t, elem.String(), "elem")
}) })
t.Run("add elem", func(t *testing.T) { t.Run("add elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one")
cmd := redis.MustParse(ParseLPush, "lpush key two") cmd := redis.MustParse(ParseLPush, "lpush key two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
elem, _ := db.List().Get("key", 0) elem, _ := red.List().Get("key", 0)
testx.AssertEqual(t, elem.String(), "two") be.Equal(t, elem.String(), "two")
}) })
t.Run("add miltiple", func(t *testing.T) { t.Run("add miltiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
{ {
cmd := redis.MustParse(ParseLPush, "lpush key one") cmd := redis.MustParse(ParseLPush, "lpush key one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
} }
{ {
cmd := redis.MustParse(ParseLPush, "lpush key two") cmd := redis.MustParse(ParseLPush, "lpush key two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
} }
el0, _ := db.List().Get("key", 0) el0, _ := red.List().Get("key", 0)
testx.AssertEqual(t, el0.String(), "two") be.Equal(t, el0.String(), "two")
el1, _ := db.List().Get("key", 1) el1, _ := red.List().Get("key", 1)
testx.AssertEqual(t, el1.String(), "one") be.Equal(t, el1.String(), "one")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseLPush, "lpush key elem") cmd := redis.MustParse(ParseLPush, "lpush key elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrKeyType) be.Err(t, err, core.ErrKeyType)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), core.ErrKeyType.Error()+" (lpush)") be.Equal(t, conn.Out(), core.ErrKeyType.Error()+" (lpush)")
}) })
} }

View File

@@ -3,9 +3,9 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLRangeParse(t *testing.T) { func TestLRangeParse(t *testing.T) {
@@ -39,13 +39,13 @@ func TestLRangeParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLRange, test.cmd) cmd, err := redis.Parse(ParseLRange, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.start, test.want.start) be.Equal(t, cmd.start, test.want.start)
testx.AssertEqual(t, cmd.stop, test.want.stop) be.Equal(t, cmd.stop, test.want.stop)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -53,94 +53,87 @@ func TestLRangeParse(t *testing.T) {
func TestLRangeExec(t *testing.T) { func TestLRangeExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLRange, "lrange key 0 0") cmd := redis.MustParse(ParseLRange, "lrange key 0 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value(nil)) be.Equal(t, res.([]core.Value), []core.Value(nil))
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("single elem", func(t *testing.T) { t.Run("single elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseLRange, "lrange key 0 0") cmd := redis.MustParse(ParseLRange, "lrange key 0 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value{core.Value("elem")}) be.Equal(t, res.([]core.Value), []core.Value{core.Value("elem")})
testx.AssertEqual(t, conn.Out(), "1,elem") be.Equal(t, conn.Out(), "1,elem")
}) })
t.Run("multiple elems", func(t *testing.T) { t.Run("multiple elems", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLRange, "lrange key 0 1") cmd := redis.MustParse(ParseLRange, "lrange key 0 1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value{core.Value("one"), core.Value("two")}) be.Equal(t, res.([]core.Value), []core.Value{core.Value("one"), core.Value("two")})
testx.AssertEqual(t, conn.Out(), "2,one,two") be.Equal(t, conn.Out(), "2,one,two")
}) })
t.Run("negative indexes", func(t *testing.T) { t.Run("negative indexes", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLRange, "lrange key -2 -1") cmd := redis.MustParse(ParseLRange, "lrange key -2 -1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value{core.Value("two"), core.Value("thr")}) be.Equal(t, res.([]core.Value), []core.Value{core.Value("two"), core.Value("thr")})
testx.AssertEqual(t, conn.Out(), "2,two,thr") be.Equal(t, conn.Out(), "2,two,thr")
}) })
t.Run("out of bounds", func(t *testing.T) { t.Run("out of bounds", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLRange, "lrange key 3 5") cmd := redis.MustParse(ParseLRange, "lrange key 3 5")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value(nil)) be.Equal(t, res.([]core.Value), []core.Value(nil))
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("start < stop", func(t *testing.T) { t.Run("start < stop", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLRange, "lrange key 2 1") cmd := redis.MustParse(ParseLRange, "lrange key 2 1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value(nil)) be.Equal(t, res.([]core.Value), []core.Value(nil))
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseLRange, "lrange key 0 0") cmd := redis.MustParse(ParseLRange, "lrange key 0 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value(nil)) be.Equal(t, res.([]core.Value), []core.Value(nil))
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,8 +3,8 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLRemParse(t *testing.T) { func TestLRemParse(t *testing.T) {
@@ -43,13 +43,13 @@ func TestLRemParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLRem, test.cmd) cmd, err := redis.Parse(ParseLRem, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.count, test.want.count) be.Equal(t, cmd.count, test.want.count)
testx.AssertEqual(t, cmd.elem, test.want.elem) be.Equal(t, cmd.elem, test.want.elem)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -57,120 +57,113 @@ func TestLRemParse(t *testing.T) {
func TestLRemExec(t *testing.T) { func TestLRemExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLRem, "lrem key 1 elem") cmd := redis.MustParse(ParseLRem, "lrem key 1 elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("delete elem", func(t *testing.T) { t.Run("delete elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseLRem, "lrem key 1 elem") cmd := redis.MustParse(ParseLRem, "lrem key 1 elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
count, _ := db.List().Len("key") count, _ := red.List().Len("key")
testx.AssertEqual(t, count, 0) be.Equal(t, count, 0)
}) })
t.Run("delete front", func(t *testing.T) { t.Run("delete front", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "fou")
_, _ = db.List().PushBack("key", "fou")
cmd := redis.MustParse(ParseLRem, "lrem key 2 two") cmd := redis.MustParse(ParseLRem, "lrem key 2 two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
count, _ := db.List().Len("key") count, _ := red.List().Len("key")
testx.AssertEqual(t, count, 4) be.Equal(t, count, 4)
el1, _ := db.List().Get("key", 1) el1, _ := red.List().Get("key", 1)
testx.AssertEqual(t, el1.String(), "thr") be.Equal(t, el1.String(), "thr")
}) })
t.Run("delete back", func(t *testing.T) { t.Run("delete back", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "fou")
_, _ = db.List().PushBack("key", "fou")
cmd := redis.MustParse(ParseLRem, "lrem key -2 two") cmd := redis.MustParse(ParseLRem, "lrem key -2 two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
count, _ := db.List().Len("key") count, _ := red.List().Len("key")
testx.AssertEqual(t, count, 4) be.Equal(t, count, 4)
el1, _ := db.List().Get("key", 1) el1, _ := red.List().Get("key", 1)
testx.AssertEqual(t, el1.String(), "two") be.Equal(t, el1.String(), "two")
}) })
t.Run("delete all", func(t *testing.T) { t.Run("delete all", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "fou")
_, _ = db.List().PushBack("key", "fou")
cmd := redis.MustParse(ParseLRem, "lrem key 0 two") cmd := redis.MustParse(ParseLRem, "lrem key 0 two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 3) be.Equal(t, res, 3)
testx.AssertEqual(t, conn.Out(), "3") be.Equal(t, conn.Out(), "3")
count, _ := db.List().Len("key") count, _ := red.List().Len("key")
testx.AssertEqual(t, count, 3) be.Equal(t, count, 3)
}) })
t.Run("elem not found", func(t *testing.T) { t.Run("elem not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseLRem, "lrem key 1 other") cmd := redis.MustParse(ParseLRem, "lrem key 1 other")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
count, _ := db.List().Len("key") count, _ := red.List().Len("key")
testx.AssertEqual(t, count, 1) be.Equal(t, count, 1)
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseLRem, "lrem key 1 elem") cmd := redis.MustParse(ParseLRem, "lrem key 1 elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLSetParse(t *testing.T) { func TestLSetParse(t *testing.T) {
@@ -44,13 +44,13 @@ func TestLSetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLSet, test.cmd) cmd, err := redis.Parse(ParseLSet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.index, test.want.index) be.Equal(t, cmd.index, test.want.index)
testx.AssertEqual(t, cmd.elem, test.want.elem) be.Equal(t, cmd.elem, test.want.elem)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -58,72 +58,67 @@ func TestLSetParse(t *testing.T) {
func TestLSetExec(t *testing.T) { func TestLSetExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLSet, "lset key 0 elem") cmd := redis.MustParse(ParseLSet, "lset key 0 elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrNotFound) be.Err(t, err, core.ErrNotFound)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), redis.ErrOutOfRange.Error()+" (lset)") be.Equal(t, conn.Out(), redis.ErrOutOfRange.Error()+" (lset)")
}) })
t.Run("set elem", func(t *testing.T) { t.Run("set elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLSet, "lset key 1 upd") cmd := redis.MustParse(ParseLSet, "lset key 1 upd")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
el1, _ := db.List().Get("key", 1) el1, _ := red.List().Get("key", 1)
testx.AssertEqual(t, el1.String(), "upd") be.Equal(t, el1.String(), "upd")
}) })
t.Run("negative index", func(t *testing.T) { t.Run("negative index", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLSet, "lset key -1 upd") cmd := redis.MustParse(ParseLSet, "lset key -1 upd")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
el2, _ := db.List().Get("key", 2) el2, _ := red.List().Get("key", 2)
testx.AssertEqual(t, el2.String(), "upd") be.Equal(t, el2.String(), "upd")
}) })
t.Run("index out of bounds", func(t *testing.T) { t.Run("index out of bounds", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseLSet, "lset key 1 upd") cmd := redis.MustParse(ParseLSet, "lset key 1 upd")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrNotFound) be.Err(t, err, core.ErrNotFound)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), redis.ErrOutOfRange.Error()+" (lset)") be.Equal(t, conn.Out(), redis.ErrOutOfRange.Error()+" (lset)")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseLSet, "lset key 0 elem") cmd := redis.MustParse(ParseLSet, "lset key 0 elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrNotFound) be.Err(t, err, core.ErrNotFound)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), redis.ErrOutOfRange.Error()+" (lset)") be.Equal(t, conn.Out(), redis.ErrOutOfRange.Error()+" (lset)")
}) })
} }

View File

@@ -3,8 +3,8 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLTrimParse(t *testing.T) { func TestLTrimParse(t *testing.T) {
@@ -33,13 +33,13 @@ func TestLTrimParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLTrim, test.cmd) cmd, err := redis.Parse(ParseLTrim, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.start, test.want.start) be.Equal(t, cmd.start, test.want.start)
testx.AssertEqual(t, cmd.stop, test.want.stop) be.Equal(t, cmd.stop, test.want.stop)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -47,98 +47,92 @@ func TestLTrimParse(t *testing.T) {
func TestLTrimExec(t *testing.T) { func TestLTrimExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLTrim, "ltrim key 0 0") cmd := redis.MustParse(ParseLTrim, "ltrim key 0 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
}) })
t.Run("keep single elem", func(t *testing.T) { t.Run("keep single elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseLTrim, "ltrim key 0 0") cmd := redis.MustParse(ParseLTrim, "ltrim key 0 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
count, _ := db.List().Len("key") count, _ := red.List().Len("key")
testx.AssertEqual(t, count, 1) be.Equal(t, count, 1)
}) })
t.Run("keep multiple elems", func(t *testing.T) { t.Run("keep multiple elems", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr") _, _ = red.List().PushBack("key", "fou")
_, _ = db.List().PushBack("key", "fou")
cmd := redis.MustParse(ParseLTrim, "ltrim key 1 2") cmd := redis.MustParse(ParseLTrim, "ltrim key 1 2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
count, _ := db.List().Len("key") count, _ := red.List().Len("key")
testx.AssertEqual(t, count, 2) be.Equal(t, count, 2)
el0, _ := db.List().Get("key", 0) el0, _ := red.List().Get("key", 0)
testx.AssertEqual(t, el0.String(), "two") be.Equal(t, el0.String(), "two")
el1, _ := db.List().Get("key", 1) el1, _ := red.List().Get("key", 1)
testx.AssertEqual(t, el1.String(), "thr") be.Equal(t, el1.String(), "thr")
}) })
t.Run("negative index", func(t *testing.T) { t.Run("negative index", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr") _, _ = red.List().PushBack("key", "fou")
_, _ = db.List().PushBack("key", "fou")
cmd := redis.MustParse(ParseLTrim, "ltrim key 0 -1") cmd := redis.MustParse(ParseLTrim, "ltrim key 0 -1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
count, _ := db.List().Len("key") count, _ := red.List().Len("key")
testx.AssertEqual(t, count, 4) be.Equal(t, count, 4)
}) })
t.Run("start > stop", func(t *testing.T) { t.Run("start > stop", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
cmd := redis.MustParse(ParseLTrim, "ltrim key 2 1") cmd := redis.MustParse(ParseLTrim, "ltrim key 2 1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 3) be.Equal(t, res, 3)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
count, _ := db.List().Len("key") count, _ := red.List().Len("key")
testx.AssertEqual(t, count, 0) be.Equal(t, count, 0)
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseLTrim, "ltrim key 0 0") cmd := redis.MustParse(ParseLTrim, "ltrim key 0 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
}) })
} }

View File

@@ -3,9 +3,9 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestRPopParse(t *testing.T) { func TestRPopParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestRPopParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseRPop, test.cmd) cmd, err := redis.Parse(ParseRPop, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -46,62 +46,58 @@ func TestRPopParse(t *testing.T) {
func TestRPopExec(t *testing.T) { func TestRPopExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseRPop, "rpop key") cmd := redis.MustParse(ParseRPop, "rpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
t.Run("pop elem", func(t *testing.T) { t.Run("pop elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "elem")
_, _ = db.List().PushBack("key", "elem")
cmd := redis.MustParse(ParseRPop, "rpop key") cmd := redis.MustParse(ParseRPop, "rpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("elem")) be.Equal(t, res.(core.Value), core.Value("elem"))
testx.AssertEqual(t, conn.Out(), "elem") be.Equal(t, conn.Out(), "elem")
}) })
t.Run("pop multiple", func(t *testing.T) { t.Run("pop multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one") _, _ = red.List().PushBack("key", "two")
_, _ = db.List().PushBack("key", "two") _, _ = red.List().PushBack("key", "thr")
_, _ = db.List().PushBack("key", "thr")
{ {
cmd := redis.MustParse(ParseRPop, "rpop key") cmd := redis.MustParse(ParseRPop, "rpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("thr")) be.Equal(t, res.(core.Value), core.Value("thr"))
testx.AssertEqual(t, conn.Out(), "thr") be.Equal(t, conn.Out(), "thr")
} }
{ {
cmd := redis.MustParse(ParseRPop, "rpop key") cmd := redis.MustParse(ParseRPop, "rpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("two")) be.Equal(t, res.(core.Value), core.Value("two"))
testx.AssertEqual(t, conn.Out(), "two") be.Equal(t, conn.Out(), "two")
} }
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseRPop, "rpop key") cmd := redis.MustParse(ParseRPop, "rpop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
} }

View File

@@ -3,9 +3,9 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestRPopLPushParse(t *testing.T) { func TestRPopLPushParse(t *testing.T) {
@@ -34,12 +34,12 @@ func TestRPopLPushParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseRPopLPush, test.cmd) cmd, err := redis.Parse(ParseRPopLPush, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.src, test.want.src) be.Equal(t, cmd.src, test.want.src)
testx.AssertEqual(t, cmd.dst, test.want.dst) be.Equal(t, cmd.dst, test.want.dst)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -47,101 +47,96 @@ func TestRPopLPushParse(t *testing.T) {
func TestRPopLPushExec(t *testing.T) { func TestRPopLPushExec(t *testing.T) {
t.Run("src not found", func(t *testing.T) { t.Run("src not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst") cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
t.Run("pop elem", func(t *testing.T) { t.Run("pop elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("src", "elem")
_, _ = db.List().PushBack("src", "elem")
cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst") cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("elem")) be.Equal(t, res.(core.Value), core.Value("elem"))
testx.AssertEqual(t, conn.Out(), "elem") be.Equal(t, conn.Out(), "elem")
count, _ := db.List().Len("src") count, _ := red.List().Len("src")
testx.AssertEqual(t, count, 0) be.Equal(t, count, 0)
count, _ = db.List().Len("dst") count, _ = red.List().Len("dst")
testx.AssertEqual(t, count, 1) be.Equal(t, count, 1)
}) })
t.Run("pop multiple", func(t *testing.T) { t.Run("pop multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("src", "one")
_, _ = db.List().PushBack("src", "one") _, _ = red.List().PushBack("src", "two")
_, _ = db.List().PushBack("src", "two") _, _ = red.List().PushBack("src", "thr")
_, _ = db.List().PushBack("src", "thr")
{ {
cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst") cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("thr")) be.Equal(t, res.(core.Value), core.Value("thr"))
testx.AssertEqual(t, conn.Out(), "thr") be.Equal(t, conn.Out(), "thr")
} }
{ {
cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst") cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("two")) be.Equal(t, res.(core.Value), core.Value("two"))
testx.AssertEqual(t, conn.Out(), "two") be.Equal(t, conn.Out(), "two")
} }
count, _ := db.List().Len("src") count, _ := red.List().Len("src")
testx.AssertEqual(t, count, 1) be.Equal(t, count, 1)
count, _ = db.List().Len("dst") count, _ = red.List().Len("dst")
testx.AssertEqual(t, count, 2) be.Equal(t, count, 2)
}) })
t.Run("push to self", func(t *testing.T) { t.Run("push to self", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("src", "one")
_, _ = db.List().PushBack("src", "one") _, _ = red.List().PushBack("src", "two")
_, _ = db.List().PushBack("src", "two") _, _ = red.List().PushBack("src", "thr")
_, _ = db.List().PushBack("src", "thr")
{ {
cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src src") cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src src")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("thr")) be.Equal(t, res.(core.Value), core.Value("thr"))
testx.AssertEqual(t, conn.Out(), "thr") be.Equal(t, conn.Out(), "thr")
} }
{ {
cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src src") cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src src")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("two")) be.Equal(t, res.(core.Value), core.Value("two"))
testx.AssertEqual(t, conn.Out(), "two") be.Equal(t, conn.Out(), "two")
} }
elems, _ := db.List().Range("src", 0, -1) elems, _ := red.List().Range("src", 0, -1)
testx.AssertEqual(t, elems[0].String(), "two") be.Equal(t, elems[0].String(), "two")
testx.AssertEqual(t, elems[1].String(), "thr") be.Equal(t, elems[1].String(), "thr")
testx.AssertEqual(t, elems[2].String(), "one") be.Equal(t, elems[2].String(), "one")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("src", "str")
_ = db.Str().Set("src", "str")
cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst") cmd := redis.MustParse(ParseRPopLPush, "rpoplpush src dst")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
} }

View File

@@ -3,9 +3,9 @@ package list
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestRPushParse(t *testing.T) { func TestRPushParse(t *testing.T) {
@@ -39,12 +39,12 @@ func TestRPushParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseRPush, test.cmd) cmd, err := redis.Parse(ParseRPush, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.elem, test.want.elem) be.Equal(t, cmd.elem, test.want.elem)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -52,70 +52,66 @@ func TestRPushParse(t *testing.T) {
func TestRPushExec(t *testing.T) { func TestRPushExec(t *testing.T) {
t.Run("empty list", func(t *testing.T) { t.Run("empty list", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseRPush, "rpush key elem") cmd := redis.MustParse(ParseRPush, "rpush key elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
elem, _ := db.List().Get("key", 0) elem, _ := red.List().Get("key", 0)
testx.AssertEqual(t, elem.String(), "elem") be.Equal(t, elem.String(), "elem")
}) })
t.Run("add elem", func(t *testing.T) { t.Run("add elem", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.List().PushBack("key", "one")
_, _ = db.List().PushBack("key", "one")
cmd := redis.MustParse(ParseRPush, "rpush key two") cmd := redis.MustParse(ParseRPush, "rpush key two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
elem, _ := db.List().Get("key", 1) elem, _ := red.List().Get("key", 1)
testx.AssertEqual(t, elem.String(), "two") be.Equal(t, elem.String(), "two")
}) })
t.Run("add miltiple", func(t *testing.T) { t.Run("add miltiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
{ {
cmd := redis.MustParse(ParseRPush, "rpush key one") cmd := redis.MustParse(ParseRPush, "rpush key one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
} }
{ {
cmd := redis.MustParse(ParseRPush, "rpush key two") cmd := redis.MustParse(ParseRPush, "rpush key two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
} }
el0, _ := db.List().Get("key", 0) el0, _ := red.List().Get("key", 0)
testx.AssertEqual(t, el0.String(), "one") be.Equal(t, el0.String(), "one")
el1, _ := db.List().Get("key", 1) el1, _ := red.List().Get("key", 1)
testx.AssertEqual(t, el1.String(), "two") be.Equal(t, el1.String(), "two")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseRPush, "rpush key elem") cmd := redis.MustParse(ParseRPush, "rpush key elem")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrKeyType) be.Err(t, err, core.ErrKeyType)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), core.ErrKeyType.Error()+" (rpush)") be.Equal(t, conn.Out(), core.ErrKeyType.Error()+" (rpush)")
}) })
} }

View File

@@ -3,8 +3,8 @@ package server
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestConfigParse(t *testing.T) { func TestConfigParse(t *testing.T) {
@@ -38,11 +38,11 @@ func TestConfigParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseConfig, test.cmd) cmd, err := redis.Parse(ParseConfig, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.subcmd, test.want.subcmd) be.Equal(t, cmd.subcmd, test.want.subcmd)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -50,14 +50,13 @@ func TestConfigParse(t *testing.T) {
func TestConfigExec(t *testing.T) { func TestConfigExec(t *testing.T) {
t.Run("config get", func(t *testing.T) { t.Run("config get", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseConfig, "config get *") cmd := redis.MustParse(ParseConfig, "config get *")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "2,databases,1") be.Equal(t, conn.Out(), "2,databases,1")
}) })
} }

View File

@@ -3,8 +3,8 @@ package server
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestDBSizeParse(t *testing.T) { func TestDBSizeParse(t *testing.T) {
@@ -25,9 +25,9 @@ func TestDBSizeParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseDBSize, test.cmd) cmd, err := redis.Parse(ParseDBSize, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err != nil { if err != nil {
testx.AssertEqual(t, cmd, DBSize{}) be.Equal(t, cmd, DBSize{})
} }
}) })
} }
@@ -35,29 +35,26 @@ func TestDBSizeParse(t *testing.T) {
func TestDBSizeExec(t *testing.T) { func TestDBSizeExec(t *testing.T) {
t.Run("dbsize", func(t *testing.T) { t.Run("dbsize", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = red.Str().Set("age", 25)
_ = db.Str().Set("name", "alice")
_ = db.Str().Set("age", 25)
cmd := redis.MustParse(ParseDBSize, "dbsize") cmd := redis.MustParse(ParseDBSize, "dbsize")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseDBSize, "dbsize") cmd := redis.MustParse(ParseDBSize, "dbsize")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -4,8 +4,8 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestLolwutParse(t *testing.T) { func TestLolwutParse(t *testing.T) {
@@ -30,9 +30,9 @@ func TestLolwutParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseLolwut, test.cmd) cmd, err := redis.Parse(ParseLolwut, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err != nil { if err != nil {
testx.AssertEqual(t, cmd, Lolwut{}) be.Equal(t, cmd, Lolwut{})
} }
}) })
} }
@@ -40,24 +40,22 @@ func TestLolwutParse(t *testing.T) {
func TestLolwutExec(t *testing.T) { func TestLolwutExec(t *testing.T) {
t.Run("lolwut", func(t *testing.T) { t.Run("lolwut", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLolwut, "lolwut you ok?") cmd := redis.MustParse(ParseLolwut, "lolwut you ok?")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
_, err := cmd.Run(conn, red) _, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(conn.Out()) >= 3, true) be.Equal(t, len(conn.Out()) >= 3, true)
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseLolwut, "lolwut") cmd := redis.MustParse(ParseLolwut, "lolwut")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
_, err := cmd.Run(conn, red) _, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, strings.HasPrefix(conn.Out(), "Ask me a question"), true) be.Equal(t, strings.HasPrefix(conn.Out(), "Ask me a question"), true)
}) })
} }

View File

@@ -3,15 +3,12 @@ package server
import ( import (
"testing" "testing"
"github.com/nalgeon/redka"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func getDB(tb testing.TB) (*redka.DB, redis.Redka) { func getRedka(tb testing.TB) redis.Redka {
tb.Helper() tb.Helper()
db, err := redka.Open("file:/data.db?vfs=memdb", nil) db := testx.OpenDB(tb)
if err != nil { return redis.RedkaDB(db)
tb.Fatal(err)
}
return db, redis.RedkaDB(db)
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSAddParse(t *testing.T) { func TestSAddParse(t *testing.T) {
@@ -44,12 +44,12 @@ func TestSAddParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSAdd, test.cmd) cmd, err := redis.Parse(ParseSAdd, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.members, test.want.members) be.Equal(t, cmd.members, test.want.members)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -57,76 +57,71 @@ func TestSAddParse(t *testing.T) {
func TestSAddExec(t *testing.T) { func TestSAddExec(t *testing.T) {
t.Run("create single", func(t *testing.T) { t.Run("create single", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSAdd, "sadd key one") cmd := redis.MustParse(ParseSAdd, "sadd key one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
items, _ := db.Set().Items("key") items, _ := red.Set().Items("key")
testx.AssertEqual(t, items, []core.Value{core.Value("one")}) be.Equal(t, items, []core.Value{core.Value("one")})
}) })
t.Run("create multiple", func(t *testing.T) { t.Run("create multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSAdd, "sadd key one two") cmd := redis.MustParse(ParseSAdd, "sadd key one two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
items, _ := db.Set().Items("key") items, _ := red.Set().Items("key")
sortValues(items) sortValues(items)
testx.AssertEqual(t, items, []core.Value{core.Value("one"), core.Value("two")}) be.Equal(t, items, []core.Value{core.Value("one"), core.Value("two")})
}) })
t.Run("create/update", func(t *testing.T) { t.Run("create/update", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one")
_, _ = db.Set().Add("key", "one")
cmd := redis.MustParse(ParseSAdd, "sadd key one two") cmd := redis.MustParse(ParseSAdd, "sadd key one two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
items, _ := db.Set().Items("key") items, _ := red.Set().Items("key")
sortValues(items) sortValues(items)
testx.AssertEqual(t, items, []core.Value{core.Value("one"), core.Value("two")}) be.Equal(t, items, []core.Value{core.Value("one"), core.Value("two")})
}) })
t.Run("update multiple", func(t *testing.T) { t.Run("update multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one", "two")
_, _ = db.Set().Add("key", "one", "two")
cmd := redis.MustParse(ParseSAdd, "sadd key one two") cmd := redis.MustParse(ParseSAdd, "sadd key one two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
items, _ := db.Set().Items("key") items, _ := red.Set().Items("key")
sortValues(items) sortValues(items)
testx.AssertEqual(t, items, []core.Value{core.Value("one"), core.Value("two")}) be.Equal(t, items, []core.Value{core.Value("one"), core.Value("two")})
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "value")
_ = db.Str().Set("key", "value")
cmd := redis.MustParse(ParseSAdd, "sadd key one") cmd := redis.MustParse(ParseSAdd, "sadd key one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrKeyType) be.Err(t, err, core.ErrKeyType)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), core.ErrKeyType.Error()+" (sadd)") be.Equal(t, conn.Out(), core.ErrKeyType.Error()+" (sadd)")
}) })
} }

View File

@@ -3,8 +3,8 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSCardParse(t *testing.T) { func TestSCardParse(t *testing.T) {
@@ -33,11 +33,11 @@ func TestSCardParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSCard, test.cmd) cmd, err := redis.Parse(ParseSCard, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -45,51 +45,47 @@ func TestSCardParse(t *testing.T) {
func TestSCardExec(t *testing.T) { func TestSCardExec(t *testing.T) {
t.Run("card", func(t *testing.T) { t.Run("card", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one", "two")
_, _ = db.Set().Add("key", "one", "two")
cmd := redis.MustParse(ParseSCard, "scard key") cmd := redis.MustParse(ParseSCard, "scard key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one")
_, _ = db.Set().Add("key", "one") _, _ = red.Set().Delete("key", "one")
_, _ = db.Set().Delete("key", "one")
cmd := redis.MustParse(ParseSCard, "scard key") cmd := redis.MustParse(ParseSCard, "scard key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSCard, "scard key") cmd := redis.MustParse(ParseSCard, "scard key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "value")
_ = db.Str().Set("key", "value")
cmd := redis.MustParse(ParseSCard, "scard key") cmd := redis.MustParse(ParseSCard, "scard key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSDiffParse(t *testing.T) { func TestSDiffParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestSDiffParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSDiff, test.cmd) cmd, err := redis.Parse(ParseSDiff, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.keys, test.want.keys) be.Equal(t, cmd.keys, test.want.keys)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -46,105 +46,97 @@ func TestSDiffParse(t *testing.T) {
func TestSDiffExec(t *testing.T) { func TestSDiffExec(t *testing.T) {
t.Run("non-empty", func(t *testing.T) { t.Run("non-empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two", "thr", "fiv")
_, _ = db.Set().Add("key1", "one", "two", "thr", "fiv") _, _ = red.Set().Add("key2", "two", "fou", "six")
_, _ = db.Set().Add("key2", "two", "fou", "six") _, _ = red.Set().Add("key3", "thr", "six")
_, _ = db.Set().Add("key3", "thr", "six")
cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3") cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 2) be.Equal(t, len(res.([]core.Value)), 2)
testx.AssertEqual(t, conn.Out(), "2,fiv,one") be.Equal(t, conn.Out(), "2,fiv,one", "2,one,fiv")
}) })
t.Run("no keys", func(t *testing.T) { t.Run("no keys", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSDiff, "sdiff key1") cmd := redis.MustParse(ParseSDiff, "sdiff key1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("single key", func(t *testing.T) { t.Run("single key", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two", "thr")
_, _ = db.Set().Add("key1", "one", "two", "thr")
cmd := redis.MustParse(ParseSDiff, "sdiff key1") cmd := redis.MustParse(ParseSDiff, "sdiff key1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 3) be.Equal(t, len(res.([]core.Value)), 3)
testx.AssertEqual(t, conn.Out(), "3,one,thr,two") be.Equal(t, conn.Out(), "3,one,thr,two", "3,one,two,thr")
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two")
_, _ = db.Set().Add("key1", "one", "two") _, _ = red.Set().Add("key2", "one", "fou")
_, _ = db.Set().Add("key2", "one", "fou") _, _ = red.Set().Add("key3", "two", "fiv")
_, _ = db.Set().Add("key3", "two", "fiv")
cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3") cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("first not found", func(t *testing.T) { t.Run("first not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key2", "two")
_, _ = db.Set().Add("key2", "two") _, _ = red.Set().Add("key3", "thr")
_, _ = db.Set().Add("key3", "thr")
cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3") cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("rest not found", func(t *testing.T) { t.Run("rest not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "two")
_, _ = db.Set().Add("key2", "two")
cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3") cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 1) be.Equal(t, len(res.([]core.Value)), 1)
testx.AssertEqual(t, conn.Out(), "1,one") be.Equal(t, conn.Out(), "1,one")
}) })
t.Run("all not found", func(t *testing.T) { t.Run("all not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3") cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _ = red.Str().Set("key2", "two")
_ = db.Str().Set("key2", "two") _, _ = red.Set().Add("key3", "thr")
_, _ = db.Set().Add("key3", "thr")
cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3") cmd := redis.MustParse(ParseSDiff, "sdiff key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 1) be.Equal(t, len(res.([]core.Value)), 1)
testx.AssertEqual(t, conn.Out(), "1,one") be.Equal(t, conn.Out(), "1,one")
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSDiffStoreParse(t *testing.T) { func TestSDiffStoreParse(t *testing.T) {
@@ -39,12 +39,12 @@ func TestSDiffStoreParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSDiffStore, test.cmd) cmd, err := redis.Parse(ParseSDiffStore, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.dest, test.want.dest) be.Equal(t, cmd.dest, test.want.dest)
testx.AssertEqual(t, cmd.keys, test.want.keys) be.Equal(t, cmd.keys, test.want.keys)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -52,139 +52,131 @@ func TestSDiffStoreParse(t *testing.T) {
func TestSDiffStoreExec(t *testing.T) { func TestSDiffStoreExec(t *testing.T) {
t.Run("store", func(t *testing.T) { t.Run("store", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two", "thr", "fiv")
_, _ = db.Set().Add("key1", "one", "two", "thr", "fiv") _, _ = red.Set().Add("key2", "two", "fou", "six")
_, _ = db.Set().Add("key2", "two", "fou", "six") _, _ = red.Set().Add("key3", "thr", "six")
_, _ = db.Set().Add("key3", "thr", "six")
cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2 key3") cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
sortValues(items) sortValues(items)
testx.AssertEqual(t, items, []core.Value{core.Value("fiv"), core.Value("one")}) be.Equal(t, items, []core.Value{core.Value("fiv"), core.Value("one")})
}) })
t.Run("rewrite dest", func(t *testing.T) { t.Run("rewrite dest", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "two")
_, _ = db.Set().Add("key2", "two") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2") cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value{core.Value("one")}) be.Equal(t, items, []core.Value{core.Value("one")})
}) })
t.Run("single key", func(t *testing.T) { t.Run("single key", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two")
_, _ = db.Set().Add("key1", "one", "two") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1") cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
sortValues(items) sortValues(items)
testx.AssertEqual(t, items, []core.Value{core.Value("one"), core.Value("two")}) be.Equal(t, items, []core.Value{core.Value("one"), core.Value("two")})
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2") cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value(nil)) be.Equal(t, items, []core.Value(nil))
}) })
t.Run("first not found", func(t *testing.T) { t.Run("first not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key2", "two")
_, _ = db.Set().Add("key2", "two") _, _ = red.Set().Add("key3", "thr")
_, _ = db.Set().Add("key3", "thr") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2 key3") cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value(nil)) be.Equal(t, items, []core.Value(nil))
}) })
t.Run("rest not found", func(t *testing.T) { t.Run("rest not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "two")
_, _ = db.Set().Add("key2", "two")
cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2 key3") cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value{core.Value("one")}) be.Equal(t, items, []core.Value{core.Value("one")})
}) })
t.Run("source key type mismatch", func(t *testing.T) { t.Run("source key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "two")
_, _ = db.Set().Add("key2", "two") _ = red.Str().Set("key3", "thr")
_ = db.Str().Set("key3", "thr")
cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2 key3") cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value{core.Value("one")}) be.Equal(t, items, []core.Value{core.Value("one")})
}) })
t.Run("dest key type mismatch", func(t *testing.T) { t.Run("dest key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "two")
_, _ = db.Set().Add("key2", "two") _ = red.Str().Set("dest", "old")
_ = db.Str().Set("dest", "old")
cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2") cmd := redis.MustParse(ParseSDiffStore, "sdiffstore dest key1 key2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrKeyType) be.Err(t, err, core.ErrKeyType)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), core.ErrKeyType.Error()+" (sdiffstore)") be.Equal(t, conn.Out(), core.ErrKeyType.Error()+" (sdiffstore)")
sval, _ := db.Str().Get("dest") sval, _ := red.Str().Get("dest")
testx.AssertEqual(t, sval, core.Value("old")) be.Equal(t, sval, core.Value("old"))
}) })
} }

View File

@@ -5,18 +5,15 @@ import (
"sort" "sort"
"testing" "testing"
"github.com/nalgeon/redka"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func getDB(tb testing.TB) (*redka.DB, redis.Redka) { func getRedka(tb testing.TB) redis.Redka {
tb.Helper() tb.Helper()
db, err := redka.Open("file:/data.db?vfs=memdb", nil) db := testx.OpenDB(tb)
if err != nil { return redis.RedkaDB(db)
tb.Fatal(err)
}
return db, redis.RedkaDB(db)
} }
func sortValues(vals []core.Value) { func sortValues(vals []core.Value) {

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSInterParse(t *testing.T) { func TestSInterParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestSInterParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSInter, test.cmd) cmd, err := redis.Parse(ParseSInter, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.keys, test.want.keys) be.Equal(t, cmd.keys, test.want.keys)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -46,92 +46,85 @@ func TestSInterParse(t *testing.T) {
func TestSInterExec(t *testing.T) { func TestSInterExec(t *testing.T) {
t.Run("non-empty", func(t *testing.T) { t.Run("non-empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two", "thr")
_, _ = db.Set().Add("key1", "one", "two", "thr") _, _ = red.Set().Add("key2", "two", "thr", "fou")
_, _ = db.Set().Add("key2", "two", "thr", "fou") _, _ = red.Set().Add("key3", "one", "two", "thr", "fou")
_, _ = db.Set().Add("key3", "one", "two", "thr", "fou")
cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3") cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 2) be.Equal(t, len(res.([]core.Value)), 2)
testx.AssertEqual(t, conn.Out(), "2,thr,two") be.Equal(t, conn.Out(), "2,thr,two")
}) })
t.Run("no keys", func(t *testing.T) { t.Run("no keys", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSInter, "sinter key1") cmd := redis.MustParse(ParseSInter, "sinter key1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("single key", func(t *testing.T) { t.Run("single key", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two", "thr")
_, _ = db.Set().Add("key1", "one", "two", "thr")
cmd := redis.MustParse(ParseSInter, "sinter key1") cmd := redis.MustParse(ParseSInter, "sinter key1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 3) be.Equal(t, len(res.([]core.Value)), 3)
testx.AssertEqual(t, conn.Out(), "3,one,thr,two") be.Equal(t, conn.Out(), "3,one,thr,two")
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two")
_, _ = db.Set().Add("key1", "one", "two") _, _ = red.Set().Add("key2", "two", "thr")
_, _ = db.Set().Add("key2", "two", "thr") _, _ = red.Set().Add("key3", "thr", "fou")
_, _ = db.Set().Add("key3", "thr", "fou")
cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3") cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one")
cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3") cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("all not found", func(t *testing.T) { t.Run("all not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3") cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _ = red.Str().Set("key2", "one")
_ = db.Str().Set("key2", "one") _, _ = red.Set().Add("key3", "one")
_, _ = db.Set().Add("key3", "one")
cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3") cmd := redis.MustParse(ParseSInter, "sinter key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSInterStoreParse(t *testing.T) { func TestSInterStoreParse(t *testing.T) {
@@ -39,10 +39,10 @@ func TestSInterStoreParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSInterStore, test.cmd) cmd, err := redis.Parse(ParseSInterStore, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.dest, test.want.dest) be.Equal(t, cmd.dest, test.want.dest)
testx.AssertEqual(t, cmd.keys, test.want.keys) be.Equal(t, cmd.keys, test.want.keys)
} }
}) })
} }
@@ -50,123 +50,116 @@ func TestSInterStoreParse(t *testing.T) {
func TestSInterStoreExec(t *testing.T) { func TestSInterStoreExec(t *testing.T) {
t.Run("store", func(t *testing.T) { t.Run("store", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two", "thr")
_, _ = db.Set().Add("key1", "one", "two", "thr") _, _ = red.Set().Add("key2", "two", "thr", "fou")
_, _ = db.Set().Add("key2", "two", "thr", "fou") _, _ = red.Set().Add("key3", "one", "two", "thr", "fou")
_, _ = db.Set().Add("key3", "one", "two", "thr", "fou")
cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2 key3") cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
sortValues(items) sortValues(items)
testx.AssertEqual(t, items, []core.Value{core.Value("thr"), core.Value("two")}) be.Equal(t, items, []core.Value{core.Value("thr"), core.Value("two")})
}) })
t.Run("rewrite dest", func(t *testing.T) { t.Run("rewrite dest", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2") cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value{core.Value("one")}) be.Equal(t, items, []core.Value{core.Value("one")})
}) })
t.Run("single key", func(t *testing.T) { t.Run("single key", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two")
_, _ = db.Set().Add("key1", "one", "two") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1") cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
sortValues(items) sortValues(items)
testx.AssertEqual(t, items, []core.Value{core.Value("one"), core.Value("two")}) be.Equal(t, items, []core.Value{core.Value("one"), core.Value("two")})
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "two")
_, _ = db.Set().Add("key2", "two") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2") cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value(nil)) be.Equal(t, items, []core.Value(nil))
}) })
t.Run("source key not found", func(t *testing.T) { t.Run("source key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2 key3") cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value(nil)) be.Equal(t, items, []core.Value(nil))
}) })
t.Run("source key type mismatch", func(t *testing.T) { t.Run("source key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one") _ = red.Str().Set("key3", "one")
_ = db.Str().Set("key3", "one")
cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2 key3") cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value(nil)) be.Equal(t, items, []core.Value(nil))
}) })
t.Run("dest key type mismatch", func(t *testing.T) { t.Run("dest key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one") _ = red.Str().Set("dest", "old")
_ = db.Str().Set("dest", "old")
cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2") cmd := redis.MustParse(ParseSInterStore, "sinterstore dest key1 key2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrKeyType) be.Err(t, err, core.ErrKeyType)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), core.ErrKeyType.Error()+" (sinterstore)") be.Equal(t, conn.Out(), core.ErrKeyType.Error()+" (sinterstore)")
sval, _ := db.Str().Get("dest") sval, _ := red.Str().Get("dest")
testx.AssertEqual(t, sval, core.Value("old")) be.Equal(t, sval, core.Value("old"))
}) })
} }

View File

@@ -3,8 +3,8 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSIsMemberParse(t *testing.T) { func TestSIsMemberParse(t *testing.T) {
@@ -38,12 +38,12 @@ func TestSIsMemberParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSIsMember, test.cmd) cmd, err := redis.Parse(ParseSIsMember, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.member, test.want.member) be.Equal(t, cmd.member, test.want.member)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -51,50 +51,46 @@ func TestSIsMemberParse(t *testing.T) {
func TestSIsMemberExec(t *testing.T) { func TestSIsMemberExec(t *testing.T) {
t.Run("elem found", func(t *testing.T) { t.Run("elem found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one")
_, _ = db.Set().Add("key", "one")
cmd := redis.MustParse(ParseSIsMember, "sismember key one") cmd := redis.MustParse(ParseSIsMember, "sismember key one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
}) })
t.Run("elem not found", func(t *testing.T) { t.Run("elem not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one")
_, _ = db.Set().Add("key", "one")
cmd := redis.MustParse(ParseSIsMember, "sismember key two") cmd := redis.MustParse(ParseSIsMember, "sismember key two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSIsMember, "sismember key one") cmd := redis.MustParse(ParseSIsMember, "sismember key one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "one")
_ = db.Str().Set("key", "one")
cmd := redis.MustParse(ParseSIsMember, "sismember key one") cmd := redis.MustParse(ParseSIsMember, "sismember key one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, false) be.Equal(t, res, false)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSMembersParse(t *testing.T) { func TestSMembersParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestSMembersParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSMembers, test.cmd) cmd, err := redis.Parse(ParseSMembers, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -46,40 +46,35 @@ func TestSMembersParse(t *testing.T) {
func TestSMembersExec(t *testing.T) { func TestSMembersExec(t *testing.T) {
t.Run("items", func(t *testing.T) { t.Run("items", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one", "two", "thr")
_, _ = db.Set().Add("key", "one", "two", "thr")
cmd := redis.MustParse(ParseSMembers, "smembers key") cmd := redis.MustParse(ParseSMembers, "smembers key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value{ be.Equal(t, len(res.([]core.Value)), 3)
core.Value("one"), core.Value("thr"), core.Value("two"), be.Equal(t, conn.Out(), "3,one,thr,two", "3,one,two,thr")
})
testx.AssertEqual(t, conn.Out(), "3,one,thr,two")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSMembers, "smembers key") cmd := redis.MustParse(ParseSMembers, "smembers key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value(nil)) be.Equal(t, res.([]core.Value), []core.Value(nil))
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "value")
_ = db.Str().Set("key", "value")
cmd := redis.MustParse(ParseSMembers, "smembers key") cmd := redis.MustParse(ParseSMembers, "smembers key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, []core.Value(nil)) be.Equal(t, res.([]core.Value), []core.Value(nil))
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSMoveParse(t *testing.T) { func TestSMoveParse(t *testing.T) {
@@ -39,13 +39,13 @@ func TestSMoveParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSMove, test.cmd) cmd, err := redis.Parse(ParseSMove, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.src, test.want.src) be.Equal(t, cmd.src, test.want.src)
testx.AssertEqual(t, cmd.dest, test.want.dest) be.Equal(t, cmd.dest, test.want.dest)
testx.AssertEqual(t, cmd.member, test.want.member) be.Equal(t, cmd.member, test.want.member)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -53,109 +53,103 @@ func TestSMoveParse(t *testing.T) {
func TestSMoveExec(t *testing.T) { func TestSMoveExec(t *testing.T) {
t.Run("move", func(t *testing.T) { t.Run("move", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("src", "one", "two")
_, _ = db.Set().Add("src", "one", "two") _, _ = red.Set().Add("dest", "thr", "fou")
_, _ = db.Set().Add("dest", "thr", "fou")
cmd := redis.MustParse(ParseSMove, "smove src dest one") cmd := redis.MustParse(ParseSMove, "smove src dest one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
sone, _ := db.Set().Exists("src", "one") sone, _ := red.Set().Exists("src", "one")
testx.AssertEqual(t, sone, false) be.Equal(t, sone, false)
done, _ := db.Set().Exists("dest", "one") done, _ := red.Set().Exists("dest", "one")
testx.AssertEqual(t, done, true) be.Equal(t, done, true)
}) })
t.Run("dest not found", func(t *testing.T) { t.Run("dest not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("src", "one", "two")
_, _ = db.Set().Add("src", "one", "two")
cmd := redis.MustParse(ParseSMove, "smove src dest one") cmd := redis.MustParse(ParseSMove, "smove src dest one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
sone, _ := db.Set().Exists("src", "one") sone, _ := red.Set().Exists("src", "one")
testx.AssertEqual(t, sone, false) be.Equal(t, sone, false)
done, _ := db.Set().Exists("dest", "one") done, _ := red.Set().Exists("dest", "one")
testx.AssertEqual(t, done, true) be.Equal(t, done, true)
}) })
t.Run("src elem not found", func(t *testing.T) { t.Run("src elem not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("src", "two")
_, _ = db.Set().Add("src", "two") _, _ = red.Set().Add("dest", "thr", "fou")
_, _ = db.Set().Add("dest", "thr", "fou")
cmd := redis.MustParse(ParseSMove, "smove src dest one") cmd := redis.MustParse(ParseSMove, "smove src dest one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
sone, _ := db.Set().Exists("src", "one") sone, _ := red.Set().Exists("src", "one")
testx.AssertEqual(t, sone, false) be.Equal(t, sone, false)
done, _ := db.Set().Exists("dest", "one") done, _ := red.Set().Exists("dest", "one")
testx.AssertEqual(t, done, false) be.Equal(t, done, false)
}) })
t.Run("src key not found", func(t *testing.T) { t.Run("src key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("dest", "thr", "fou")
_, _ = db.Set().Add("dest", "thr", "fou")
cmd := redis.MustParse(ParseSMove, "smove src dest one") cmd := redis.MustParse(ParseSMove, "smove src dest one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
sone, _ := db.Set().Exists("src", "one") sone, _ := red.Set().Exists("src", "one")
testx.AssertEqual(t, sone, false) be.Equal(t, sone, false)
done, _ := db.Set().Exists("dest", "one") done, _ := red.Set().Exists("dest", "one")
testx.AssertEqual(t, done, false) be.Equal(t, done, false)
}) })
t.Run("dest type mismatch", func(t *testing.T) { t.Run("dest type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("src", "one", "two")
_, _ = db.Set().Add("src", "one", "two") _ = red.Str().Set("dest", "str")
_ = db.Str().Set("dest", "str")
cmd := redis.MustParse(ParseSMove, "smove src dest one") cmd := redis.MustParse(ParseSMove, "smove src dest one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrKeyType) be.Err(t, err, core.ErrKeyType)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), core.ErrKeyType.Error()+" (smove)") be.Equal(t, conn.Out(), core.ErrKeyType.Error()+" (smove)")
sone, _ := db.Set().Exists("src", "one") sone, _ := red.Set().Exists("src", "one")
testx.AssertEqual(t, sone, true) be.Equal(t, sone, true)
done, _ := db.Set().Exists("dest", "one") done, _ := red.Set().Exists("dest", "one")
testx.AssertEqual(t, done, false) be.Equal(t, done, false)
}) })
t.Run("src type mismatch", func(t *testing.T) { t.Run("src type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("src", "one")
_ = db.Str().Set("src", "one") _, _ = red.Set().Add("dest", "thr", "fou")
_, _ = db.Set().Add("dest", "thr", "fou")
cmd := redis.MustParse(ParseSMove, "smove src dest one") cmd := redis.MustParse(ParseSMove, "smove src dest one")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
sone, _ := db.Set().Exists("src", "one") sone, _ := red.Set().Exists("src", "one")
testx.AssertEqual(t, sone, false) be.Equal(t, sone, false)
done, _ := db.Set().Exists("dest", "one") done, _ := red.Set().Exists("dest", "one")
testx.AssertEqual(t, done, false) be.Equal(t, done, false)
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSPopParse(t *testing.T) { func TestSPopParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestSPopParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSPop, test.cmd) cmd, err := redis.Parse(ParseSPop, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -46,43 +46,40 @@ func TestSPopParse(t *testing.T) {
func TestSPopExec(t *testing.T) { func TestSPopExec(t *testing.T) {
t.Run("pop", func(t *testing.T) { t.Run("pop", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one", "two", "thr")
_, _ = db.Set().Add("key", "one", "two", "thr")
cmd := redis.MustParse(ParseSPop, "spop key") cmd := redis.MustParse(ParseSPop, "spop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
s := res.(core.Value).String() s := res.(core.Value).String()
testx.AssertEqual(t, s == "one" || s == "two" || s == "thr", true) be.Equal(t, s == "one" || s == "two" || s == "thr", true)
s = conn.Out() s = conn.Out()
testx.AssertEqual(t, s == "one" || s == "two" || s == "thr", true) be.Equal(t, s == "one" || s == "two" || s == "thr", true)
slen, _ := db.Set().Len("key") slen, _ := red.Set().Len("key")
testx.AssertEqual(t, slen, 2) be.Equal(t, slen, 2)
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSPop, "spop key") cmd := redis.MustParse(ParseSPop, "spop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "value")
_ = db.Str().Set("key", "value")
cmd := redis.MustParse(ParseSPop, "spop key") cmd := redis.MustParse(ParseSPop, "spop key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSRandMemberParse(t *testing.T) { func TestSRandMemberParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestSRandMemberParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSRandMember, test.cmd) cmd, err := redis.Parse(ParseSRandMember, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -46,40 +46,37 @@ func TestSRandMemberParse(t *testing.T) {
func TestSRandMemberExec(t *testing.T) { func TestSRandMemberExec(t *testing.T) {
t.Run("random", func(t *testing.T) { t.Run("random", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one", "two", "thr")
_, _ = db.Set().Add("key", "one", "two", "thr")
cmd := redis.MustParse(ParseSRandMember, "srandmember key") cmd := redis.MustParse(ParseSRandMember, "srandmember key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
s := res.(core.Value).String() s := res.(core.Value).String()
testx.AssertEqual(t, s == "one" || s == "two" || s == "thr", true) be.Equal(t, s == "one" || s == "two" || s == "thr", true)
s = conn.Out() s = conn.Out()
testx.AssertEqual(t, s == "one" || s == "two" || s == "thr", true) be.Equal(t, s == "one" || s == "two" || s == "thr", true)
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSRandMember, "srandmember key") cmd := redis.MustParse(ParseSRandMember, "srandmember key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "value")
_ = db.Str().Set("key", "value")
cmd := redis.MustParse(ParseSRandMember, "srandmember key") cmd := redis.MustParse(ParseSRandMember, "srandmember key")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSRemParse(t *testing.T) { func TestSRemParse(t *testing.T) {
@@ -44,12 +44,12 @@ func TestSRemParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSRem, test.cmd) cmd, err := redis.Parse(ParseSRem, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.members, test.want.members) be.Equal(t, cmd.members, test.want.members)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -57,56 +57,52 @@ func TestSRemParse(t *testing.T) {
func TestSRemExec(t *testing.T) { func TestSRemExec(t *testing.T) {
t.Run("some", func(t *testing.T) { t.Run("some", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one", "two", "thr")
_, _ = db.Set().Add("key", "one", "two", "thr")
cmd := redis.MustParse(ParseSRem, "srem key one thr") cmd := redis.MustParse(ParseSRem, "srem key one thr")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
items, _ := db.Set().Items("key") items, _ := red.Set().Items("key")
testx.AssertEqual(t, items, []core.Value{core.Value("two")}) be.Equal(t, items, []core.Value{core.Value("two")})
}) })
t.Run("none", func(t *testing.T) { t.Run("none", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "one", "two", "thr")
_, _ = db.Set().Add("key", "one", "two", "thr")
cmd := redis.MustParse(ParseSRem, "srem key fou fiv") cmd := redis.MustParse(ParseSRem, "srem key fou fiv")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
slen, _ := db.Set().Len("key") slen, _ := red.Set().Len("key")
testx.AssertEqual(t, slen, 3) be.Equal(t, slen, 3)
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSRem, "srem key one two") cmd := redis.MustParse(ParseSRem, "srem key one two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("key", "str")
_ = db.Str().Set("key", "str")
cmd := redis.MustParse(ParseSRem, "srem key one two") cmd := redis.MustParse(ParseSRem, "srem key one two")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
} }

View File

@@ -1,12 +1,13 @@
package set package set
import ( import (
"fmt"
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/rset" "github.com/nalgeon/redka/internal/rset"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSScanParse(t *testing.T) { func TestSScanParse(t *testing.T) {
@@ -103,50 +104,53 @@ func TestSScanParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSScan, test.cmd) cmd, err := redis.Parse(ParseSScan, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.key) be.Equal(t, cmd.key, test.key)
testx.AssertEqual(t, cmd.cursor, test.cursor) be.Equal(t, cmd.cursor, test.cursor)
testx.AssertEqual(t, cmd.match, test.match) be.Equal(t, cmd.match, test.match)
testx.AssertEqual(t, cmd.count, test.count) be.Equal(t, cmd.count, test.count)
} else { } else {
testx.AssertEqual(t, cmd, SScan{}) be.Equal(t, cmd, SScan{})
} }
}) })
} }
} }
func TestSScanExec(t *testing.T) { func TestSScanExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key", "m11", "m12", "m21", "m22", "m31")
_, _ = db.Set().Add("key", "m11", "m12", "m21", "m22", "m31")
t.Run("sscan all", func(t *testing.T) { t.Run("sscan all", func(t *testing.T) {
var cursor int
{ {
cmd := redis.MustParse(ParseSScan, "sscan key 0") cmd := redis.MustParse(ParseSScan, "sscan key 0")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rset.ScanResult) sres := res.(rset.ScanResult)
testx.AssertEqual(t, sres.Cursor, 5) be.True(t, sres.Cursor > 0)
testx.AssertEqual(t, len(sres.Items), 5) be.Equal(t, len(sres.Items), 5)
testx.AssertEqual(t, sres.Items[0], core.Value("m11")) be.Equal(t, sres.Items[0], core.Value("m11"))
testx.AssertEqual(t, sres.Items[4], core.Value("m31")) be.Equal(t, sres.Items[4], core.Value("m31"))
testx.AssertEqual(t, conn.Out(), "2,5,5,m11,m12,m21,m22,m31") wantOut := fmt.Sprintf("2,%d,5,m11,m12,m21,m22,m31", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
cmd := redis.MustParse(ParseSScan, "sscan key 5") next := fmt.Sprintf("sscan key %d", cursor)
cmd := redis.MustParse(ParseSScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rset.ScanResult) sres := res.(rset.ScanResult)
testx.AssertEqual(t, sres.Cursor, 0) be.Equal(t, sres.Cursor, 0)
testx.AssertEqual(t, len(sres.Items), 0) be.Equal(t, len(sres.Items), 0)
testx.AssertEqual(t, conn.Out(), "2,0,0") be.Equal(t, conn.Out(), "2,0,0")
} }
}) })
t.Run("sscan pattern", func(t *testing.T) { t.Run("sscan pattern", func(t *testing.T) {
@@ -154,72 +158,83 @@ func TestSScanExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rset.ScanResult) sres := res.(rset.ScanResult)
testx.AssertEqual(t, sres.Cursor, 4) be.True(t, sres.Cursor > 0)
testx.AssertEqual(t, len(sres.Items), 2) be.Equal(t, len(sres.Items), 2)
testx.AssertEqual(t, sres.Items[0].String(), "m21") be.Equal(t, sres.Items[0].String(), "m21")
testx.AssertEqual(t, sres.Items[1].String(), "m22") be.Equal(t, sres.Items[1].String(), "m22")
testx.AssertEqual(t, conn.Out(), "2,4,2,m21,m22") wantOut := fmt.Sprintf("2,%d,2,m21,m22", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
}) })
t.Run("sscan count", func(t *testing.T) { t.Run("sscan count", func(t *testing.T) {
var cursor int
{ {
// page 1 // page 1
cmd := redis.MustParse(ParseSScan, "sscan key 0 match * count 2") cmd := redis.MustParse(ParseSScan, "sscan key 0 match * count 2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rset.ScanResult) sres := res.(rset.ScanResult)
testx.AssertEqual(t, sres.Cursor, 2) be.True(t, sres.Cursor > 0)
testx.AssertEqual(t, len(sres.Items), 2) be.Equal(t, len(sres.Items), 2)
testx.AssertEqual(t, sres.Items[0].String(), "m11") be.Equal(t, sres.Items[0].String(), "m11")
testx.AssertEqual(t, sres.Items[1].String(), "m12") be.Equal(t, sres.Items[1].String(), "m12")
testx.AssertEqual(t, conn.Out(), "2,2,2,m11,m12") wantOut := fmt.Sprintf("2,%d,2,m11,m12", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
// page 2 // page 2
cmd := redis.MustParse(ParseSScan, "sscan key 2 match * count 2") next := fmt.Sprintf("sscan key %d match * count 2", cursor)
cmd := redis.MustParse(ParseSScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rset.ScanResult) sres := res.(rset.ScanResult)
testx.AssertEqual(t, sres.Cursor, 4) be.True(t, sres.Cursor > cursor)
testx.AssertEqual(t, len(sres.Items), 2) be.Equal(t, len(sres.Items), 2)
testx.AssertEqual(t, sres.Items[0].String(), "m21") be.Equal(t, sres.Items[0].String(), "m21")
testx.AssertEqual(t, sres.Items[1].String(), "m22") be.Equal(t, sres.Items[1].String(), "m22")
testx.AssertEqual(t, conn.Out(), "2,4,2,m21,m22") wantOut := fmt.Sprintf("2,%d,2,m21,m22", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
// page 3 // page 3
cmd := redis.MustParse(ParseSScan, "sscan key 4 match * count 2") next := fmt.Sprintf("sscan key %d match * count 2", cursor)
cmd := redis.MustParse(ParseSScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rset.ScanResult) sres := res.(rset.ScanResult)
testx.AssertEqual(t, sres.Cursor, 5) be.True(t, sres.Cursor > cursor)
testx.AssertEqual(t, len(sres.Items), 1) be.Equal(t, len(sres.Items), 1)
testx.AssertEqual(t, sres.Items[0].String(), "m31") be.Equal(t, sres.Items[0].String(), "m31")
testx.AssertEqual(t, conn.Out(), "2,5,1,m31") wantOut := fmt.Sprintf("2,%d,1,m31", sres.Cursor)
be.Equal(t, conn.Out(), wantOut)
cursor = sres.Cursor
} }
{ {
// no more pages // no more pages
cmd := redis.MustParse(ParseSScan, "sscan key 5 match * count 2") next := fmt.Sprintf("sscan key %d match * count 2", cursor)
cmd := redis.MustParse(ParseSScan, next)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
sres := res.(rset.ScanResult) sres := res.(rset.ScanResult)
testx.AssertEqual(t, sres.Cursor, 0) be.Equal(t, sres.Cursor, 0)
testx.AssertEqual(t, len(sres.Items), 0) be.Equal(t, len(sres.Items), 0)
testx.AssertEqual(t, conn.Out(), "2,0,0") be.Equal(t, conn.Out(), "2,0,0")
} }
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSUnionParse(t *testing.T) { func TestSUnionParse(t *testing.T) {
@@ -34,11 +34,11 @@ func TestSUnionParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSUnion, test.cmd) cmd, err := redis.Parse(ParseSUnion, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.keys, test.want.keys) be.Equal(t, cmd.keys, test.want.keys)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -46,78 +46,72 @@ func TestSUnionParse(t *testing.T) {
func TestSUnionExec(t *testing.T) { func TestSUnionExec(t *testing.T) {
t.Run("non-empty", func(t *testing.T) { t.Run("non-empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two")
_, _ = db.Set().Add("key1", "one", "two") _, _ = red.Set().Add("key2", "two", "thr")
_, _ = db.Set().Add("key2", "two", "thr") _, _ = red.Set().Add("key3", "thr", "fou")
_, _ = db.Set().Add("key3", "thr", "fou")
cmd := redis.MustParse(ParseSUnion, "sunion key1 key2 key3") cmd := redis.MustParse(ParseSUnion, "sunion key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 4) be.Equal(t, len(res.([]core.Value)), 4)
testx.AssertEqual(t, conn.Out(), "4,fou,one,thr,two") be.Equal(t, conn.Out(), "4,fou,one,thr,two")
}) })
t.Run("no keys", func(t *testing.T) { t.Run("no keys", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSUnion, "sunion key1") cmd := redis.MustParse(ParseSUnion, "sunion key1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("single key", func(t *testing.T) { t.Run("single key", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two", "thr")
_, _ = db.Set().Add("key1", "one", "two", "thr")
cmd := redis.MustParse(ParseSUnion, "sunion key1") cmd := redis.MustParse(ParseSUnion, "sunion key1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 3) be.Equal(t, len(res.([]core.Value)), 3)
testx.AssertEqual(t, conn.Out(), "3,one,thr,two") be.Equal(t, conn.Out(), "3,one,thr,two")
}) })
t.Run("key not found", func(t *testing.T) { t.Run("key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "two")
_, _ = db.Set().Add("key2", "two")
cmd := redis.MustParse(ParseSUnion, "sunion key1 key2 key3") cmd := redis.MustParse(ParseSUnion, "sunion key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 2) be.Equal(t, len(res.([]core.Value)), 2)
testx.AssertEqual(t, conn.Out(), "2,one,two") be.Equal(t, conn.Out(), "2,one,two")
}) })
t.Run("all not found", func(t *testing.T) { t.Run("all not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseSUnion, "sunion key1 key2 key3") cmd := redis.MustParse(ParseSUnion, "sunion key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 0) be.Equal(t, len(res.([]core.Value)), 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
}) })
t.Run("key type mismatch", func(t *testing.T) { t.Run("key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _ = red.Str().Set("key2", "two")
_ = db.Str().Set("key2", "two") _, _ = red.Set().Add("key3", "thr")
_, _ = db.Set().Add("key3", "thr")
cmd := redis.MustParse(ParseSUnion, "sunion key1 key2 key3") cmd := redis.MustParse(ParseSUnion, "sunion key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, len(res.([]core.Value)), 2) be.Equal(t, len(res.([]core.Value)), 2)
testx.AssertEqual(t, conn.Out(), "2,one,thr") be.Equal(t, conn.Out(), "2,one,thr")
}) })
} }

View File

@@ -3,9 +3,9 @@ package set
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSUnionStoreParse(t *testing.T) { func TestSUnionStoreParse(t *testing.T) {
@@ -39,12 +39,12 @@ func TestSUnionStoreParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSUnionStore, test.cmd) cmd, err := redis.Parse(ParseSUnionStore, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.dest, test.want.dest) be.Equal(t, cmd.dest, test.want.dest)
testx.AssertEqual(t, cmd.keys, test.want.keys) be.Equal(t, cmd.keys, test.want.keys)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -52,123 +52,116 @@ func TestSUnionStoreParse(t *testing.T) {
func TestSUnionStoreExec(t *testing.T) { func TestSUnionStoreExec(t *testing.T) {
t.Run("store", func(t *testing.T) { t.Run("store", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two", "thr")
_, _ = db.Set().Add("key1", "one", "two", "thr") _, _ = red.Set().Add("key2", "two", "thr", "fou")
_, _ = db.Set().Add("key2", "two", "thr", "fou") _, _ = red.Set().Add("key3", "one", "two", "thr", "fou")
_, _ = db.Set().Add("key3", "one", "two", "thr", "fou")
cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2 key3") cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 4) be.Equal(t, res, 4)
testx.AssertEqual(t, conn.Out(), "4") be.Equal(t, conn.Out(), "4")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
sortValues(items) sortValues(items)
testx.AssertEqual(t, items, []core.Value{ be.Equal(t, items, []core.Value{
core.Value("fou"), core.Value("one"), core.Value("thr"), core.Value("two"), core.Value("fou"), core.Value("one"), core.Value("thr"), core.Value("two"),
}) })
}) })
t.Run("rewrite dest", func(t *testing.T) { t.Run("rewrite dest", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2") cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value{core.Value("one")}) be.Equal(t, items, []core.Value{core.Value("one")})
}) })
t.Run("single key", func(t *testing.T) { t.Run("single key", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one", "two")
_, _ = db.Set().Add("key1", "one", "two") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1") cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 2) be.Equal(t, res, 2)
testx.AssertEqual(t, conn.Out(), "2") be.Equal(t, conn.Out(), "2")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
sortValues(items) sortValues(items)
testx.AssertEqual(t, items, []core.Value{core.Value("one"), core.Value("two")}) be.Equal(t, items, []core.Value{core.Value("one"), core.Value("two")})
}) })
t.Run("empty", func(t *testing.T) { t.Run("empty", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2") cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 0) be.Equal(t, res, 0)
testx.AssertEqual(t, conn.Out(), "0") be.Equal(t, conn.Out(), "0")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value(nil)) be.Equal(t, items, []core.Value(nil))
}) })
t.Run("source key not found", func(t *testing.T) { t.Run("source key not found", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one") _, _ = red.Set().Add("dest", "old")
_, _ = db.Set().Add("dest", "old")
cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2 key3") cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value{core.Value("one")}) be.Equal(t, items, []core.Value{core.Value("one")})
}) })
t.Run("source key type mismatch", func(t *testing.T) { t.Run("source key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one") _ = red.Str().Set("key3", "one")
_ = db.Str().Set("key3", "one")
cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2 key3") cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2 key3")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
items, _ := db.Set().Items("dest") items, _ := red.Set().Items("dest")
testx.AssertEqual(t, items, []core.Value{core.Value("one")}) be.Equal(t, items, []core.Value{core.Value("one")})
}) })
t.Run("dest key type mismatch", func(t *testing.T) { t.Run("dest key type mismatch", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _, _ = red.Set().Add("key1", "one")
_, _ = db.Set().Add("key1", "one") _, _ = red.Set().Add("key2", "one")
_, _ = db.Set().Add("key2", "one") _ = red.Str().Set("dest", "old")
_ = db.Str().Set("dest", "old")
cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2") cmd := redis.MustParse(ParseSUnionStore, "sunionstore dest key1 key2")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertErr(t, err, core.ErrKeyType) be.Err(t, err, core.ErrKeyType)
testx.AssertEqual(t, res, nil) be.Equal(t, res, nil)
testx.AssertEqual(t, conn.Out(), core.ErrKeyType.Error()+" (sunionstore)") be.Equal(t, conn.Out(), core.ErrKeyType.Error()+" (sunionstore)")
sval, _ := db.Str().Get("dest") sval, _ := red.Str().Get("dest")
testx.AssertEqual(t, sval, core.Value("old")) be.Equal(t, sval, core.Value("old"))
}) })
} }

View File

@@ -3,8 +3,8 @@ package string
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestDecrParse(t *testing.T) { func TestDecrParse(t *testing.T) {
@@ -37,12 +37,12 @@ func TestDecrParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(parse, test.cmd) cmd, err := redis.Parse(parse, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.delta, test.want.delta) be.Equal(t, cmd.delta, test.want.delta)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -54,33 +54,31 @@ func TestDecrExec(t *testing.T) {
} }
t.Run("create", func(t *testing.T) { t.Run("create", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(parse, "decr age") cmd := redis.MustParse(parse, "decr age")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, -1) be.Equal(t, res, -1)
testx.AssertEqual(t, conn.Out(), "-1") be.Equal(t, conn.Out(), "-1")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.MustInt(), -1) be.Equal(t, age.MustInt(), -1)
}) })
t.Run("decr", func(t *testing.T) { t.Run("decr", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("age", "25")
_ = db.Str().Set("age", "25")
cmd := redis.MustParse(parse, "decr age") cmd := redis.MustParse(parse, "decr age")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 24) be.Equal(t, res, 24)
testx.AssertEqual(t, conn.Out(), "24") be.Equal(t, conn.Out(), "24")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.MustInt(), 24) be.Equal(t, age.MustInt(), 24)
}) })
} }

View File

@@ -3,8 +3,8 @@ package string
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestDecrByParse(t *testing.T) { func TestDecrByParse(t *testing.T) {
@@ -37,12 +37,12 @@ func TestDecrByParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(parse, test.cmd) cmd, err := redis.Parse(parse, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.delta, test.want.delta) be.Equal(t, cmd.delta, test.want.delta)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -54,33 +54,31 @@ func TestDecrByExec(t *testing.T) {
} }
t.Run("create", func(t *testing.T) { t.Run("create", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(parse, "decrby age 12") cmd := redis.MustParse(parse, "decrby age 12")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, -12) be.Equal(t, res, -12)
testx.AssertEqual(t, conn.Out(), "-12") be.Equal(t, conn.Out(), "-12")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.MustInt(), -12) be.Equal(t, age.MustInt(), -12)
}) })
t.Run("decrby", func(t *testing.T) { t.Run("decrby", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("age", "25")
_ = db.Str().Set("age", "25")
cmd := redis.MustParse(parse, "decrby age 12") cmd := redis.MustParse(parse, "decrby age 12")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 13) be.Equal(t, res, 13)
testx.AssertEqual(t, conn.Out(), "13") be.Equal(t, conn.Out(), "13")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.MustInt(), 13) be.Equal(t, age.MustInt(), 13)
}) })
} }

View File

@@ -3,9 +3,9 @@ package string
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestGetParse(t *testing.T) { func TestGetParse(t *testing.T) {
@@ -34,21 +34,19 @@ func TestGetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseGet, test.cmd) cmd, err := redis.Parse(ParseGet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want) be.Equal(t, cmd.key, test.want)
} else { } else {
testx.AssertEqual(t, cmd, Get{}) be.Equal(t, cmd, Get{})
} }
}) })
} }
} }
func TestGetExec(t *testing.T) { func TestGetExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
tests := []struct { tests := []struct {
cmd string cmd string
@@ -72,9 +70,9 @@ func TestGetExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseGet, test.cmd) cmd := redis.MustParse(ParseGet, test.cmd)
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.res) be.Equal(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
}) })
} }
} }

View File

@@ -3,9 +3,9 @@ package string
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestGetSetParse(t *testing.T) { func TestGetSetParse(t *testing.T) {
@@ -39,12 +39,12 @@ func TestGetSetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseGetSet, test.cmd) cmd, err := redis.Parse(ParseGetSet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.value, test.want.value) be.Equal(t, cmd.value, test.want.value)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -52,34 +52,31 @@ func TestGetSetParse(t *testing.T) {
func TestGetSetExec(t *testing.T) { func TestGetSetExec(t *testing.T) {
t.Run("create", func(t *testing.T) { t.Run("create", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseGetSet, "getset name alice") cmd := redis.MustParse(ParseGetSet, "getset name alice")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value(nil)) be.Equal(t, res.(core.Value), core.Value(nil))
testx.AssertEqual(t, conn.Out(), "(nil)") be.Equal(t, conn.Out(), "(nil)")
name, _ := db.Str().Get("name") name, _ := red.Str().Get("name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
}) })
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(ParseGetSet, "getset name bob") cmd := redis.MustParse(ParseGetSet, "getset name bob")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, core.Value("alice")) be.Equal(t, res.(core.Value), core.Value("alice"))
testx.AssertEqual(t, conn.Out(), "alice") be.Equal(t, conn.Out(), "alice")
name, _ := db.Str().Get("name") name, _ := red.Str().Get("name")
testx.AssertEqual(t, name.String(), "bob") be.Equal(t, name.String(), "bob")
}) })
} }

View File

@@ -3,8 +3,8 @@ package string
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestIncrParse(t *testing.T) { func TestIncrParse(t *testing.T) {
@@ -37,12 +37,12 @@ func TestIncrParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(parse, test.cmd) cmd, err := redis.Parse(parse, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.delta, test.want.delta) be.Equal(t, cmd.delta, test.want.delta)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -54,33 +54,31 @@ func TestIncrExec(t *testing.T) {
} }
t.Run("create", func(t *testing.T) { t.Run("create", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(parse, "incr age") cmd := redis.MustParse(parse, "incr age")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 1) be.Equal(t, res, 1)
testx.AssertEqual(t, conn.Out(), "1") be.Equal(t, conn.Out(), "1")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.MustInt(), 1) be.Equal(t, age.MustInt(), 1)
}) })
t.Run("incr", func(t *testing.T) { t.Run("incr", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("age", "25")
_ = db.Str().Set("age", "25")
cmd := redis.MustParse(parse, "incr age") cmd := redis.MustParse(parse, "incr age")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 26) be.Equal(t, res, 26)
testx.AssertEqual(t, conn.Out(), "26") be.Equal(t, conn.Out(), "26")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.MustInt(), 26) be.Equal(t, age.MustInt(), 26)
}) })
} }

View File

@@ -3,8 +3,8 @@ package string
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestIncrByParse(t *testing.T) { func TestIncrByParse(t *testing.T) {
@@ -37,12 +37,12 @@ func TestIncrByParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(parse, test.cmd) cmd, err := redis.Parse(parse, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.delta, test.want.delta) be.Equal(t, cmd.delta, test.want.delta)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -54,33 +54,31 @@ func TestIncrByExec(t *testing.T) {
} }
t.Run("create", func(t *testing.T) { t.Run("create", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(parse, "incrby age 42") cmd := redis.MustParse(parse, "incrby age 42")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 42) be.Equal(t, res, 42)
testx.AssertEqual(t, conn.Out(), "42") be.Equal(t, conn.Out(), "42")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.MustInt(), 42) be.Equal(t, age.MustInt(), 42)
}) })
t.Run("incrby", func(t *testing.T) { t.Run("incrby", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("age", "25")
_ = db.Str().Set("age", "25")
cmd := redis.MustParse(parse, "incrby age 42") cmd := redis.MustParse(parse, "incrby age 42")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, 67) be.Equal(t, res, 67)
testx.AssertEqual(t, conn.Out(), "67") be.Equal(t, conn.Out(), "67")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.MustInt(), 67) be.Equal(t, age.MustInt(), 67)
}) })
} }

View File

@@ -3,8 +3,8 @@ package string
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestIncrByFloatParse(t *testing.T) { func TestIncrByFloatParse(t *testing.T) {
@@ -43,20 +43,19 @@ func TestIncrByFloatParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseIncrByFloat, test.cmd) cmd, err := redis.Parse(ParseIncrByFloat, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.delta, test.want.delta) be.Equal(t, cmd.delta, test.want.delta)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
} }
func TestIncrByFloatExec(t *testing.T) { func TestIncrByFloatExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
tests := []struct { tests := []struct {
cmd string cmd string
@@ -87,15 +86,14 @@ func TestIncrByFloatExec(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
_ = db.Str().Set("age", 25) _ = red.Str().Set("age", 25)
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseIncrByFloat, test.cmd) cmd := redis.MustParse(ParseIncrByFloat, test.cmd)
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.res) be.Equal(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
}) })
} }
} }

View File

@@ -3,9 +3,9 @@ package string
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestMGetParse(t *testing.T) { func TestMGetParse(t *testing.T) {
@@ -34,22 +34,21 @@ func TestMGetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseMGet, test.cmd) cmd, err := redis.Parse(ParseMGet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.keys, test.want) be.Equal(t, cmd.keys, test.want)
} else { } else {
testx.AssertEqual(t, cmd, MGet{}) be.Equal(t, cmd, MGet{})
} }
}) })
} }
} }
func TestMGetExec(t *testing.T) { func TestMGetExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("name", "alice") _ = red.Str().Set("name", "alice")
_ = db.Str().Set("age", 25) _ = red.Str().Set("age", 25)
tests := []struct { tests := []struct {
cmd string cmd string
@@ -83,9 +82,9 @@ func TestMGetExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseMGet, test.cmd) cmd := redis.MustParse(ParseMGet, test.cmd)
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.res) be.Equal(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
}) })
} }
} }

View File

@@ -3,8 +3,8 @@ package string
import ( import (
"testing" "testing"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestMSetParse(t *testing.T) { func TestMSetParse(t *testing.T) {
@@ -46,11 +46,11 @@ func TestMSetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseMSet, test.cmd) cmd, err := redis.Parse(ParseMSet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.items, test.want.items) be.Equal(t, cmd.items, test.want.items)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -58,73 +58,69 @@ func TestMSetParse(t *testing.T) {
func TestMSetExec(t *testing.T) { func TestMSetExec(t *testing.T) {
t.Run("create single", func(t *testing.T) { t.Run("create single", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseMSet, "mset name alice") cmd := redis.MustParse(ParseMSet, "mset name alice")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
name, _ := db.Str().Get("name") name, _ := red.Str().Get("name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
}) })
t.Run("create multiple", func(t *testing.T) { t.Run("create multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(ParseMSet, "mset name alice age 25") cmd := redis.MustParse(ParseMSet, "mset name alice age 25")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
name, _ := db.Str().Get("name") name, _ := red.Str().Get("name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.String(), "25") be.Equal(t, age.String(), "25")
}) })
t.Run("create/update", func(t *testing.T) { t.Run("create/update", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("name", "alice") _ = red.Str().Set("name", "alice")
cmd := redis.MustParse(ParseMSet, "mset name bob age 50") cmd := redis.MustParse(ParseMSet, "mset name bob age 50")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
name, _ := db.Str().Get("name") name, _ := red.Str().Get("name")
testx.AssertEqual(t, name.String(), "bob") be.Equal(t, name.String(), "bob")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.String(), "50") be.Equal(t, age.String(), "50")
}) })
t.Run("update multiple", func(t *testing.T) { t.Run("update multiple", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
_ = db.Str().Set("name", "alice") _ = red.Str().Set("name", "alice")
_ = db.Str().Set("age", 25) _ = red.Str().Set("age", 25)
cmd := redis.MustParse(ParseMSet, "mset name bob age 50") cmd := redis.MustParse(ParseMSet, "mset name bob age 50")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
name, _ := db.Str().Get("name") name, _ := red.Str().Get("name")
testx.AssertEqual(t, name.String(), "bob") be.Equal(t, name.String(), "bob")
age, _ := db.Str().Get("age") age, _ := red.Str().Get("age")
testx.AssertEqual(t, age.String(), "50") be.Equal(t, age.String(), "50")
}) })
} }

View File

@@ -4,8 +4,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestPSetEXParse(t *testing.T) { func TestPSetEXParse(t *testing.T) {
@@ -48,13 +48,13 @@ func TestPSetEXParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(parse, test.cmd) cmd, err := redis.Parse(parse, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.value, test.want.value) be.Equal(t, cmd.value, test.want.value)
testx.AssertEqual(t, cmd.ttl, test.want.ttl) be.Equal(t, cmd.ttl, test.want.ttl)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
@@ -66,64 +66,59 @@ func TestPSetEXExec(t *testing.T) {
} }
t.Run("create", func(t *testing.T) { t.Run("create", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
cmd := redis.MustParse(parse, "psetex name 60000 alice") cmd := redis.MustParse(parse, "psetex name 60000 alice")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
expireAt := time.Now().Add(60 * time.Second) expireAt := time.Now().Add(60 * time.Second)
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, *key.ETime/1000, expireAt.UnixMilli()/1000) be.Equal(t, *key.ETime/1000, expireAt.UnixMilli()/1000)
name, _ := db.Str().Get("name") name, _ := red.Str().Get("name")
testx.AssertEqual(t, name.String(), "alice") be.Equal(t, name.String(), "alice")
}) })
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().Set("name", "alice")
_ = db.Str().Set("name", "alice")
cmd := redis.MustParse(parse, "psetex name 60000 bob") cmd := redis.MustParse(parse, "psetex name 60000 bob")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
expireAt := time.Now().Add(60 * time.Second) expireAt := time.Now().Add(60 * time.Second)
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, *key.ETime/1000, expireAt.UnixMilli()/1000) be.Equal(t, *key.ETime/1000, expireAt.UnixMilli()/1000)
name, _ := db.Str().Get("name") name, _ := red.Str().Get("name")
testx.AssertEqual(t, name.String(), "bob") be.Equal(t, name.String(), "bob")
}) })
t.Run("change ttl", func(t *testing.T) { t.Run("change ttl", func(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close() _ = red.Str().SetExpires("name", "alice", 60*time.Second)
_ = db.Str().SetExpires("name", "alice", 60*time.Second)
cmd := redis.MustParse(parse, "psetex name 10000 bob") cmd := redis.MustParse(parse, "psetex name 10000 bob")
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, true) be.Equal(t, res, true)
testx.AssertEqual(t, conn.Out(), "OK") be.Equal(t, conn.Out(), "OK")
expireAt := time.Now().Add(10 * time.Second) expireAt := time.Now().Add(10 * time.Second)
key, _ := db.Key().Get("name") key, _ := red.Key().Get("name")
testx.AssertEqual(t, *key.ETime/1000, expireAt.UnixMilli()/1000) be.Equal(t, *key.ETime/1000, expireAt.UnixMilli()/1000)
name, _ := db.Str().Get("name") name, _ := red.Str().Get("name")
testx.AssertEqual(t, name.String(), "bob") be.Equal(t, name.String(), "bob")
}) })
} }

View File

@@ -4,9 +4,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/nalgeon/be"
"github.com/nalgeon/redka/internal/core" "github.com/nalgeon/redka/internal/core"
"github.com/nalgeon/redka/internal/redis" "github.com/nalgeon/redka/internal/redis"
"github.com/nalgeon/redka/internal/testx"
) )
func TestSetParse(t *testing.T) { func TestSetParse(t *testing.T) {
@@ -123,23 +123,22 @@ func TestSetParse(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.cmd, func(t *testing.T) { t.Run(test.cmd, func(t *testing.T) {
cmd, err := redis.Parse(ParseSet, test.cmd) cmd, err := redis.Parse(ParseSet, test.cmd)
testx.AssertEqual(t, err, test.err) be.Equal(t, err, test.err)
if err == nil { if err == nil {
testx.AssertEqual(t, cmd.key, test.want.key) be.Equal(t, cmd.key, test.want.key)
testx.AssertEqual(t, cmd.value, test.want.value) be.Equal(t, cmd.value, test.want.value)
testx.AssertEqual(t, cmd.ifNX, test.want.ifNX) be.Equal(t, cmd.ifNX, test.want.ifNX)
testx.AssertEqual(t, cmd.ifXX, test.want.ifXX) be.Equal(t, cmd.ifXX, test.want.ifXX)
testx.AssertEqual(t, cmd.ttl, test.want.ttl) be.Equal(t, cmd.ttl, test.want.ttl)
} else { } else {
testx.AssertEqual(t, cmd, test.want) be.Equal(t, cmd, test.want)
} }
}) })
} }
} }
func TestSetExec(t *testing.T) { func TestSetExec(t *testing.T) {
db, red := getDB(t) red := getRedka(t)
defer db.Close()
tests := []struct { tests := []struct {
cmd string cmd string
@@ -203,9 +202,9 @@ func TestSetExec(t *testing.T) {
conn := redis.NewFakeConn() conn := redis.NewFakeConn()
cmd := redis.MustParse(ParseSet, test.cmd) cmd := redis.MustParse(ParseSet, test.cmd)
res, err := cmd.Run(conn, red) res, err := cmd.Run(conn, red)
testx.AssertNoErr(t, err) be.Err(t, err, nil)
testx.AssertEqual(t, res, test.res) be.Equal(t, res, test.res)
testx.AssertEqual(t, conn.Out(), test.out) be.Equal(t, conn.Out(), test.out)
}) })
} }
} }

Some files were not shown because too many files have changed in this diff Show More