Partly resolves issue #86 Reviewed-on: #90 Co-authored-by: alfred-mk <alfredmwaik@gmail.com> Co-committed-by: alfred-mk <alfredmwaik@gmail.com>
		
			
				
	
	
		
			294 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			294 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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)
 | |
| }
 |