package application import ( "context" "log" "strconv" "testing" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" "git.grassecon.net/grassrootseconomics/common/pin" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-vise/store" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" "github.com/alecthomas/assert/v2" ) func TestCountIncorrectPINAttempts(t *testing.T) { ctx, store := InitializeTestStore(t) sessionId := "session123" ctx = context.WithValue(ctx, "SessionId", sessionId) attempts := uint8(2) h := &MenuHandlers{ userdataStore: store, } err := store.WriteEntry(ctx, sessionId, storedb.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(attempts)))) if err != nil { t.Logf(err.Error()) } err = h.incrementIncorrectPINAttempts(ctx, sessionId) if err != nil { t.Logf(err.Error()) } attemptsAfterCount, err := store.ReadEntry(ctx, sessionId, storedb.DATA_INCORRECT_PIN_ATTEMPTS) if err != nil { t.Logf(err.Error()) } pinAttemptsValue, _ := strconv.ParseUint(string(attemptsAfterCount), 0, 64) pinAttemptsCount := uint8(pinAttemptsValue) expectedAttempts := attempts + 1 assert.Equal(t, pinAttemptsCount, expectedAttempts) } func TestResetIncorrectPINAttempts(t *testing.T) { ctx, store := InitializeTestStore(t) sessionId := "session123" ctx = context.WithValue(ctx, "SessionId", sessionId) err := store.WriteEntry(ctx, sessionId, storedb.DATA_INCORRECT_PIN_ATTEMPTS, []byte(string("2"))) if err != nil { t.Logf(err.Error()) } h := &MenuHandlers{ userdataStore: store, } h.resetIncorrectPINAttempts(ctx, sessionId) incorrectAttempts, err := store.ReadEntry(ctx, sessionId, storedb.DATA_INCORRECT_PIN_ATTEMPTS) if err != nil { t.Logf(err.Error()) } assert.Equal(t, "0", string(incorrectAttempts)) } func TestSaveTemporaryPin(t *testing.T) { sessionId := "session123" ctx, userdatastore := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) _, logdb := InitializeTestLogdbStore(t) logDb := store.LogDb{ Db: logdb, } fm, err := NewFlagManager(flagsPath) if err != nil { log.Fatal(err) } flag_invalid_pin, _ := fm.GetFlag("flag_invalid_pin") // Create the MenuHandlers instance with the mock flag manager h := &MenuHandlers{ flagManager: fm, userdataStore: userdatastore, logDb: logDb, } // 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_invalid_pin}, }, }, { name: "Invalid Pin entry", input: []byte("12343"), expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_pin}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Call the method res, err := h.SaveTemporaryPin(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, "Result should match expected result") }) } } func TestConfirmPinChange(t *testing.T) { sessionId := "session123" mockState := state.NewState(16) ctx, store := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) fm, _ := NewFlagManager(flagsPath) flag_pin_mismatch, _ := fm.GetFlag("flag_pin_mismatch") flag_account_pin_reset, _ := fm.GetFlag("flag_account_pin_reset") mockAccountService := new(mocks.MockAccountService) h := &MenuHandlers{ userdataStore: store, flagManager: fm, accountService: mockAccountService, st: mockState, } tests := []struct { name string input []byte temporarypin string expectedResult resource.Result }{ { name: "Test with correct pin confirmation", input: []byte("1234"), temporarypin: "1234", expectedResult: resource.Result{ FlagReset: []uint32{flag_pin_mismatch, flag_account_pin_reset}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Hash the PIN hashedPIN, err := pin.HashPIN(tt.temporarypin) if err != nil { logg.ErrorCtxf(ctx, "failed to hash temporaryPin", "error", err) t.Fatal(err) } // Set up the expected behavior of the mock err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(hashedPIN)) if err != nil { t.Fatal(err) } //Call the function under test res, _ := h.ConfirmPinChange(ctx, "confirm_pin_change", tt.input) //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 TestValidateBlockedNumber(t *testing.T) { sessionId := "session123" validNumber := "+254712345678" invalidNumber := "12343" // Invalid phone number unregisteredNumber := "+254734567890" // Valid but unregistered number publicKey := "0X13242618721" mockState := state.NewState(128) ctx, userStore := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) fm, err := NewFlagManager(flagsPath) if err != nil { t.Fatal(err) } flag_unregistered_number, _ := fm.GetFlag("flag_unregistered_number") h := &MenuHandlers{ userdataStore: userStore, st: mockState, flagManager: fm, } err = userStore.WriteEntry(ctx, validNumber, storedb.DATA_PUBLIC_KEY, []byte(publicKey)) if err != nil { t.Fatal(err) } tests := []struct { name string input []byte expectedResult resource.Result }{ { name: "Valid and registered number", input: []byte(validNumber), expectedResult: resource.Result{}, }, { name: "Invalid Phone Number", input: []byte(invalidNumber), expectedResult: resource.Result{ FlagSet: []uint32{flag_unregistered_number}, }, }, { name: "Unregistered Phone Number", input: []byte(unregisteredNumber), expectedResult: resource.Result{ FlagSet: []uint32{flag_unregistered_number}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := h.ValidateBlockedNumber(ctx, "validate_blocked_number", tt.input) assert.NoError(t, err) assert.Equal(t, tt.expectedResult, res) if tt.name == "Valid and registered number" { blockedNumber, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER) if err != nil { t.Fatal(err) } assert.Equal(t, validNumber, string(blockedNumber)) } }) } } func TestResetOthersPin(t *testing.T) { sessionId := "session123" blockedNumber := "+254712345678" testPin := "1234" ctx, userStore := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) hashedPIN, err := pin.HashPIN(testPin) if err != nil { logg.ErrorCtxf(ctx, "failed to hash testPin", "error", err) t.Fatal(err) } h := &MenuHandlers{ userdataStore: userStore, } // Write initial data to the store err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER, []byte(blockedNumber)) if err != nil { t.Fatal(err) } err = userStore.WriteEntry(ctx, blockedNumber, storedb.DATA_TEMPORARY_VALUE, []byte(hashedPIN)) if err != nil { t.Fatal(err) } _, err = h.ResetOthersPin(ctx, "reset_others_pin", []byte("")) assert.NoError(t, err) }