feat: add tests
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:kooltab2/services/pin_lock_service.dart';
|
||||
|
||||
class MockFlutterSecureStorage extends Mock
|
||||
implements FlutterSecureStorage {}
|
||||
|
||||
String _computeHash(String pin, String salt) {
|
||||
final bytes = utf8.encode('$salt:$pin');
|
||||
return sha256.convert(bytes).toString();
|
||||
}
|
||||
|
||||
void main() {
|
||||
late PinLockService service;
|
||||
late MockFlutterSecureStorage mockStorage;
|
||||
|
||||
setUp(() {
|
||||
mockStorage = MockFlutterSecureStorage();
|
||||
service = PinLockService(storage: mockStorage);
|
||||
});
|
||||
|
||||
group('PinLockService', () {
|
||||
group('hasPin', () {
|
||||
test('returns false when no hash stored', () async {
|
||||
when(() => mockStorage.read(key: 'pin_hash'))
|
||||
.thenAnswer((_) async => null);
|
||||
|
||||
final result = await service.hasPin();
|
||||
|
||||
expect(result, false);
|
||||
});
|
||||
|
||||
test('returns false when hash is empty', () async {
|
||||
when(() => mockStorage.read(key: 'pin_hash'))
|
||||
.thenAnswer((_) async => '');
|
||||
|
||||
final result = await service.hasPin();
|
||||
|
||||
expect(result, false);
|
||||
});
|
||||
|
||||
test('returns true when hash exists', () async {
|
||||
when(() => mockStorage.read(key: 'pin_hash'))
|
||||
.thenAnswer((_) async => 'somehash');
|
||||
|
||||
final result = await service.hasPin();
|
||||
|
||||
expect(result, true);
|
||||
});
|
||||
});
|
||||
|
||||
group('setPin', () {
|
||||
test('stores salt and hash', () async {
|
||||
when(() => mockStorage.write(key: any(named: 'key'), value: any(named: 'value')))
|
||||
.thenAnswer((_) async {});
|
||||
|
||||
await service.setPin('1234');
|
||||
|
||||
verify(() => mockStorage.write(key: 'pin_salt', value: any(named: 'value'))).called(1);
|
||||
verify(() => mockStorage.write(key: 'pin_hash', value: any(named: 'value'))).called(1);
|
||||
});
|
||||
|
||||
test('generates unique salts for different pins', () async {
|
||||
when(() => mockStorage.write(key: any(named: 'key'), value: any(named: 'value')))
|
||||
.thenAnswer((_) async {});
|
||||
|
||||
await service.setPin('1234');
|
||||
final firstSaltCapture = verify(() => mockStorage.write(
|
||||
key: 'pin_salt',
|
||||
value: captureAny(named: 'value'),
|
||||
)).captured.first;
|
||||
|
||||
await service.setPin('5678');
|
||||
final secondSaltCapture = verify(() => mockStorage.write(
|
||||
key: 'pin_salt',
|
||||
value: captureAny(named: 'value'),
|
||||
)).captured.last;
|
||||
|
||||
expect(firstSaltCapture, isNot(equals(secondSaltCapture)));
|
||||
});
|
||||
});
|
||||
|
||||
group('verifyPin', () {
|
||||
test('returns false when salt is missing', () async {
|
||||
when(() => mockStorage.read(key: 'pin_salt'))
|
||||
.thenAnswer((_) async => null);
|
||||
when(() => mockStorage.read(key: 'pin_hash'))
|
||||
.thenAnswer((_) async => 'somehash');
|
||||
|
||||
final result = await service.verifyPin('1234');
|
||||
|
||||
expect(result, false);
|
||||
});
|
||||
|
||||
test('returns false when hash is missing', () async {
|
||||
when(() => mockStorage.read(key: 'pin_salt'))
|
||||
.thenAnswer((_) async => 'somesalt');
|
||||
when(() => mockStorage.read(key: 'pin_hash'))
|
||||
.thenAnswer((_) async => null);
|
||||
|
||||
final result = await service.verifyPin('1234');
|
||||
|
||||
expect(result, false);
|
||||
});
|
||||
|
||||
test('returns true for correct pin', () async {
|
||||
const salt = 'test_salt';
|
||||
const pin = '1234';
|
||||
final expectedHash = _computeHash(pin, salt);
|
||||
when(() => mockStorage.read(key: 'pin_salt'))
|
||||
.thenAnswer((_) async => salt);
|
||||
when(() => mockStorage.read(key: 'pin_hash'))
|
||||
.thenAnswer((_) async => expectedHash);
|
||||
|
||||
final result = await service.verifyPin('1234');
|
||||
|
||||
expect(result, true);
|
||||
});
|
||||
|
||||
test('returns false for incorrect pin', () async {
|
||||
const salt = 'test_salt';
|
||||
final correctHash = _computeHash('1234', salt);
|
||||
when(() => mockStorage.read(key: 'pin_salt'))
|
||||
.thenAnswer((_) async => salt);
|
||||
when(() => mockStorage.read(key: 'pin_hash'))
|
||||
.thenAnswer((_) async => correctHash);
|
||||
|
||||
final result = await service.verifyPin('5678');
|
||||
|
||||
expect(result, false);
|
||||
});
|
||||
});
|
||||
|
||||
group('clearPin', () {
|
||||
test('deletes both salt and hash', () async {
|
||||
when(() => mockStorage.delete(key: any(named: 'key')))
|
||||
.thenAnswer((_) async {});
|
||||
|
||||
await service.clearPin();
|
||||
|
||||
verify(() => mockStorage.delete(key: 'pin_salt')).called(1);
|
||||
verify(() => mockStorage.delete(key: 'pin_hash')).called(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user