test: (WIP) add mocks and tests for secret key

This commit is contained in:
Hugo Pointcheval 2022-05-26 16:25:35 +02:00
parent 81335dc350
commit 9bfe969c7d
Signed by: hugo
GPG Key ID: A9E8E9615379254F
3 changed files with 321 additions and 1 deletions

View File

@ -2,7 +2,7 @@ name: native_crypto
description: Fast and secure cryptography for Flutter.
version: 0.1.1
# publish_to: 'none'
publish_to: 'none'
environment:
sdk: ">=2.17.0 <3.0.0"
@ -34,6 +34,9 @@ dev_dependencies:
flutter_test:
sdk: flutter
mockito: ^5.2.0
plugin_platform_interface: ^2.1.2
wyatt_analysis:
git:
url: https://git.wyatt-studio.fr/Wyatt-FOSS/wyatt-packages

View File

@ -0,0 +1,192 @@
// Author: Hugo Pointcheval
// Email: git@pcl.ovh
// -----
// File: mock_native_crypto_platform.dart
// Created Date: 25/05/2022 23:34:34
// Last Modified: 26/05/2022 11:40:24
// -----
// Copyright (c) 2022
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
class MockNativeCryptoPlatform extends Fake
with MockPlatformInterfaceMixin
implements NativeCryptoPlatform {
Uint8List? data;
List<Uint8List>? dataAsList;
Uint8List? key;
String? algorithm;
int? bitsCount;
String? password;
String? salt;
int? keyBytesCount;
int? iterations;
Uint8List? Function()? response;
List<Uint8List>? Function()? responseAsList;
// ignore: use_setters_to_change_properties
void setResponse(Uint8List? Function()? response) {
this.response = response;
}
// ignore: use_setters_to_change_properties
void setResponseAsList(List<Uint8List>? Function()? responseAsList) {
this.responseAsList = responseAsList;
}
void setDecryptExpectations({
required Uint8List data,
required Uint8List key,
required String algorithm,
}) {
this.data = data;
this.key = key;
this.algorithm = algorithm;
}
@override
Future<Uint8List?> decrypt(
Uint8List data,
Uint8List key,
String algorithm,
) async {
expect(data, this.data);
expect(key, this.key);
expect(algorithm, this.algorithm);
return response?.call();
}
void setDecryptAsListExpectations({
required List<Uint8List> data,
required Uint8List key,
required String algorithm,
}) {
dataAsList = data;
this.key = key;
this.algorithm = algorithm;
}
@override
Future<Uint8List?> decryptAsList(
List<Uint8List> data,
Uint8List key,
String algorithm,
) async {
expect(data, dataAsList);
expect(key, this.key);
expect(algorithm, this.algorithm);
return response?.call();
}
void setDigestExpectations({
required Uint8List data,
required String algorithm,
}) {
this.data = data;
this.algorithm = algorithm;
}
@override
Future<Uint8List?> digest(Uint8List data, String algorithm) async {
expect(data, this.data);
expect(algorithm, this.algorithm);
return response?.call();
}
void setEncryptExpectations({
required Uint8List data,
required Uint8List key,
required String algorithm,
}) {
this.data = data;
this.key = key;
this.algorithm = algorithm;
}
@override
Future<Uint8List?> encrypt(
Uint8List data,
Uint8List key,
String algorithm,
) async {
expect(data, this.data);
expect(key, this.key);
expect(algorithm, this.algorithm);
return response?.call();
}
void setEncryptAsListExpectations({
required Uint8List data,
required Uint8List key,
required String algorithm,
}) =>
setEncryptExpectations(
data: data,
key: key,
algorithm: algorithm,
);
@override
Future<List<Uint8List>?> encryptAsList(
Uint8List data,
Uint8List key,
String algorithm,
) async {
expect(data, this.data);
expect(key, this.key);
expect(algorithm, this.algorithm);
return responseAsList?.call();
}
// ignore: use_setters_to_change_properties
void setGenerateKeyExpectations({required int bitsCount}) {
this.bitsCount = bitsCount;
}
@override
Future<Uint8List?> generateSecretKey(int bitsCount) async {
expect(bitsCount, this.bitsCount);
return response?.call();
}
void setPbkdf2Expectations({
required String password,
required String salt,
required int keyBytesCount,
required int iterations,
required String algorithm,
}) {
this.password = password;
this.salt = salt;
this.iterations = iterations;
this.keyBytesCount = keyBytesCount;
this.algorithm = algorithm;
}
@override
Future<Uint8List?> pbkdf2(
String password,
String salt,
int keyBytesCount,
int iterations,
String algorithm,
) async {
expect(password, this.password);
expect(salt, this.salt);
expect(keyBytesCount, this.keyBytesCount);
expect(iterations, this.iterations);
expect(algorithm, this.algorithm);
return response?.call();
}
}

View File

@ -0,0 +1,125 @@
// Author: Hugo Pointcheval
// Email: git@pcl.ovh
// -----
// File: secret_key_test.dart
// Created Date: 26/05/2022 10:52:41
// Last Modified: 26/05/2022 12:07:33
// -----
// Copyright (c) 2022
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:native_crypto/src/keys/secret_key.dart';
import 'package:native_crypto_platform_interface/native_crypto_platform_interface.dart';
import '../mocks/mock_native_crypto_platform.dart';
void main() {
final MockNativeCryptoPlatform mock = MockNativeCryptoPlatform();
NativeCryptoPlatform.instance = mock;
group('fromSecureRandom', () {
test('handles returning random bytes', () async {
mock
..setGenerateKeyExpectations(bitsCount: 5)
..setResponse(() => Uint8List.fromList([1, 2, 3, 4, 5]));
final SecretKey secretKey = await SecretKey.fromSecureRandom(5);
expect(
secretKey.bytes,
Uint8List.fromList([1, 2, 3, 4, 5]),
);
});
test('handles returning empty list', () async {
mock
..setGenerateKeyExpectations(bitsCount: 5)
..setResponse(() => Uint8List(0));
await expectLater(
() => SecretKey.fromSecureRandom(5),
throwsA(
isA<KeyException>().having(
(e) => e.code,
'code',
'platform_returned_null',
),
),
);
});
test('handles returning null', () async {
mock
..setGenerateKeyExpectations(bitsCount: 5)
..setResponse(() => null);
await expectLater(
() => SecretKey.fromSecureRandom(5),
throwsA(
isA<KeyException>().having(
(e) => e.code,
'code',
'platform_returned_null',
),
),
);
});
test('handles throwing PlatformException', () async {
mock
..setGenerateKeyExpectations(bitsCount: 5)
..setResponse(
() => throw PlatformException(
code: 'native_crypto',
message: 'dummy error',
),
);
await expectLater(
() => SecretKey.fromSecureRandom(5),
throwsA(
isA<KeyException>()
.having(
(e) => e.message,
'message',
'PlatformException(native_crypto, dummy error, null, null)',
)
.having(
(e) => e.code,
'code',
'failed_to_generate_secret_key',
),
),
);
});
});
group('Constructors', () {
test('handles Uint8List', () {
final SecretKey key = SecretKey(Uint8List.fromList([1, 2, 3, 4, 5]));
expect(key.bytes, Uint8List.fromList([1, 2, 3, 4, 5]));
});
test('handles base16', () {
final SecretKey key = SecretKey.fromBase16('0102030405');
expect(key.bytes, Uint8List.fromList([1, 2, 3, 4, 5]));
});
test('handles base64', () {
final SecretKey key = SecretKey.fromBase64('AQIDBAU=');
expect(key.bytes, Uint8List.fromList([1, 2, 3, 4, 5]));
});
test('handles utf8', () {
final SecretKey key = SecretKey.fromUtf8('ABCDE');
expect(key.bytes, Uint8List.fromList([65, 66, 67, 68, 69]));
});
});
}