547 lines
12 KiB
Go
547 lines
12 KiB
Go
package dal
|
|
|
|
import (
|
|
"database/sql"
|
|
"database/sql/driver"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.rosemyrtle.work/personal-finance/server/internal/entity"
|
|
"git.rosemyrtle.work/personal-finance/server/internal/golang"
|
|
"github.com/DATA-DOG/go-sqlmock"
|
|
"github.com/google/uuid"
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
func TestDalImpl_Transaction(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
date := time.Now()
|
|
|
|
type fields struct {
|
|
Db *sql.DB
|
|
}
|
|
type args struct {
|
|
transactionId int64
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
mocks [][]driver.Value
|
|
want *entity.Transaction
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"SelectTransaction",
|
|
fields{db},
|
|
args{1},
|
|
[][]driver.Value{
|
|
{1, date, "income", 1000, nil},
|
|
},
|
|
&entity.Transaction{Id: 1, Date: date, Description: "income", Value: decimal.NewFromInt(1000)},
|
|
false,
|
|
},
|
|
{
|
|
"SelectTransactionWithCategory",
|
|
fields{db},
|
|
args{1},
|
|
[][]driver.Value{
|
|
{1, date, "income", 1000, "C1"},
|
|
},
|
|
&entity.Transaction{Id: 1, Date: date, Description: "income", Value: decimal.NewFromInt(1000), Category: golang.Ptr("C1")},
|
|
false,
|
|
},
|
|
{
|
|
"SelectNoTransaction", fields{db}, args{2}, nil, nil, false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := &DalImpl{
|
|
Db: tt.fields.Db,
|
|
}
|
|
|
|
mock.
|
|
ExpectQuery(`
|
|
^SELECT \w+\.id, \w+\.date, \w+\.description, \w+\.amount, \w+\.name
|
|
FROM \w+\.transactions \w+
|
|
LEFT JOIN \w+\.transactions_categorized \w+
|
|
ON \w+\.id = \w+\.id
|
|
WHERE \w+\.id = \$1$`).
|
|
WithArgs(tt.args.transactionId).
|
|
WillReturnRows(
|
|
mock.NewRows([]string{"id", "date", "description", "amount", "category"}).AddRows(tt.mocks...),
|
|
)
|
|
|
|
got, err := d.Transaction(tt.args.transactionId)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("DalImpl.Transaction() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("DalImpl.Transaction() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDalImpl_Transactions(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
date := time.Now()
|
|
|
|
type fields struct {
|
|
Db *sql.DB
|
|
}
|
|
type args struct {
|
|
limit, offset int
|
|
category *string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
mocks [][]driver.Value
|
|
want entity.Transactions
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"SelectTransactions",
|
|
fields{db},
|
|
args{limit: 30, offset: 0, category: nil},
|
|
[][]driver.Value{
|
|
{1, date, "income", 1000, nil},
|
|
{2, date, "expense", -10.50, nil},
|
|
},
|
|
entity.Transactions{
|
|
{Id: 1, Date: date, Description: "income", Value: decimal.NewFromInt(1000)},
|
|
{Id: 2, Date: date, Description: "expense", Value: decimal.NewFromFloat(-10.50)},
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"SelectTransactionsWithCategory",
|
|
fields{db},
|
|
args{limit: 30, offset: 0, category: golang.Ptr("C1")},
|
|
[][]driver.Value{
|
|
{1, date, "income", 1000, "C1"},
|
|
{2, date, "expense", -10.50, nil},
|
|
},
|
|
entity.Transactions{
|
|
{Id: 1, Date: date, Description: "income", Value: decimal.NewFromInt(1000), Category: golang.Ptr("C1")},
|
|
{Id: 2, Date: date, Description: "expense", Value: decimal.NewFromFloat(-10.50)},
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"SelectNoTransactions", fields{db}, args{limit: 30, offset: 0, category: nil}, nil, nil, false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
dal := &DalImpl{
|
|
Db: tt.fields.Db,
|
|
}
|
|
|
|
args := []driver.Value{tt.args.limit, tt.args.offset}
|
|
stmt := `
|
|
^SELECT \w+\.id, \w+\.date, \w+\.description, \w+\.amount, \w+\.name
|
|
FROM \w+\.transactions \w+
|
|
LEFT JOIN \w+\.transactions_categorized \w+
|
|
ON \w+\.id = \w+\.id
|
|
`
|
|
if tt.args.category != nil {
|
|
stmt += `WHERE \w+\.name SIMILAR TO '%' || \$3 || '%'`
|
|
args = append(args, *tt.args.category)
|
|
}
|
|
stmt += `
|
|
ORDER BY \w+\.date DESC
|
|
LIMIT \$1
|
|
OFFSET \$2
|
|
`
|
|
|
|
mock.
|
|
ExpectQuery(stmt).
|
|
WithArgs(args...).
|
|
WillReturnRows(
|
|
mock.NewRows([]string{"id", "date", "description", "amount", "category"}).AddRows(tt.mocks...),
|
|
)
|
|
|
|
got, err := dal.Transactions(tt.args.limit, tt.args.offset, tt.args.category)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("DalImpl.Transactions() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("DalImpl.Transactions() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDalImpl_Bank(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
uuid := uuid.New()
|
|
|
|
type fields struct {
|
|
Db *sql.DB
|
|
}
|
|
type args struct {
|
|
bankId string
|
|
rows [][]driver.Value
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want *entity.Bank
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"200",
|
|
fields{db},
|
|
args{
|
|
"Bank A",
|
|
[][]driver.Value{
|
|
{"Bank A", "Bank A", uuid.String()},
|
|
}},
|
|
&entity.Bank{Id: "Bank A", Name: "Bank A", NordigenId: uuid},
|
|
false,
|
|
},
|
|
{"404", fields{db}, args{"Bank B", nil}, nil, false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := &DalImpl{
|
|
Db: tt.fields.Db,
|
|
}
|
|
|
|
mock.
|
|
ExpectQuery("^SELECT .* FROM .*banks b JOIN .*banks_nordigen n ON b.name = n.name WHERE b.name = \\$1$").
|
|
WithArgs(tt.args.bankId).
|
|
WillReturnRows(
|
|
mock.
|
|
NewRows([]string{"name", "name", "requisition_id"}).
|
|
AddRows(tt.args.rows...),
|
|
)
|
|
|
|
got, err := d.Bank(tt.args.bankId)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("DalImpl.Bank() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("DalImpl.Bank() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDalImpl_Banks(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
uuid := uuid.New()
|
|
|
|
type fields struct {
|
|
Db *sql.DB
|
|
}
|
|
type args struct {
|
|
rows [][]driver.Value
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want entity.Banks
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"200",
|
|
fields{db},
|
|
args{[][]driver.Value{
|
|
{"Bank A", "Bank A", uuid.String()},
|
|
{"Bank B", "Bank B", uuid.String()},
|
|
}},
|
|
entity.Banks{
|
|
{Id: "Bank A", Name: "Bank A", NordigenId: uuid},
|
|
{Id: "Bank B", Name: "Bank B", NordigenId: uuid},
|
|
},
|
|
false,
|
|
},
|
|
{"204", fields{db}, args{}, nil, false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
d := &DalImpl{
|
|
Db: tt.fields.Db,
|
|
}
|
|
|
|
mock.
|
|
ExpectQuery("^SELECT .* FROM .*banks b JOIN .*banks_nordigen n ON b.name = n.name$").
|
|
WithoutArgs().
|
|
WillReturnRows(
|
|
mock.
|
|
NewRows([]string{"name", "name", "requisition_id"}).
|
|
AddRows(tt.args.rows...),
|
|
)
|
|
|
|
got, err := d.Banks()
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("DalImpl.Banks() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("DalImpl.Banks() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDalImpl_InsertTransaction(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
date := time.Now()
|
|
|
|
type fields struct {
|
|
Db *sql.DB
|
|
}
|
|
type args struct {
|
|
t entity.Transaction
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want entity.Transaction
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"201",
|
|
fields{db},
|
|
args{entity.Transaction{Id: entity.InvalidId, Date: date, Description: "freedom", Value: decimal.NewFromInt(9000)}},
|
|
entity.Transaction{Id: 1, Date: date, Description: "freedom", Value: decimal.NewFromInt(9000)},
|
|
false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
dal := &DalImpl{
|
|
Db: tt.fields.Db,
|
|
}
|
|
|
|
mock.
|
|
ExpectQuery(`
|
|
INSERT INTO .* \(date, description, amount\)
|
|
VALUES \(\$1, \$2, \$3\)
|
|
RETURNING id`).
|
|
WithArgs(tt.args.t.Date, tt.args.t.Description, tt.args.t.Value).
|
|
WillReturnRows(
|
|
mock.NewRows([]string{"id"}).
|
|
AddRows([]driver.Value{tt.want.Id}),
|
|
)
|
|
|
|
got, err := dal.InsertTransaction(tt.args.t)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("DalImpl.InsertTransaction() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("DalImpl.InsertTransaction() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDalImpl_UpdateTransaction(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
type fields struct {
|
|
Db *sql.DB
|
|
}
|
|
type args struct {
|
|
id entity.TransactionId
|
|
category *entity.CategoryName
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
mocks driver.Result
|
|
want bool
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"SuccessfulUpdate",
|
|
fields{db},
|
|
args{id: entity.InvalidId, category: golang.Ptr("C1")},
|
|
sqlmock.NewResult(0, 1),
|
|
true,
|
|
false,
|
|
},
|
|
{
|
|
"UnsuccessfulUpdate",
|
|
fields{db},
|
|
args{id: entity.InvalidId, category: golang.Ptr("C1")},
|
|
sqlmock.NewResult(0, 0),
|
|
false,
|
|
true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
dal := &DalImpl{
|
|
Db: tt.fields.Db,
|
|
}
|
|
|
|
mock.
|
|
ExpectExec(`
|
|
UPDATE \w+\.transactions_categorized
|
|
SET name = \$2
|
|
WHERE id = \$1`).
|
|
WithArgs(tt.args.id, tt.args.category).
|
|
WillReturnResult(tt.mocks)
|
|
|
|
got, err := dal.UpdateTransaction(tt.args.id, tt.args.category)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("DalImpl.UpdateTransaction() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("DalImpl.UpdateTransaction() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDalImpl_TransactionExists(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
type fields struct {
|
|
Db *sql.DB
|
|
}
|
|
type args struct {
|
|
id uint64
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want bool
|
|
wantErr bool
|
|
}{
|
|
{"TransactionExists", fields{db}, args{1}, true, false},
|
|
{"TransactionNotExists", fields{db}, args{1}, false, false},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
dal := &DalImpl{
|
|
Db: tt.fields.Db,
|
|
}
|
|
|
|
mock.
|
|
ExpectQuery(`
|
|
SELECT EXISTS\(
|
|
SELECT 1
|
|
FROM pfbudget.transactions
|
|
WHERE id = \$1
|
|
\)`).
|
|
WithArgs(tt.args.id).
|
|
WillReturnRows(
|
|
mock.NewRows([]string{"exists"}).
|
|
AddRows([]driver.Value{tt.want}),
|
|
)
|
|
|
|
got, err := dal.TransactionExists(tt.args.id)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("DalImpl.TransactionExists() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("DalImpl.TransactionExists() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDalImpl_Categories(t *testing.T) {
|
|
db, mock, err := sqlmock.New()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
type fields struct {
|
|
Db *sql.DB
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
mocks [][]driver.Value
|
|
want entity.Categories
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"SelectCategories",
|
|
fields{db},
|
|
[][]driver.Value{{"C1", "G1"}},
|
|
entity.Categories{{Name: "C1", Group: golang.Ptr("G1")}},
|
|
false,
|
|
},
|
|
{
|
|
"SelectMutipleCategories",
|
|
fields{db},
|
|
[][]driver.Value{{"C1", "G1"}, {"C2", nil}},
|
|
entity.Categories{{Name: "C1", Group: golang.Ptr("G1")}, {Name: "C2"}},
|
|
false,
|
|
},
|
|
{
|
|
"SelectNoCategories",
|
|
fields{db},
|
|
[][]driver.Value{},
|
|
nil,
|
|
false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
dal := &DalImpl{
|
|
Db: tt.fields.Db,
|
|
}
|
|
|
|
mock.
|
|
ExpectQuery(`SELECT \w+\.name, \w+\.group FROM \w+.categories \w+`).
|
|
WithoutArgs().
|
|
WillReturnRows(mock.NewRows([]string{"name", "group"}).AddRows(tt.mocks...))
|
|
|
|
got, err := dal.Categories()
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("DalImpl.Categories() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("DalImpl.Categories() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|