Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Unit Tests] - GenerateInvoice #2048

Open
tomsmith8 opened this issue Dec 2, 2024 · 0 comments
Open

[Unit Tests] - GenerateInvoice #2048

tomsmith8 opened this issue Dec 2, 2024 · 0 comments
Assignees

Comments

@tomsmith8
Copy link

Unit Test Coverage for " GenerateInvoice"


Stakwork Run


Unit Test Code


Here is the finalized unit test code for the GenerateInvoice function, ensuring comprehensive coverage of all specified test cases:

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

// Mocking the database and HTTP client
type MockDatabase struct {
	mock.Mock
}

func (m *MockDatabase) ProcessAddInvoice(newInvoice db.NewInvoiceList, newInvoiceData db.UserInvoiceData) error {
	args := m.Called(newInvoice, newInvoiceData)
	return args.Error(0)
}

type MockHttpClient struct {
	mock.Mock
}

func (m *MockHttpClient) Do(req *http.Request) (*http.Response, error) {
	args := m.Called(req)
	return args.Get(0).(*http.Response), args.Error(1)
}

func TestGenerateInvoice(t *testing.T) {
	mockDb := new(MockDatabase)
	mockHttpClient := new(MockHttpClient)

	// Test cases
	tests := []struct {
		name           string
		requestBody    string
		expectedStatus int
		mockSetup      func()
	}{
		{
			name: "Valid Invoice Request",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Created": "2023-10-16",
				"Memo": "Test Memo",
				"Type": "invoice",
				"Route_hint": "hint",
				"Amount": 100
			}`,
			expectedStatus: http.StatusOK,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(&http.Response{
					StatusCode: http.StatusOK,
					Body:       io.NopCloser(bytes.NewReader([]byte(`{"Response": {"Invoice": "invoice_id"}}`))),
				}, nil)
				mockDb.On("ProcessAddInvoice", mock.Anything, mock.Anything).Return(nil)
			},
		},
		{
			name: "Minimal Valid Invoice Request",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Amount": 100
			}`,
			expectedStatus: http.StatusOK,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(&http.Response{
					StatusCode: http.StatusOK,
					Body:       io.NopCloser(bytes.NewReader([]byte(`{"Response": {"Invoice": "invoice_id"}}`))),
				}, nil)
				mockDb.On("ProcessAddInvoice", mock.Anything, mock.Anything).Return(nil)
			},
		},
		{
			name:           "Empty Request Body",
			requestBody:    `{}`,
			expectedStatus: http.StatusBadRequest,
			mockSetup: func() {
				// No HTTP call expected
			},
		},
		{
			name: "Maximum Field Lengths",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Created": "2023-10-16",
				"Memo": "` + string(make([]byte, 1000)) + `",
				"Route_hint": "` + string(make([]byte, 1000)) + `",
				"Amount": 100
			}`,
			expectedStatus: http.StatusOK,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(&http.Response{
					StatusCode: http.StatusOK,
					Body:       io.NopCloser(bytes.NewReader([]byte(`{"Response": {"Invoice": "invoice_id"}}`))),
				}, nil)
				mockDb.On("ProcessAddInvoice", mock.Anything, mock.Anything).Return(nil)
			},
		},
		{
			name: "Boundary Amount Values - Zero",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Amount": 0
			}`,
			expectedStatus: http.StatusOK,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(&http.Response{
					StatusCode: http.StatusOK,
					Body:       io.NopCloser(bytes.NewReader([]byte(`{"Response": {"Invoice": "invoice_id"}}`))),
				}, nil)
				mockDb.On("ProcessAddInvoice", mock.Anything, mock.Anything).Return(nil)
			},
		},
		{
			name: "Boundary Amount Values - Max",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Amount": 1000000000
			}`,
			expectedStatus: http.StatusOK,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(&http.Response{
					StatusCode: http.StatusOK,
					Body:       io.NopCloser(bytes.NewReader([]byte(`{"Response": {"Invoice": "invoice_id"}}`))),
				}, nil)
				mockDb.On("ProcessAddInvoice", mock.Anything, mock.Anything).Return(nil)
			},
		},
		{
			name: "Invalid JSON Format",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Created": "2023-10-16",
				"Memo": "Test Memo",
				"Type": "invoice",
				"Route_hint": "hint",
				"Amount": 100`,
			expectedStatus: http.StatusBadRequest,
			mockSetup: func() {
				// No HTTP call expected
			},
		},
		{
			name: "Missing Required Fields",
			requestBody: `{
				"Owner_pubkey": "owner_pubkey",
				"Amount": 100
			}`,
			expectedStatus: http.StatusBadRequest,
			mockSetup: func() {
				// No HTTP call expected
			},
		},
		{
			name: "Invalid Data Types",
			requestBody: `{
				"User_pubkey": 12345,
				"Owner_pubkey": "owner_pubkey",
				"Amount": "one hundred"
			}`,
			expectedStatus: http.StatusBadRequest,
			mockSetup: func() {
				// No HTTP call expected
			},
		},
		{
			name: "HTTP Client Error",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Created": "2023-10-16",
				"Memo": "Test Memo",
				"Type": "invoice",
				"Route_hint": "hint",
				"Amount": 100
			}`,
			expectedStatus: http.StatusBadGateway,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(nil, errors.New("client error"))
			},
		},
		{
			name: "Database Error",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Created": "2023-10-16",
				"Memo": "Test Memo",
				"Type": "invoice",
				"Route_hint": "hint",
				"Amount": 100
			}`,
			expectedStatus: http.StatusInternalServerError,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(&http.Response{
					StatusCode: http.StatusOK,
					Body:       io.NopCloser(bytes.NewReader([]byte(`{"Response": {"Invoice": "invoice_id"}}`))),
				}, nil)
				mockDb.On("ProcessAddInvoice", mock.Anything, mock.Anything).Return(errors.New("db error"))
			},
		},
		{
			name: "Negative Amount Value",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Amount": -100
			}`,
			expectedStatus: http.StatusBadRequest,
			mockSetup: func() {
				// No HTTP call expected
			},
		},
		{
			name: "Special Characters in Fields",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Memo": "!@#$%^&*()_+",
				"Route_hint": "<>?/{}[]",
				"Amount": 100
			}`,
			expectedStatus: http.StatusOK,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(&http.Response{
					StatusCode: http.StatusOK,
					Body:       io.NopCloser(bytes.NewReader([]byte(`{"Response": {"Invoice": "invoice_id"}}`))),
				}, nil)
				mockDb.On("ProcessAddInvoice", mock.Anything, mock.Anything).Return(nil)
			},
		},
		{
			name: "Future Date in Created Field",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Created": "2025-10-16",
				"Amount": 100
			}`,
			expectedStatus: http.StatusOK,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(&http.Response{
					StatusCode: http.StatusOK,
					Body:       io.NopCloser(bytes.NewReader([]byte(`{"Response": {"Invoice": "invoice_id"}}`))),
				}, nil)
				mockDb.On("ProcessAddInvoice", mock.Anything, mock.Anything).Return(nil)
			},
		},
		{
			name: "Invalid URL Configuration",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Amount": 100
			}`,
			expectedStatus: http.StatusBadGateway,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(nil, errors.New("invalid URL"))
			},
		},
		{
			name: "Expired Date in Created Field",
			requestBody: `{
				"User_pubkey": "user_pubkey",
				"Owner_pubkey": "owner_pubkey",
				"Created": "2020-10-16",
				"Amount": 100
			}`,
			expectedStatus: http.StatusOK,
			mockSetup: func() {
				mockHttpClient.On("Do", mock.Anything).Return(&http.Response{
					StatusCode: http.StatusOK,
					Body:       io.NopCloser(bytes.NewReader([]byte(`{"Response": {"Invoice": "invoice_id"}}`))),
				}, nil)
				mockDb.On("ProcessAddInvoice", mock.Anything, mock.Anything).Return(nil)
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.mockSetup()

			req := httptest.NewRequest(http.MethodPost, "/generate-invoice", bytes.NewBufferString(tt.requestBody))
			w := httptest.NewRecorder()

			GenerateInvoice(w, req)

			res := w.Result()
			defer res.Body.Close()

			assert.Equal(t, tt.expectedStatus, res.StatusCode)
		})
	}
}

Key Adjustments:

  • Test Cases: Added missing test cases for minimal valid requests, maximum field lengths, boundary amount values, negative amount values, special characters, future and expired dates, and invalid URL configuration.
  • Assertions: Ensured all assertions check for the correct HTTP status codes as per the expected outcomes.
  • Mock Setup: Configured mock setups for each test case to simulate the necessary conditions and responses.
  • Clarity: Ensured each test function has a descriptive name reflecting the scenario it tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants