package handler import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) // MockAuthService implements service.AuthService type MockAuthService struct { mock.Mock } func (m *MockAuthService) OtpRequest(ctx context.Context, phoneNumber string) error { args := m.Called(ctx, phoneNumber) return args.Error(0) } func (m *MockAuthService) OtpVerify(ctx context.Context, phoneNumber, code string, loginChallenge string) (string, error) { args := m.Called(ctx, phoneNumber, code, loginChallenge) return args.String(0), args.Error(1) } func (m *MockAuthService) AcceptConsent(ctx context.Context, phoneNumber string, challenge string) (string, error) { args := m.Called(ctx, phoneNumber, challenge) return args.String(0), args.Error(1) } func TestNewAuthHandler(t *testing.T) { mockService := &MockAuthService{} handler := NewAuthHandler(mockService) assert.NotNil(t, handler) assert.Equal(t, mockService, handler.service) assert.Implements(t, (*StrictServerInterface)(nil), handler) } func TestAuthHandler_PostAuthOtpRequest(t *testing.T) { tests := []struct { name string phoneNumber string setupMock func(*MockAuthService) expectedStatus int expectedOk bool expectedMsg string }{ { name: "successful otp request", phoneNumber: "+79161234567", setupMock: func(m *MockAuthService) { m.On("OtpRequest", mock.Anything, "+79161234567").Return(nil).Once() }, expectedStatus: 200, expectedOk: true, expectedMsg: "OTP request successful", }, { name: "service error", phoneNumber: "invalid", setupMock: func(m *MockAuthService) { m.On("OtpRequest", mock.Anything, "invalid").Return(assert.AnError).Once() }, expectedStatus: 400, expectedOk: false, expectedMsg: assert.AnError.Error(), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockService := &MockAuthService{} handler := &AuthHandler{service: mockService} ctx := context.Background() tt.setupMock(mockService) request := PostAuthOtpRequestRequestObject{ Body: &PostAuthOtpRequestJSONRequestBody{ PhoneNumber: tt.phoneNumber, }, } result, err := handler.PostAuthOtpRequest(ctx, request) assert.NoError(t, err) // Handler should not return errors, only response objects if tt.expectedStatus == 200 { response, ok := result.(PostAuthOtpRequest200JSONResponse) assert.True(t, ok) assert.Equal(t, tt.expectedOk, response.Ok) assert.Equal(t, tt.expectedMsg, response.Message) } else { response, ok := result.(PostAuthOtpRequest400JSONResponse) assert.True(t, ok) assert.Equal(t, tt.expectedOk, response.Ok) assert.Equal(t, tt.expectedMsg, response.Message) } mockService.AssertExpectations(t) }) } } func TestAuthHandler_PostAuthOtpVerify(t *testing.T) { tests := []struct { name string phoneNumber string otp string loginChallenge string setupMock func(*MockAuthService) expectedStatus int expectedOk bool expectedMsg string expectedRedirect string }{ { name: "successful otp verification", phoneNumber: "+79161234567", otp: "123456", loginChallenge: "challenge123", setupMock: func(m *MockAuthService) { m.On("OtpVerify", mock.Anything, "+79161234567", "123456", "challenge123"). Return("https://example.com/callback", nil).Once() }, expectedStatus: 200, expectedOk: true, expectedMsg: "OTP verification successful", expectedRedirect: "https://example.com/callback", }, { name: "service error", phoneNumber: "+79161234567", otp: "wrong", loginChallenge: "challenge123", setupMock: func(m *MockAuthService) { m.On("OtpVerify", mock.Anything, "+79161234567", "wrong", "challenge123"). Return("", assert.AnError).Once() }, expectedStatus: 400, expectedOk: false, expectedMsg: assert.AnError.Error(), expectedRedirect: "", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockService := &MockAuthService{} handler := &AuthHandler{service: mockService} ctx := context.Background() tt.setupMock(mockService) request := PostAuthOtpVerifyRequestObject{ Body: &PostAuthOtpVerifyJSONRequestBody{ PhoneNumber: tt.phoneNumber, Otp: tt.otp, LoginChallenge: tt.loginChallenge, }, } result, err := handler.PostAuthOtpVerify(ctx, request) assert.NoError(t, err) if tt.expectedStatus == 200 { response, ok := result.(PostAuthOtpVerify200JSONResponse) assert.True(t, ok) assert.Equal(t, tt.expectedOk, response.Ok) assert.Equal(t, tt.expectedMsg, response.Message) assert.Equal(t, tt.expectedRedirect, response.RedirectUrl) } else { response, ok := result.(PostAuthOtpVerify400JSONResponse) assert.True(t, ok) assert.Equal(t, tt.expectedOk, response.Ok) assert.Equal(t, tt.expectedMsg, response.Message) assert.Equal(t, tt.expectedRedirect, response.RedirectUrl) } mockService.AssertExpectations(t) }) } } func TestAuthHandler_PostAuthConsentAccept(t *testing.T) { tests := []struct { name string phoneNumber string consentChallenge string setupMock func(*MockAuthService) expectedStatus int expectedOk bool expectedMsg string expectedRedirect string }{ { name: "successful consent accept", phoneNumber: "+79161234567", consentChallenge: "consent123", setupMock: func(m *MockAuthService) { m.On("AcceptConsent", mock.Anything, "+79161234567", "consent123"). Return("https://example.com/callback", nil).Once() }, expectedStatus: 200, expectedOk: true, expectedMsg: "Consent accepted successfully", expectedRedirect: "https://example.com/callback", }, { name: "service error", phoneNumber: "+79161234567", consentChallenge: "invalid", setupMock: func(m *MockAuthService) { m.On("AcceptConsent", mock.Anything, "+79161234567", "invalid"). Return("", assert.AnError).Once() }, expectedStatus: 400, expectedOk: false, expectedMsg: assert.AnError.Error(), expectedRedirect: "", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockService := &MockAuthService{} handler := &AuthHandler{service: mockService} ctx := context.Background() tt.setupMock(mockService) request := PostAuthConsentAcceptRequestObject{ Body: &PostAuthConsentAcceptJSONRequestBody{ PhoneNumber: tt.phoneNumber, ConsentChallenge: tt.consentChallenge, }, } result, err := handler.PostAuthConsentAccept(ctx, request) assert.NoError(t, err) if tt.expectedStatus == 200 { response, ok := result.(PostAuthConsentAccept200JSONResponse) assert.True(t, ok) assert.Equal(t, tt.expectedOk, response.Ok) assert.Equal(t, tt.expectedMsg, response.Message) assert.Equal(t, tt.expectedRedirect, response.RedirectUrl) } else { response, ok := result.(PostAuthConsentAccept400JSONResponse) assert.True(t, ok) assert.Equal(t, tt.expectedOk, response.Ok) assert.Equal(t, tt.expectedMsg, response.Message) assert.Equal(t, tt.expectedRedirect, response.RedirectUrl) } mockService.AssertExpectations(t) }) } } func TestAuthHandler_EdgeCases(t *testing.T) { t.Run("nil request body should not panic", func(t *testing.T) { mockService := &MockAuthService{} handler := &AuthHandler{service: mockService} ctx := context.Background() // Test with nil body - this should be handled by the generated code // but we test that our handler doesn't panic defer func() { if r := recover(); r != nil { t.Errorf("Handler panicked with nil body: %v", r) } }() request := PostAuthOtpRequestRequestObject{ Body: &PostAuthOtpRequestJSONRequestBody{ PhoneNumber: "", }, } mockService.On("OtpRequest", mock.Anything, "").Return(assert.AnError).Once() result, err := handler.PostAuthOtpRequest(ctx, request) assert.NoError(t, err) assert.NotNil(t, result) mockService.AssertExpectations(t) }) }