Files
xdrop/apps/api/internal/repo/test_helpers_test.go
T

206 lines
4.4 KiB
Go

package repo
import (
"context"
"fmt"
"io/fs"
"reflect"
"github.com/xdrop/monorepo/internal/models"
)
type stubMigrationFiles struct {
readDirFn func(name string) ([]fs.DirEntry, error)
readFileFn func(name string) ([]byte, error)
}
func (f stubMigrationFiles) ReadDir(name string) ([]fs.DirEntry, error) {
if f.readDirFn != nil {
return f.readDirFn(name)
}
return nil, nil
}
func (f stubMigrationFiles) ReadFile(name string) ([]byte, error) {
if f.readFileFn != nil {
return f.readFileFn(name)
}
return nil, nil
}
type stubPostgresDB struct {
beginFn func(ctx context.Context) (postgresTx, error)
execFn func(ctx context.Context, sql string, args ...any) error
queryFn func(ctx context.Context, sql string, args ...any) (postgresRows, error)
queryRowFn func(ctx context.Context, sql string, args ...any) postgresRow
}
func (db stubPostgresDB) Begin(ctx context.Context) (postgresTx, error) {
if db.beginFn != nil {
return db.beginFn(ctx)
}
return &stubPostgresTx{}, nil
}
func (db stubPostgresDB) Exec(ctx context.Context, sql string, args ...any) error {
if db.execFn != nil {
return db.execFn(ctx, sql, args...)
}
return nil
}
func (db stubPostgresDB) Query(ctx context.Context, sql string, args ...any) (postgresRows, error) {
if db.queryFn != nil {
return db.queryFn(ctx, sql, args...)
}
return &stubRows{}, nil
}
func (db stubPostgresDB) QueryRow(ctx context.Context, sql string, args ...any) postgresRow {
if db.queryRowFn != nil {
return db.queryRowFn(ctx, sql, args...)
}
return stubRow{}
}
type stubPostgresTx struct {
commitCalled bool
commitErr error
execFn func(ctx context.Context, sql string, args ...any) error
queryRowFn func(ctx context.Context, sql string, args ...any) postgresRow
rollbackCalled bool
rollbackErr error
}
func (tx *stubPostgresTx) Commit(context.Context) error {
tx.commitCalled = true
return tx.commitErr
}
func (tx *stubPostgresTx) Exec(ctx context.Context, sql string, args ...any) error {
if tx.execFn != nil {
return tx.execFn(ctx, sql, args...)
}
return nil
}
func (tx *stubPostgresTx) QueryRow(ctx context.Context, sql string, args ...any) postgresRow {
if tx.queryRowFn != nil {
return tx.queryRowFn(ctx, sql, args...)
}
return stubRow{}
}
func (tx *stubPostgresTx) Rollback(context.Context) error {
tx.rollbackCalled = true
return tx.rollbackErr
}
type stubRow struct {
err error
values []any
}
func (r stubRow) Scan(dest ...any) error {
if r.err != nil {
return r.err
}
return assignScanValues(dest, r.values)
}
type stubRows struct {
closed bool
err error
index int
scanErr error
scanErrAt int
values [][]any
}
func (r *stubRows) Close() {
r.closed = true
}
func (r *stubRows) Err() error {
return r.err
}
func (r *stubRows) Next() bool {
if r.index >= len(r.values) {
return false
}
r.index++
return true
}
func (r *stubRows) Scan(dest ...any) error {
if r.scanErr != nil && r.index == r.scanErrAt {
return r.scanErr
}
return assignScanValues(dest, r.values[r.index-1])
}
func assignScanValues(dest []any, values []any) error {
if len(dest) != len(values) {
return fmt.Errorf("scan value count mismatch: %d != %d", len(dest), len(values))
}
for i := range dest {
target := reflect.ValueOf(dest[i])
if !target.IsValid() || target.Kind() != reflect.Pointer || target.IsNil() {
return fmt.Errorf("scan target %d is not a pointer", i)
}
elem := target.Elem()
if values[i] == nil {
elem.Set(reflect.Zero(elem.Type()))
continue
}
value := reflect.ValueOf(values[i])
switch {
case value.Type().AssignableTo(elem.Type()):
elem.Set(value)
case value.Type().ConvertibleTo(elem.Type()):
elem.Set(value.Convert(elem.Type()))
default:
return fmt.Errorf("cannot assign %s to %s", value.Type(), elem.Type())
}
}
return nil
}
func transferScanValues(transfer models.Transfer) []any {
return []any{
transfer.ID,
transfer.Status,
transfer.WrappedRootKey,
transfer.ManifestObjectKey,
transfer.ManifestCiphertextSize,
transfer.TotalFiles,
transfer.TotalCiphertextBytes,
transfer.ExpiresAt,
transfer.CreatedAt,
transfer.UpdatedAt,
transfer.FinalizedAt,
transfer.ManageTokenHash,
transfer.DeletedAt,
transfer.PurgedAt,
}
}
func fileScanValues(file models.TransferFile) []any {
return []any{
file.TransferID,
file.OpaqueFileID,
file.TotalChunks,
file.CiphertextBytes,
file.PlaintextBytes,
file.ChunkSize,
file.UploadStatus,
file.CreatedAt,
file.UpdatedAt,
}
}