package ussd import ( "context" "encoding/json" "fmt" "log" "path" "testing" "git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" "git.grassecon.net/urdt/ussd/internal/mocks" "git.grassecon.net/urdt/ussd/internal/models" "git.grassecon.net/urdt/ussd/internal/utils" "github.com/alecthomas/assert/v2" testdataloader "github.com/peteole/testdata-loader" ) var ( baseDir = testdataloader.GetBasePath() flagsPath = path.Join(baseDir, "services", "registration", "pp.csv") ) func TestCreateAccount(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } // Create required mocks mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) expectedResult := resource.Result{} accountCreatedFlag, err := fm.GetFlag("flag_account_created") if err != nil { t.Logf(err.Error()) } expectedResult.FlagSet = append(expectedResult.FlagSet, accountCreatedFlag) // Define session ID and mock data sessionId := "session123" typ := utils.DATA_ACCOUNT_CREATED fakeError := db.ErrNotFound{} // Create context with session ID ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return([]byte("123"), fakeError) expectedAccountResp := &models.AccountResponse{ Ok: true, Result: struct { CustodialId json.Number `json:"custodialId"` PublicKey string `json:"publicKey"` TrackingId string `json:"trackingId"` }{ CustodialId: "12", PublicKey: "0x8E0XSCSVA", TrackingId: "d95a7e83-196c-4fd0-866fSGAGA", }, } mockCreateAccountService.On("CreateAccount").Return(expectedAccountResp, nil) data := map[utils.DataTyp]string{ utils.DATA_TRACKING_ID: expectedAccountResp.Result.TrackingId, utils.DATA_PUBLIC_KEY: expectedAccountResp.Result.PublicKey, utils.DATA_CUSTODIAL_ID: expectedAccountResp.Result.CustodialId.String(), } for key, value := range data { mockDataStore.On("WriteEntry", ctx, sessionId, key, []byte(value)).Return(nil) } // Create a Handlers instance with the mock data store h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, } // Call the method you want to test res, err := h.CreateAccount(ctx, "create_account", []byte("some-input")) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) } func TestSaveFirstname(t *testing.T) { // Create a new instance of MockMyDataStore mockStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" firstName := "John" ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_FIRST_NAME, []byte(firstName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method res, err := h.SaveFirstname(ctx, "save_firstname", []byte(firstName)) // Assert results assert.NoError(t, err) assert.Equal(t, resource.Result{}, res) // Assert all expectations were met mockStore.AssertExpectations(t) } func TestSaveFamilyname(t *testing.T) { // Create a new instance of UserDataStore mockStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" familyName := "Doeee" ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(familyName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method res, err := h.SaveFamilyname(ctx, "save_familyname", []byte(familyName)) // Assert results assert.NoError(t, err) assert.Equal(t, resource.Result{}, res) // Assert all expectations were met mockStore.AssertExpectations(t) } func TestSavePin(t *testing.T) { fm, err := NewFlagManager(flagsPath) mockStore := new(mocks.MockUserDataStore) if err != nil { log.Fatal(err) } flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, userdataStore: mockStore, } sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Define test cases tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Valid Pin entry", input: []byte("1234"), expectedResult: resource.Result{ FlagReset: []uint32{flag_incorrect_pin}, }, }, { name: "Invalid Pin entry", input: []byte("12343"), expectedResult: resource.Result{ FlagSet: []uint32{flag_incorrect_pin}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Set up the expected behavior of the mock mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(tt.input)).Return(nil) // Call the method res, err := h.SavePin(ctx, "save_pin", tt.input) if err != nil { t.Error(err) } // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Flags should be equal to account created") }) } } func TestSaveYoB(t *testing.T) { // Create a new instance of MockMyDataStore mockStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" yob := "1980" ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_YOB, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method res, err := h.SaveYob(ctx, "save_yob", []byte(yob)) // Assert results assert.NoError(t, err) assert.Equal(t, resource.Result{}, res) // Assert all expectations were met mockStore.AssertExpectations(t) } func TestSaveLocation(t *testing.T) { // Create a new instance of MockMyDataStore mockStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" yob := "Kilifi" ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_LOCATION, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method res, err := h.SaveLocation(ctx, "save_location", []byte(yob)) // Assert results assert.NoError(t, err) assert.Equal(t, resource.Result{}, res) // Assert all expectations were met mockStore.AssertExpectations(t) } func TestSaveOfferings(t *testing.T) { // Create a new instance of MockUserDataStore mockStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" offerings := "Bananas" ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_OFFERINGS, []byte(offerings)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method res, err := h.SaveOfferings(ctx, "save_offerings", []byte(offerings)) // Assert results assert.NoError(t, err) assert.Equal(t, resource.Result{}, res) // Assert all expectations were met mockStore.AssertExpectations(t) } func TestSaveGender(t *testing.T) { // Create a new instance of MockMyDataStore mockStore := new(mocks.MockUserDataStore) // Define the session ID and context sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Define test cases tests := []struct { name string input []byte expectedGender string expectCall bool }{ { name: "Valid Male Input", input: []byte("1"), expectedGender: "Male", expectCall: true, }, { name: "Valid Female Input", input: []byte("2"), expectedGender: "Female", expectCall: true, }, { name: "Valid Unspecified Input", input: []byte("3"), expectedGender: "Unspecified", expectCall: true, }, { name: "Empty Input", input: []byte(""), expectedGender: "", expectCall: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Set up expectations for the mock database if tt.expectCall { expectedKey := utils.DATA_GENDER mockStore.On("WriteEntry", ctx, sessionId, expectedKey, []byte(tt.expectedGender)).Return(nil) } else { mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)).Return(nil) } // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method _, err := h.SaveGender(ctx, "someSym", tt.input) // Assert no error assert.NoError(t, err) // Verify expectations if tt.expectCall { mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)) } else { mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)) } }) } } func TestCheckIdentifier(t *testing.T) { // Create a new instance of MockMyDataStore mockStore := new(mocks.MockUserDataStore) // Define the session ID and context sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Define test cases tests := []struct { name string mockPublicKey []byte mockErr error expectedContent string expectError bool }{ { name: "Saved public Key", mockPublicKey: []byte("0xa8363"), mockErr: nil, expectedContent: "0xa8363", expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Set up expectations for the mock database mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.mockPublicKey, tt.mockErr) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method res, err := h.CheckIdentifier(ctx, "check_identifier", nil) // Assert results assert.NoError(t, err) assert.Equal(t, tt.expectedContent, res.Content) // Verify expectations mockStore.AssertExpectations(t) }) } } func TestMaxAmount(t *testing.T) { mockStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) // Define test data sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) publicKey := "0xcasgatweksalw1018221" expectedBalance := "0.003CELO" // Set up the expected behavior of the mock mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) mockCreateAccountService.On("CheckBalance", publicKey).Return(expectedBalance, nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, accountService: mockCreateAccountService, } // Call the method res, _ := h.MaxAmount(ctx, "max_amount", []byte("check_balance")) //Assert that the balance that was set as the result content is what was returned by Check Balance assert.Equal(t, expectedBalance, res.Content) } func TestGetSender(t *testing.T) { mockStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) publicKey := "0xcasgatweksalw1018221" // Set up the expected behavior of the mock mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method res, _ := h.GetSender(ctx, "max_amount", []byte("check_balance")) //Assert that the public key from readentry operation is what was set as the result content. assert.Equal(t, publicKey, res.Content) } func TestGetAmount(t *testing.T) { mockStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) Amount := "0.03CELO" // Set up the expected behavior of the mock mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return([]byte(Amount), nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method res, _ := h.GetAmount(ctx, "get_amount", []byte("Getting amount...")) //Assert that the retrieved amount is what was set as the content assert.Equal(t, Amount, res.Content) } func TestGetRecipient(t *testing.T) { mockStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) recepient := "0xcasgatweksalw1018221" // Set up the expected behavior of the mock mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return([]byte(recepient), nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, } // Call the method res, _ := h.GetRecipient(ctx, "get_recipient", []byte("Getting recipient...")) //Assert that the retrieved recepient is what was set as the content assert.Equal(t, recepient, res.Content) } func TestGetFlag(t *testing.T) { fm, err := NewFlagManager(flagsPath) expectedFlag := uint32(9) if err != nil { t.Logf(err.Error()) } flag, err := fm.GetFlag("flag_account_created") if err != nil { t.Logf(err.Error()) } assert.Equal(t, uint32(flag), expectedFlag, "Flags should be equal to account created") } func TestSetLanguage(t *testing.T) { // Create a new instance of the Flag Manager fm, err := NewFlagManager(flagsPath) if err != nil { log.Fatal(err) } // Define test cases tests := []struct { name string execPath []string expectedResult resource.Result }{ { name: "Set Default Language (English)", execPath: []string{"set_default"}, expectedResult: resource.Result{ FlagSet: []uint32{state.FLAG_LANG, 8}, Content: "eng", }, }, { name: "Set Swahili Language", execPath: []string{"set_swa"}, expectedResult: resource.Result{ FlagSet: []uint32{state.FLAG_LANG, 8}, Content: "swa", }, }, { name: "Unhandled path", execPath: []string{""}, expectedResult: resource.Result{ FlagSet: []uint32{8}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockState := state.NewState(16) // Set the ExecPath mockState.ExecPath = tt.execPath // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, st: mockState, } // Call the method res, err := h.SetLanguage(context.Background(), "set_language", nil) if err != nil { t.Error(err) } // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should match expected result") }) } } func TestSetResetSingleEdit(t *testing.T) { fm, err := NewFlagManager(flagsPath) flag_allow_update, _ := fm.parser.GetFlag("flag_allow_update") flag_single_edit, _ := fm.parser.GetFlag("flag_single_edit") if err != nil { log.Fatal(err) } // Define test cases tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Set single Edit", input: []byte("2"), expectedResult: resource.Result{ FlagSet: []uint32{flag_single_edit}, FlagReset: []uint32{flag_allow_update}, }, }, { name: "Set single Edit", input: []byte("3"), expectedResult: resource.Result{ FlagSet: []uint32{flag_single_edit}, FlagReset: []uint32{flag_allow_update}, }, }, { name: "Set single edit", input: []byte("4"), expectedResult: resource.Result{ FlagReset: []uint32{flag_allow_update}, FlagSet: []uint32{flag_single_edit}, }, }, { name: "No single edit set", input: []byte("1"), expectedResult: resource.Result{ FlagReset: []uint32{flag_single_edit}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, } // Call the method res, err := h.SetResetSingleEdit(context.Background(), "set_reset_single_edit", tt.input) if err != nil { t.Error(err) } // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Flags should match reset edit") }) } } func TestResetAllowUpdate(t *testing.T) { fm, err := NewFlagManager(flagsPath) flag_allow_update, _ := fm.parser.GetFlag("flag_allow_update") if err != nil { log.Fatal(err) } // Define test cases tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Resets allow update", input: []byte(""), expectedResult: resource.Result{ FlagReset: []uint32{flag_allow_update}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, } // Call the method res, err := h.ResetAllowUpdate(context.Background(), "reset_allow update", tt.input) if err != nil { t.Error(err) } // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Flags should be equal to account created") }) } } func TestResetAccountAuthorized(t *testing.T) { fm, err := NewFlagManager(flagsPath) flag_account_authorized, _ := fm.parser.GetFlag("flag_account_authorized") if err != nil { log.Fatal(err) } // Define test cases tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Resets account authorized", input: []byte(""), expectedResult: resource.Result{ FlagReset: []uint32{flag_account_authorized}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, } // Call the method res, err := h.ResetAccountAuthorized(context.Background(), "reset_account_authorized", tt.input) if err != nil { t.Error(err) } // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") }) } } func TestIncorrectPinReset(t *testing.T) { fm, err := NewFlagManager(flagsPath) flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") if err != nil { log.Fatal(err) } // Define test cases tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Test incorrect pin reset", input: []byte(""), expectedResult: resource.Result{ FlagReset: []uint32{flag_incorrect_pin}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, } // Call the method res, err := h.ResetIncorrectPin(context.Background(), "reset_incorrect_pin", tt.input) if err != nil { t.Error(err) } // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") }) } } func TestResetIncorrectYob(t *testing.T) { fm, err := NewFlagManager(flagsPath) flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") if err != nil { log.Fatal(err) } // Define test cases tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Test incorrect yob reset", input: []byte(""), expectedResult: resource.Result{ FlagReset: []uint32{flag_incorrect_date_format}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, } // Call the method res, err := h.ResetIncorrectYob(context.Background(), "reset_incorrect_yob", tt.input) if err != nil { t.Error(err) } // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") }) } } func TestAuthorize(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } // Create required mocks mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) //expectedResult := resource.Result{} mockState := state.NewState(16) flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin") flag_account_authorized, _ := fm.GetFlag("flag_account_authorized") flag_allow_update, _ := fm.GetFlag("flag_allow_update") //Assuming 1234 is the correct account pin accountPIN := "1234" // Define session ID and mock data sessionId := "session123" typ := utils.DATA_ACCOUNT_PIN h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, st: mockState, } tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Test with correct pin", input: []byte("1234"), expectedResult: resource.Result{ FlagReset: []uint32{flag_incorrect_pin}, FlagSet: []uint32{flag_allow_update, flag_account_authorized}, }, }, { name: "Test with incorrect pin", input: []byte("1235"), expectedResult: resource.Result{ FlagReset: []uint32{flag_account_authorized}, FlagSet: []uint32{flag_incorrect_pin}, }, }, { name: "Test with pin that is not a 4 digit", input: []byte("1235aqds"), expectedResult: resource.Result{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create context with session ID ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return([]byte(accountPIN), nil) // Create a Handlers instance with the mock data store // Call the method under test res, err := h.Authorize(ctx, "authorize", []byte(tt.input)) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestVerifyYob(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } sessionId := "session123" // Create required mocks mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) mockState := state.NewState(16) flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") ctx := context.WithValue(context.Background(), "SessionId", sessionId) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, st: mockState, } tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Test with correct yob", input: []byte("1980"), expectedResult: resource.Result{ FlagReset: []uint32{flag_incorrect_date_format}, }, }, { name: "Test with incorrect yob", input: []byte("sgahaha"), expectedResult: resource.Result{ FlagSet: []uint32{flag_incorrect_date_format}, }, }, { name: "Test with numeric but less 4 digits", input: []byte("123"), expectedResult: resource.Result{ FlagSet: []uint32{flag_incorrect_date_format}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Call the method under test res, err := h.VerifyYob(ctx, "verify_yob", []byte(tt.input)) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestVerifyPin(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } sessionId := "session123" // Create required mocks mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) mockState := state.NewState(16) flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin") flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") flag_pin_set, _ := fm.parser.GetFlag("flag_pin_set") ctx := context.WithValue(context.Background(), "SessionId", sessionId) //Assuming this was the first set PIN to verify against firstSetPin := "1234" h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, st: mockState, } tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Test with correct PIN confirmation", input: []byte("1234"), expectedResult: resource.Result{ FlagSet: []uint32{flag_valid_pin, flag_pin_set}, FlagReset: []uint32{flag_pin_mismatch}, }, }, { name: "Test with PIN that does not match first ", input: []byte("1324"), expectedResult: resource.Result{ FlagSet: []uint32{flag_pin_mismatch}, }, }, } typ := utils.DATA_ACCOUNT_PIN for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return([]byte(firstSetPin), nil) // Call the method under test res, err := h.VerifyPin(ctx, "verify_pin", []byte(tt.input)) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestCheckAccountStatus(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) sessionId := "session123" flag_account_success, _ := fm.GetFlag("flag_account_success") flag_account_pending, _ := fm.GetFlag("flag_account_pending") ctx := context.WithValue(context.Background(), "SessionId", sessionId) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, } tests := []struct { name string input []byte status string expectedResult resource.Result }{ { name: "Test when account status is Success", input: []byte("TrackingId1234"), status: "SUCCESS", expectedResult: resource.Result{ FlagSet: []uint32{flag_account_success}, FlagReset: []uint32{flag_account_pending}, }, }, } typ := utils.DATA_TRACKING_ID for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return(tt.input, nil) mockCreateAccountService.On("CheckAccountStatus", string(tt.input)).Return(tt.status, nil) mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(tt.status)).Return(nil) // Call the method under test res, _ := h.CheckAccountStatus(ctx, "check_status", tt.input) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestTransactionReset(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } flag_invalid_recipient, _ := fm.GetFlag("flag_invalid_recipient") flag_invalid_recipient_with_invite, _ := fm.GetFlag("flag_invalid_recipient_with_invite") mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, } tests := []struct { name string input []byte status string expectedResult resource.Result }{ { name: "Test transaction reset for amount and recipient", expectedResult: resource.Result{ FlagReset: []uint32{flag_invalid_recipient, flag_invalid_recipient_with_invite}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil) mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_RECIPIENT, []byte("")).Return(nil) // Call the method under test res, _ := h.TransactionReset(ctx, "transaction_reset", tt.input) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestResetInvalidAmount(t *testing.T) { sessionId := "session123" fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") ctx := context.WithValue(context.Background(), "SessionId", sessionId) mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, } tests := []struct { name string input []byte status string expectedResult resource.Result }{ { name: "Test amount reset", expectedResult: resource.Result{ FlagReset: []uint32{flag_invalid_amount}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil) // Call the method under test res, _ := h.ResetTransactionAmount(ctx, "transaction_reset_amount", tt.input) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestInitiateTransaction(t *testing.T) { sessionId := "session123" fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } account_authorized_flag, err := fm.parser.GetFlag("flag_account_authorized") ctx := context.WithValue(context.Background(), "SessionId", sessionId) mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, } tests := []struct { name string input []byte PublicKey []byte Recipient []byte Amount []byte status string expectedResult resource.Result }{ { name: "Test amount reset", PublicKey: []byte("0x1241527192"), Amount: []byte("0.002CELO"), Recipient: []byte("0x12415ass27192"), expectedResult: resource.Result{ FlagReset: []uint32{account_authorized_flag}, Content: "Your request has been sent. 0x12415ass27192 will receive 0.002CELO from 0x1241527192.", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.PublicKey, nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return(tt.Amount, nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return(tt.Recipient, nil) //mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil) // Call the method under test res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", tt.input) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestQuit(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } flag_account_authorized, _ := fm.parser.GetFlag("flag_account_authorized") mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, } tests := []struct { name string input []byte status string expectedResult resource.Result }{ { name: "Test quit message", expectedResult: resource.Result{ FlagReset: []uint32{flag_account_authorized}, Content: "Thank you for using Sarafu. Goodbye!", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Call the method under test res, _ := h.Quit(ctx, "test_quit", tt.input) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestIsValidPIN(t *testing.T) { tests := []struct { name string pin string expected bool }{ { name: "Valid PIN with 4 digits", pin: "1234", expected: true, }, { name: "Valid PIN with leading zeros", pin: "0001", expected: true, }, { name: "Invalid PIN with less than 4 digits", pin: "123", expected: false, }, { name: "Invalid PIN with more than 4 digits", pin: "12345", expected: false, }, { name: "Invalid PIN with letters", pin: "abcd", expected: false, }, { name: "Invalid PIN with special characters", pin: "12@#", expected: false, }, { name: "Empty PIN", pin: "", expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { actual := isValidPIN(tt.pin) if actual != tt.expected { t.Errorf("isValidPIN(%q) = %v; expected %v", tt.pin, actual, tt.expected) } }) } } func TestQuitWithBalance(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } flag_account_authorized, _ := fm.parser.GetFlag("flag_account_authorized") mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, } tests := []struct { name string input []byte publicKey []byte balance string expectedResult resource.Result }{ { name: "Test quit with balance", balance: "0.02CELO", publicKey: []byte("0xrqeqrequuq"), expectedResult: resource.Result{ FlagReset: []uint32{flag_account_authorized}, Content: fmt.Sprintf("Your account balance is %s", "0.02CELO"), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.publicKey, nil) mockCreateAccountService.On("CheckBalance", string(tt.publicKey)).Return(tt.balance, nil) // Call the method under test res, _ := h.QuitWithBalance(ctx, "test_quit_with_balance", tt.input) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestValidateAmount(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } //flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, flagManager: fm.parser, } tests := []struct { name string input []byte publicKey []byte balance string expectedResult resource.Result }{ { name: "Test with valid amount", input: []byte("0.001"), balance: "0.003 CELO", publicKey: []byte("0xrqeqrequuq"), expectedResult: resource.Result{ Content: "0.001", }, }, // { // name: "Test with amount larger than balance", // input: []byte("0.02"), // balance: "0.003 CELO", // publicKey: []byte("0xrqeqrequuq"), // expectedResult: resource.Result{ // FlagSet: []uint32{flag_invalid_amount}, // Content: "0.02", // }, // }, // { // name: "Test with invalid amount", // input: []byte("0.02ms"), // balance: "0.003 CELO", // publicKey: []byte("0xrqeqrequuq"), // expectedResult: resource.Result{ // FlagSet: []uint32{flag_invalid_amount}, // Content: "0.02ms", // }, // }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.publicKey, nil) mockCreateAccountService.On("CheckBalance", string(tt.publicKey)).Return(tt.balance, nil) mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, tt.input).Return(nil) // Call the method under test res, _ := h.ValidateAmount(ctx, "test_validate_amount", tt.input) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") // Assert that expectations were met mockDataStore.AssertExpectations(t) }) } } func TestValidateRecipient(t *testing.T) { fm, err := NewFlagManager(flagsPath) flag_invalid_recipient, _ := fm.parser.GetFlag("flag_invalid_recipient") mockDataStore := new(mocks.MockUserDataStore) sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) if err != nil { log.Fatal(err) } // Define test cases tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Test with invalid recepient", input: []byte("000"), expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_recipient}, Content: "000", }, }, { name: "Test with valid recepient", input: []byte("0705X2"), expectedResult: resource.Result{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_RECIPIENT, tt.input).Return(nil) // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, userdataStore: mockDataStore, } // Call the method res, err := h.ValidateRecipient(ctx, "validate_recepient", tt.input) if err != nil { t.Error(err) } // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") }) } } func TestCheckBalance(t *testing.T) { mockDataStore := new(mocks.MockUserDataStore) sessionId := "session123" publicKey := "0X13242618721" balance := "0.003 CELO" expectedResult := resource.Result{ Content: "0.003 CELO", } mockCreateAccountService := new(mocks.MockAccountService) ctx := context.WithValue(context.Background(), "SessionId", sessionId) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, //flagManager: fm.parser, } //mock call operations mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) mockCreateAccountService.On("CheckBalance", string(publicKey)).Return(balance, nil) res, _ := h.CheckBalance(ctx, "check_balance", []byte("123456")) assert.Equal(t, res, expectedResult, "Result should contain flag(s) that have been reset") } func TestGetProfile(t *testing.T) { sessionId := "session123" mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) h := &Handlers{ userdataStore: mockDataStore, accountService: mockCreateAccountService, } ctx := context.WithValue(context.Background(), "SessionId", sessionId) tests := []struct { name string keys []utils.DataTyp profileInfo []string result resource.Result }{ { name: "Test with full profile information", keys: []utils.DataTyp{utils.DATA_FAMILY_NAME, utils.DATA_FIRST_NAME, utils.DATA_GENDER, utils.DATA_OFFERINGS, utils.DATA_LOCATION, utils.DATA_YOB}, profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, result: resource.Result{ Content: fmt.Sprintf( "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", "John Doee", "Male", "48", "Kilifi", "Bananas", ), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { for index, key := range tt.keys { mockDataStore.On("ReadEntry", ctx, sessionId, key).Return([]byte(tt.profileInfo[index]), nil) } res, _ := h.GetProfileInfo(ctx, "get_profile_info", []byte("")) // Assert that expectations were met mockDataStore.AssertExpectations(t) //Assert that the result set to content is what was expected assert.Equal(t, res, tt.result, "Result should contain profile information served back to user") }) } } func TestVerifyNewPin(t *testing.T) { sessionId := "session123" fm, _ := NewFlagManager(flagsPath) flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin") mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) h := &Handlers{ userdataStore: mockDataStore, flagManager: fm.parser, accountService: mockCreateAccountService, } ctx := context.WithValue(context.Background(), "SessionId", sessionId) tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Test with valid pin", input: []byte("1234"), expectedResult: resource.Result{ FlagSet: []uint32{flag_valid_pin}, }, }, { name: "Test with invalid pin", input: []byte("123"), expectedResult: resource.Result{ FlagReset: []uint32{flag_valid_pin}, }, }, { name: "Test with invalid pin", input: []byte("12345"), expectedResult: resource.Result{ FlagReset: []uint32{flag_valid_pin}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { //Call the function under test res, _ := h.VerifyNewPin(ctx, "verify_new_pin", tt.input) // Assert that expectations were met mockDataStore.AssertExpectations(t) //Assert that the result set to content is what was expected assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input") }) } } func TestSaveTemporaryPIn(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } // Create a new instance of UserDataStore mockStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" PIN := "1234" ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(PIN)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, flagManager: fm.parser, } // Call the method res, err := h.SaveTemporaryPin(ctx, "save_temporary_pin", []byte(PIN)) // Assert results assert.NoError(t, err) assert.Equal(t, resource.Result{}, res) // Assert all expectations were met mockStore.AssertExpectations(t) } func TestConfirmPin(t *testing.T) { sessionId := "session123" fm, _ := NewFlagManager(flagsPath) flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) h := &Handlers{ userdataStore: mockDataStore, flagManager: fm.parser, accountService: mockCreateAccountService, } ctx := context.WithValue(context.Background(), "SessionId", sessionId) tests := []struct { name string input []byte temporarypin []byte expectedResult resource.Result }{ { name: "Test with correct pin confirmation", input: []byte("1234"), temporarypin: []byte("1234"), expectedResult: resource.Result{ FlagReset: []uint32{flag_pin_mismatch}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Set up the expected behavior of the mock mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(tt.temporarypin)).Return(nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_PIN).Return(tt.temporarypin, nil) //Call the function under test res, _ := h.ConfirmPinChange(ctx, "confirm_pin_change", tt.temporarypin) // Assert that expectations were met mockDataStore.AssertExpectations(t) //Assert that the result set to content is what was expected assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input") }) } }