package twilio import ( "context" "io" "net/http" "net/http/httptest" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" channelpkg "github.com/gochat/gochat/internal/channel" "github.com/gochat/gochat/internal/model" ) func TestNewWebhookHandler_Cov4(t *testing.T) { svc := NewTwilioService(nil) pipe := NewIncomingProcessor(svc) h := NewWebhookHandler(pipe, svc) assert.NotNil(t, h) } func TestWebhookHandler_HandleInboundSMS_Success_Cov4(t *testing.T) { svc := NewTwilioService(nil) pipe := NewIncomingProcessor(svc) h := NewWebhookHandler(pipe, svc) formData := "MessageSid=SM123&AccountSid=AC123&From=%2B1234567890&To=%2B1987654321&Body=Hello&NumMedia=0&SmsStatus=received" req := httptest.NewRequest("POST", "/webhook", strings.NewReader(formData)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") w := httptest.NewRecorder() inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1} h.HandleInboundSMS(w, req, inbox) assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Header().Get("Content-Type"), "xml") } func TestWebhookHandler_HandleInboundSMS_NoFrom_Cov4(t *testing.T) { svc := NewTwilioService(nil) pipe := NewIncomingProcessor(svc) h := NewWebhookHandler(pipe, svc) formData := "MessageSid=SM123&To=%2B1987654321&Body=Hello&NumMedia=0" req := httptest.NewRequest("POST", "/webhook", strings.NewReader(formData)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") w := httptest.NewRecorder() inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1} h.HandleInboundSMS(w, req, inbox) assert.Equal(t, http.StatusOK, w.Code) } func TestWebhookHandler_ProcessInboundSMS_WithMedia_Cov4(t *testing.T) { svc := NewTwilioService(nil) pipe := NewIncomingProcessor(svc) h := NewWebhookHandler(pipe, svc) formData := "MessageSid=SM456&From=%2B1234567890&To=%2B1987654321&Body=MMS&NumMedia=2&MediaUrl0=http://img1.jpg&MediaUrl1=http://img2.jpg&MediaContentType0=image/jpeg&MediaContentType1=image/png" req := httptest.NewRequest("POST", "/webhook", strings.NewReader(formData)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1} msg, err := h.ProcessInboundSMS(req, inbox) require.NoError(t, err) require.NotNil(t, msg) assert.Equal(t, "SM456", msg.SourceID) } func TestWebhookHandler_ProcessInboundSMS_InvalidNumMedia_Cov4(t *testing.T) { svc := NewTwilioService(nil) pipe := NewIncomingProcessor(svc) h := NewWebhookHandler(pipe, svc) formData := "MessageSid=SM789&From=%2B1234567890&To=%2B1987654321&Body=text&NumMedia=abc" req := httptest.NewRequest("POST", "/webhook", strings.NewReader(formData)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1} msg, err := h.ProcessInboundSMS(req, inbox) require.NoError(t, err) require.NotNil(t, msg) } func TestWebhookHandler_HandleDeliveryStatus_Delivered_Cov4(t *testing.T) { svc := NewTwilioService(nil) pipe := NewIncomingProcessor(svc) h := NewWebhookHandler(pipe, svc) formData := "MessageSid=SM123&MessageStatus=delivered&To=%2B1234567890&From=%2B1987654321" req := httptest.NewRequest("POST", "/webhook", strings.NewReader(formData)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") w := httptest.NewRecorder() inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1} h.HandleDeliveryStatus(w, req, inbox) assert.Equal(t, http.StatusOK, w.Code) } func TestWebhookHandler_HandleDeliveryStatus_Unhandled_Cov4(t *testing.T) { svc := NewTwilioService(nil) pipe := NewIncomingProcessor(svc) h := NewWebhookHandler(pipe, svc) formData := "MessageSid=SM000&MessageStatus=sent&To=%2B1234567890" req := httptest.NewRequest("POST", "/webhook", strings.NewReader(formData)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") w := httptest.NewRecorder() inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1} h.HandleDeliveryStatus(w, req, inbox) assert.Equal(t, http.StatusOK, w.Code) } func TestWriteTwiMLResponse_WithMessage_Cov4(t *testing.T) { w := httptest.NewRecorder() writeTwiMLResponse(w, "Hello from GoChat") assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "Hello from GoChat") assert.Contains(t, w.Header().Get("Content-Type"), "xml") } func TestWriteTwiMLResponse_EmptyMessage_Cov4(t *testing.T) { w := httptest.NewRecorder() writeTwiMLResponse(w, "") assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "Response") } func TestTwiMLResponse_Xml_Cov4(t *testing.T) { resp := TwiMLResponse{ Message: []TwiMLMsg{{Text: "test"}}, } assert.NotEmpty(t, resp.Message) } func TestTwilioProvider_OnCreate_NoCredentials_Cov4(t *testing.T) { svc := NewTwilioService(nil) provider := NewTwilioProvider(svc, &Repository{}, NewIncomingProcessor(svc)) inbox := &model.Inbox{Base: model.Base{ID: 1}, AccountID: 1} config := channelpkg.ChannelConfig{} result, err := provider.OnCreate(context.Background(), inbox, config) assert.NoError(t, err) assert.NotNil(t, result) } func TestTwilioProvider_SendMessage_APIError_Cov4(t *testing.T) { svc := NewTwilioService(nil) svc.client.SetTransport(&testTransport{handler: func(req *http.Request) (*http.Response, error) { return &http.Response{ StatusCode: 500, Body: io.NopCloser(strings.NewReader("Internal Server Error")), Header: make(http.Header), }, nil }}) provider := NewTwilioProvider(svc, &Repository{}, NewIncomingProcessor(svc)) ctx := context.Background() inbox := &model.Inbox{ Base: model.Base{ID: 1}, ChannelConfig: `{"account_sid":"AC123","auth_token":"token","phone_number":"+198****4321"}`, } contact := &model.Contact{SourceID: "+123****7890"} msg := &model.Message{Content: "Hello"} _, err := provider.SendMessage(ctx, inbox, msg, contact) assert.Error(t, err) } func TestParseInboxConfig_InvalidJSON_Cov4(t *testing.T) { result := parseInboxConfig("invalid json") assert.NotNil(t, result) assert.Empty(t, result) } func TestConfigStr_NonStringValue_Cov4(t *testing.T) { result := configStr(channelpkg.ChannelConfig{"key": 123}, "key", "default") assert.Equal(t, "default", result) } func TestParseInboxConfig_Empty_Cov4(t *testing.T) { result := parseInboxConfig("") assert.NotNil(t, result) assert.Empty(t, result) }