package api import ( "net/http" "net/http/httptest" "reflect" "strconv" "strings" "testing" "time" "git.rosemyrtle.work/personal-finance/server/internal/dal" "git.rosemyrtle.work/personal-finance/server/internal/entity" "git.rosemyrtle.work/personal-finance/server/internal/mock" "github.com/google/uuid" "github.com/labstack/echo/v4" "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "go.uber.org/mock/gomock" ) func TestServerImpl_GetBanks(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mock_dal := mock.NewMockDAL(ctrl) type fields struct { Dal dal.DAL } tests := []struct { name string fields fields wantErr bool mocks entity.Banks }{ { "200", fields{mock_dal}, false, entity.Banks{ {Id: "Bank A", Name: "Bank A", NordigenId: uuid.New()}, {Id: "Bank B", Name: "Bank B", NordigenId: uuid.New()}, }, }, { "204", fields{mock_dal}, false, entity.Banks{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := &ServerImpl{ Dal: tt.fields.Dal, } req := httptest.NewRequest(http.MethodGet, "/banks", nil) rec := httptest.NewRecorder() ctx := echo.New().NewContext(req, rec) mock_dal.EXPECT().Banks().Return(tt.mocks, nil).Times(1) if err := s.GetBanks(ctx); (err != nil) != tt.wantErr { t.Errorf("ServerImpl.GetBanks() error = %v, wantErr %v", err, tt.wantErr) } }) } } func TestServerImpl_GetBankById(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mock_dal := mock.NewMockDAL(ctrl) type fields struct { Dal dal.DAL } type args struct { bankId string } tests := []struct { name string fields fields args args wantErr bool mocks *entity.Bank }{ { "200", fields{mock_dal}, args{"Bank A"}, false, &entity.Bank{Id: "Bank A", Name: "Bank a", NordigenId: uuid.New()}, }, { "404", fields{mock_dal}, args{"Bank B"}, false, nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := &ServerImpl{ Dal: tt.fields.Dal, } req := httptest.NewRequest(http.MethodGet, "/bank", nil) rec := httptest.NewRecorder() ctx := echo.New().NewContext(req, rec) mock_dal.EXPECT().Bank(tt.args.bankId).Return(tt.mocks, nil).Times(1) if err := s.GetBankById(ctx, tt.args.bankId); (err != nil) != tt.wantErr { t.Errorf("ServerImpl.GetBankById() error = %v, wantErr %v", err, tt.wantErr) } }) } } func TestServerImpl_GetTransactions(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mock_dal := mock.NewMockDAL(ctrl) type fields struct { Dal dal.DAL } type args struct { params GetTransactionsParams } tests := []struct { name string fields fields args args wantErr bool mocks entity.Transactions }{ { "200", fields{mock_dal}, args{GetTransactionsParams{}}, false, entity.Transactions{{Id: 1, Date: time.Now(), Description: "desc#1", Value: decimal.New(0, 0)}}, }, { "204", fields{mock_dal}, args{GetTransactionsParams{}}, false, entity.Transactions{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pf := &ServerImpl{ Dal: tt.fields.Dal, } req := httptest.NewRequest(http.MethodGet, "/transactions", nil) rec := httptest.NewRecorder() ctx := echo.New().NewContext(req, rec) mock_dal.EXPECT().Transactions().Return(tt.mocks, nil).Times(1) if err := pf.GetTransactions(ctx, tt.args.params); (err != nil) != tt.wantErr { t.Errorf("ServerImpl.GetTransactions() error = %v,", err) } code, _ := strconv.Atoi(tt.name) assert.Equal(t, code, rec.Code) }) } } func TestServerImpl_GetTransactionById(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mock_dal := mock.NewMockDAL(ctrl) type fields struct { Dal dal.DAL } type args struct { transactionId int64 } tests := []struct { name string fields fields args args wantErr bool mocks *entity.Transaction }{ { "200", fields{mock_dal}, args{1}, false, &entity.Transaction{Id: 1, Date: time.Now(), Description: "desc#1", Value: decimal.New(0, 0)}, }, { "404", fields{mock_dal}, args{2}, false, nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := &ServerImpl{ Dal: tt.fields.Dal, } req := httptest.NewRequest(http.MethodGet, "/transaction", nil) rec := httptest.NewRecorder() ctx := echo.New().NewContext(req, rec) mock_dal.EXPECT().Transaction(tt.args.transactionId).Return(tt.mocks, nil).Times(1) if err := s.GetTransactionById(ctx, tt.args.transactionId); (err != nil) != tt.wantErr { t.Errorf("ServerImpl.GetTransactionById() error = %v, wantErr %v", err, tt.wantErr) } }) } } func TestServerImpl_CreateTransaction(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mock_dal := mock.NewMockDAL(ctrl) date, _ := time.Parse(time.DateOnly, "1974-04-25") type fields struct { Dal dal.DAL } type args struct { request string } type want struct { entity entity.Transaction response string } tests := []struct { name string fields fields args args want want wantErr bool }{ { "201", fields{mock_dal}, args{`{"date": "1974-04-25", "description": "freedom", "value": 9000}`}, want{ entity.Transaction{Id: 1, Date: date, Description: "freedom", Value: decimal.New(9000, 0)}, `{"date":"1974-04-25","description":"freedom","id":1,"value":9000}`, }, false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := &ServerImpl{Dal: tt.fields.Dal} req := httptest.NewRequest(http.MethodPost, "/transactions", strings.NewReader(tt.args.request)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) rec := httptest.NewRecorder() e := echo.New() ctx := e.NewContext(req, rec) inserted := tt.want.entity inserted.Id = entity.InvalidId mock_dal.EXPECT().InsertTransaction(gomock.AssignableToTypeOf(reflect.TypeOf(tt.want.entity))).Return(tt.want.entity, nil).Times(1) if err := s.CreateTransaction(ctx); (err != nil) != tt.wantErr { t.Errorf("ServerImpl.GetTransactionById() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(strings.TrimSpace(rec.Body.String()), tt.want.response) { t.Errorf("DalImpl.InsertTransaction() = %v, want %v", rec.Body.String(), tt.want.response) } }) } } func TestServerImpl_UpdateTransaction(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() date, _ := time.Parse(time.DateOnly, "1974-04-25") m := mock.NewMockDAL(ctrl) e := m.EXPECT() type fields struct { fn func(any) *gomock.Call args any returns any err error } type args struct { request string transactionId int64 } type want struct { status int body string } tests := []struct { name string fields []fields args args want want wantErr bool }{ { "UpdateExisting", []fields{ {e.TransactionExists, gomock.Any(), true, nil}, {e.UpdateTransaction, gomock.Any(), entity.Transaction{Id: 1, Date: date, Description: "freedom", Value: decimal.New(9000, 0)}, nil}, }, args{`{"date":"1974-04-25","description":"freedom","value":9000}`, 1}, want{200, `{"date":"1974-04-25","description":"freedom","id":1,"value":9000}`}, false, }, { "NotExisting", []fields{ {e.TransactionExists, gomock.Any(), false, nil}, }, args{`{"date":"1974-04-25","description":"freedom","id":1,"value":9000}`, 1}, want{404, ""}, false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := &ServerImpl{ Dal: m, } for _, expect := range tt.fields { expect.fn(expect.args).Return(expect.returns, expect.err) } rec := httptest.NewRecorder() req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(tt.args.request)) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) ctx := echo.New().NewContext(req, rec) if err := server.UpdateTransaction(ctx, tt.args.transactionId); (err != nil) != tt.wantErr { t.Errorf("ServerImpl.UpdateTransaction() error = %v, wantErr %v", err, tt.wantErr) } if got := rec.Code; !reflect.DeepEqual(got, tt.want.status) { t.Errorf("ServerImpl.UpdateTransaction() = %v, want %v", got, tt.name) } if got := strings.TrimSpace(rec.Body.String()); !reflect.DeepEqual(got, tt.want.body) { t.Errorf("ServerImpl.UpdateTransaction() = %v, want %v", got, tt.want) } }) } }