test: (WIP) add some tests

This commit is contained in:
Hugo Pointcheval 2022-05-26 23:22:14 +02:00
parent c5d42feef4
commit 96f9aad1b3
Signed by: hugo
GPG Key ID: A9E8E9615379254F
5 changed files with 954 additions and 27 deletions

View File

@ -0,0 +1,192 @@
// Author: Hugo Pointcheval
// Email: git@pcl.ovh
// -----
// File: cipher_text_test.dart
// Created Date: 26/05/2022 20:45:38
// Last Modified: 26/05/2022 21:29:51
// -----
// Copyright (c) 2022
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:native_crypto/native_crypto.dart';
void main() {
setUp(() {
Cipher.bytesCountPerChunk = Cipher.defaultBytesCountPerChunk;
});
group('fromBytes', () {
test('throws if length is not the one expected', () {
final Uint8List bytes = Uint8List.fromList([1, 2, 3, 4, 5]);
expect(
() => CipherText.fromBytes(
bytes,
ivLength: 1,
messageLength: 1,
tagLength: 1,
),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_argument',
)
.having(
(e) => e.message,
'message',
contains('Invalid cipher text length'),
),
),
);
});
test('throws if length is bigger than expected', () {
final Uint8List bytes = Uint8List.fromList([1, 3, 3, 3, 1]);
Cipher.bytesCountPerChunk = 2;
expect(
() => CipherText.fromBytes(
bytes,
ivLength: 1,
messageLength: 3,
tagLength: 1,
),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_argument',
)
.having(
(e) => e.message,
'message',
contains('Cipher text is too big'),
),
),
);
});
test('throws if data is empty', () {
final Uint8List bytes = Uint8List(0);
expect(
() => CipherText.fromBytes(
bytes,
ivLength: 1,
messageLength: 3,
tagLength: 1,
),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_argument',
)
.having(
(e) => e.message,
'message',
contains('Passed data is empty'),
),
),
);
});
test('throws if one of the length is negative', () {
final Uint8List bytes = Uint8List(0);
expect(
() => CipherText.fromBytes(
bytes,
ivLength: -1,
messageLength: 1,
tagLength: 1,
),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_argument',
)
.having(
(e) => e.message,
'message',
contains('Invalid length'),
),
),
);
});
});
group('get.cipherAlgorithm', () {
test('throws if not set', () {
final CipherText cipherText = CipherText.fromBytes(
Uint8List.fromList([1, 2, 3]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
);
expect(
() => cipherText.cipherAlgorithm,
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_cipher',
)
.having(
(e) => e.message,
'message',
contains('Cipher algorithm is not specified'),
),
),
);
});
test('returns the expected value', () {
final CipherText cipherText = CipherText.fromBytes(
Uint8List.fromList([1, 2, 3]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
cipherAlgorithm: CipherAlgorithm.aes,
);
expect(cipherText.cipherAlgorithm, CipherAlgorithm.aes);
});
});
group('Lengths', () {
test('get.ivLength returns the expected value', () {
final CipherText cipherText = CipherText.fromBytes(
Uint8List.fromList([1, 2, 3]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
);
expect(cipherText.ivLength, 1);
});
test('get.messageLength returns the expected value', () {
final CipherText cipherText = CipherText.fromBytes(
Uint8List.fromList([1, 2, 3]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
);
expect(cipherText.messageLength, 1);
});
test('get.tagLength returns the expected value', () {
final CipherText cipherText = CipherText.fromBytes(
Uint8List.fromList([1, 2, 3]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
);
expect(cipherText.tagLength, 1);
});
});
}

View File

@ -0,0 +1,327 @@
// Author: Hugo Pointcheval
// Email: git@pcl.ovh
// -----
// File: cipher_text_wrapper_test.dart
// Created Date: 26/05/2022 21:35:41
// Last Modified: 26/05/2022 22:27:31
// -----
// Copyright (c) 2022
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:native_crypto/native_crypto.dart';
void main() {
late CipherText single;
late List<CipherText> list;
setUp(() {
Cipher.bytesCountPerChunk = Cipher.defaultBytesCountPerChunk;
single = CipherText.fromBytes(
Uint8List.fromList([1, 2, 3]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
);
list = [
CipherText.fromBytes(
Uint8List.fromList([1, 2, 3]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
),
CipherText.fromBytes(
Uint8List.fromList([4, 5, 6]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
),
];
});
group('single', () {
test('makes isSingle true', () {
final wrapper = CipherTextWrapper.single(single);
expect(wrapper.isSingle, isTrue);
});
test('makes isList false', () {
final wrapper = CipherTextWrapper.single(single);
expect(wrapper.isList, isFalse);
});
test('makes CipherText the single value', () {
final wrapper = CipherTextWrapper.single(single);
expect(wrapper.single, single);
});
test('throws when trying to get list', () {
final wrapper = CipherTextWrapper.single(single);
expect(
() => wrapper.list,
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_data',
)
.having(
(e) => e.message,
'message',
contains('is not list'),
),
),
);
});
test('makes wrapper returns bytes of CipherText', () {
final wrapper = CipherTextWrapper.single(single);
expect(wrapper.bytes, single.bytes);
});
test('makes chunkCount = 1', () {
final wrapper = CipherTextWrapper.single(single);
expect(wrapper.chunkCount, 1);
});
test('makes unwrap() returns only CipherText', () {
final wrapper = CipherTextWrapper.single(single);
expect(wrapper.unwrap<CipherText>(), single);
});
test('makes unwrap() throws when trying to unwrap List', () {
final wrapper = CipherTextWrapper.single(single);
expect(
() => wrapper.unwrap<List<CipherText>>(),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_data',
)
.having(
(e) => e.message,
'message',
contains('you should use unwrap'),
),
),
);
});
test('makes adding is not supported', () {
final wrapper = CipherTextWrapper.single(single);
expect(
() => wrapper.add(single),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_data',
)
.having(
(e) => e.message,
'message',
contains('is already single'),
),
),
);
});
});
group('list', () {
test('makes isList true', () {
final wrapper = CipherTextWrapper.list(list);
expect(wrapper.isList, isTrue);
});
test('makes isSingle false', () {
final wrapper = CipherTextWrapper.list(list);
expect(wrapper.isSingle, isFalse);
});
test('makes List<CipherText> the list value', () {
final wrapper = CipherTextWrapper.list(list);
expect(wrapper.list, list);
});
test('throws when trying to get single', () {
final wrapper = CipherTextWrapper.list(list);
expect(
() => wrapper.single,
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_data',
)
.having(
(e) => e.message,
'message',
contains('is not single'),
),
),
);
});
test('makes wrapper returns bytes of all CipherText joined', () {
final wrapper = CipherTextWrapper.list(list);
expect(wrapper.bytes, Uint8List.fromList([1, 2, 3, 4, 5, 6]));
});
test('makes chunkCount = 2', () {
final wrapper = CipherTextWrapper.list(list);
expect(wrapper.chunkCount, 2);
});
test('makes unwrap() returns List<CipherText>', () {
final wrapper = CipherTextWrapper.list(list);
expect(wrapper.unwrap<List<CipherText>>(), list);
});
test('makes unwrap() throws when trying to unwrap single', () {
final wrapper = CipherTextWrapper.list(list);
expect(
() => wrapper.unwrap<CipherText>(),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_data',
)
.having(
(e) => e.message,
'message',
contains('you should use unwrap'),
),
),
);
});
test('makes adding is supported', () {
final originalList = List<CipherText>.from(list);
final wrapper = CipherTextWrapper.list(list)..add(single);
printOnFailure(list.length.toString());
expect(wrapper.list, [...originalList, single]);
});
});
group('empty', () {
test('makes isList true', () {
final wrapper = CipherTextWrapper.empty();
expect(wrapper.isList, isTrue);
});
test('makes isSingle false', () {
final wrapper = CipherTextWrapper.empty();
expect(wrapper.isSingle, isFalse);
});
test('makes List<CipherText> the list value', () {
final wrapper = CipherTextWrapper.empty();
expect(wrapper.list, <CipherText>[]);
});
test('throws when trying to get single', () {
final wrapper = CipherTextWrapper.empty();
expect(
() => wrapper.single,
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_data',
)
.having(
(e) => e.message,
'message',
contains('is not single'),
),
),
);
});
test('makes wrapper returns empty bytes', () {
final wrapper = CipherTextWrapper.empty();
expect(wrapper.bytes, Uint8List.fromList([]));
});
test('makes chunkCount = 0', () {
final wrapper = CipherTextWrapper.empty();
expect(wrapper.chunkCount, 0);
});
test('makes unwrap() returns empty List<CipherText>', () {
final wrapper = CipherTextWrapper.empty();
expect(wrapper.unwrap<List<CipherText>>(), <CipherText>[]);
});
test('makes unwrap() throws when trying to unwrap single', () {
final wrapper = CipherTextWrapper.empty();
expect(
() => wrapper.unwrap<CipherText>(),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_data',
)
.having(
(e) => e.message,
'message',
contains('you should use unwrap'),
),
),
);
});
test('makes adding is supported', () {
final wrapper = CipherTextWrapper.empty()..add(single);
expect(wrapper.list, [single]);
});
});
group('fromBytes', () {
test('creates single from bytes when no too big', () {
final wrapper = CipherTextWrapper.fromBytes(
Uint8List.fromList([1, 2, 3]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
);
expect(wrapper.isSingle, isTrue);
expect(wrapper.single, single);
});
test('creates list from bytes when too big', () {
Cipher.bytesCountPerChunk = 3;
final wrapper = CipherTextWrapper.fromBytes(
Uint8List.fromList([1, 2, 3, 4, 5, 6]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
);
expect(wrapper.isList, isTrue);
expect(wrapper.list, list);
});
test('modifies Cipher.bytesCountPerChunk', () {
expect(Cipher.bytesCountPerChunk, Cipher.defaultBytesCountPerChunk);
CipherTextWrapper.fromBytes(
Uint8List.fromList([1, 2, 3]),
ivLength: 1,
messageLength: 1,
tagLength: 1,
chunkSize: 3,
);
expect(Cipher.bytesCountPerChunk, 3);
});
});
}

View File

@ -0,0 +1,128 @@
// Author: Hugo Pointcheval
// Email: git@pcl.ovh
// -----
// File: hash_algorithm_test.dart
// Created Date: 26/05/2022 22:28:53
// Last Modified: 26/05/2022 23:03:03
// -----
// Copyright (c) 2022
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:native_crypto/src/utils/hash_algorithm.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('name', () {
test('is sha256 for HashAlgorithm.sha256', () {
expect(HashAlgorithm.sha256.name, 'sha256');
});
test('is sha384 for HashAlgorithm.sha384', () {
expect(HashAlgorithm.sha384.name, 'sha384');
});
test('is sha512 for HashAlgorithm.sha512', () {
expect(HashAlgorithm.sha512.name, 'sha512');
});
});
group('digest', () {
test('handles returning empty list', () async {
mock
..setDigestExpectations(
data: Uint8List.fromList([1, 2, 3]),
algorithm: 'sha256',
)
..setResponse(() => Uint8List(0));
await expectLater(
() => HashAlgorithm.sha256.digest(Uint8List.fromList([1, 2, 3])),
throwsA(
isA<NativeCryptoException>().having(
(e) => e.code,
'code',
'platform_returned_empty_data',
),
),
);
});
test('handles returning null', () async {
mock
..setDigestExpectations(
data: Uint8List.fromList([1, 2, 3]),
algorithm: 'sha256',
)
..setResponse(() => null);
await expectLater(
() => HashAlgorithm.sha256.digest(Uint8List.fromList([1, 2, 3])),
throwsA(
isA<NativeCryptoException>().having(
(e) => e.code,
'code',
'platform_returned_null',
),
),
);
});
test('handles throwing PlatformException', () async {
mock
..setDigestExpectations(
data: Uint8List.fromList([1, 2, 3]),
algorithm: 'sha256',
)
..setResponse(
() => throw PlatformException(
code: 'native_crypto',
message: 'dummy error',
),
);
await expectLater(
() => HashAlgorithm.sha256.digest(Uint8List.fromList([1, 2, 3])),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.message,
'message',
'PlatformException(native_crypto, dummy error, null, null)',
)
.having(
(e) => e.code,
'code',
'platform_throws',
),
),
);
});
test('returns data on success', () async {
final hash = Uint8List.fromList([4, 5, 6]);
mock
..setDigestExpectations(
data: Uint8List.fromList([1, 2, 3]),
algorithm: 'sha256',
)
..setResponse(() => hash);
final result = await HashAlgorithm.sha256.digest(
Uint8List.fromList(
[1, 2, 3],
),
);
expect(
result,
hash,
);
});
});
}

View File

@ -0,0 +1,280 @@
// Author: Hugo Pointcheval
// Email: git@pcl.ovh
// -----
// File: pbkdf2_test.dart
// Created Date: 26/05/2022 22:37:27
// Last Modified: 26/05/2022 23:20:11
// -----
// Copyright (c) 2022
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:native_crypto/native_crypto.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('Constructor', () {
test('throws if keyBytesCount is negative', () {
expect(
() => Pbkdf2(keyBytesCount: -1, iterations: 10000),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_argument',
)
.having(
(e) => e.message,
'message',
contains('must be positive'),
),
),
);
});
test('throws if iterations is negative or 0', () {
expect(
() => Pbkdf2(keyBytesCount: 32, iterations: -1),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_argument',
)
.having(
(e) => e.message,
'message',
contains('must be strictly positive'),
),
),
);
});
});
group('derive', () {
test('throws if password is null', () async {
final pbkdf2 = Pbkdf2(keyBytesCount: 32, iterations: 10000);
await expectLater(
() => pbkdf2.derive(
salt: 'salt',
),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_argument',
)
.having(
(e) => e.message,
'message',
contains('cannot be null'),
),
),
);
});
test('throws if salt is null', () async {
final pbkdf2 = Pbkdf2(keyBytesCount: 32, iterations: 10000);
await expectLater(
() => pbkdf2.derive(
password: 'password',
),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.code,
'code',
'invalid_argument',
)
.having(
(e) => e.message,
'message',
contains('cannot be null'),
),
),
);
});
test('handles returning empty list', () async {
mock
..setPbkdf2Expectations(
password: 'password',
salt: 'salt',
keyBytesCount: 32,
iterations: 10000,
algorithm: 'sha256',
)
..setResponse(() => Uint8List(0));
final pbkdf2 = Pbkdf2(keyBytesCount: 32, iterations: 10000);
await expectLater(
() => pbkdf2.derive(
password: 'password',
salt: 'salt',
),
throwsA(
isA<NativeCryptoException>().having(
(e) => e.code,
'code',
'platform_returned_empty_data',
),
),
);
});
test('handles returning null', () async {
mock
..setPbkdf2Expectations(
password: 'password',
salt: 'salt',
keyBytesCount: 32,
iterations: 10000,
algorithm: 'sha256',
)
..setResponse(() => null);
final pbkdf2 = Pbkdf2(keyBytesCount: 32, iterations: 10000);
await expectLater(
() => pbkdf2.derive(
password: 'password',
salt: 'salt',
),
throwsA(
isA<NativeCryptoException>().having(
(e) => e.code,
'code',
'platform_returned_null',
),
),
);
});
test('handles returning data with wrong length', () async {
mock
..setPbkdf2Expectations(
password: 'password',
salt: 'salt',
keyBytesCount: 32,
iterations: 10000,
algorithm: 'sha256',
)
..setResponse(() => Uint8List(33));
final pbkdf2 = Pbkdf2(keyBytesCount: 32, iterations: 10000);
await expectLater(
() => pbkdf2.derive(
password: 'password',
salt: 'salt',
),
throwsA(
isA<NativeCryptoException>().having(
(e) => e.code,
'code',
'platform_returned_invalid_data',
),
),
);
});
test('handles throwing PlatformException', () async {
mock
..setPbkdf2Expectations(
password: 'password',
salt: 'salt',
keyBytesCount: 32,
iterations: 10000,
algorithm: 'sha256',
)
..setResponse(
() => throw PlatformException(
code: 'native_crypto',
message: 'dummy error',
),
);
final pbkdf2 = Pbkdf2(keyBytesCount: 32, iterations: 10000);
await expectLater(
() => pbkdf2.derive(
password: 'password',
salt: 'salt',
),
throwsA(
isA<NativeCryptoException>()
.having(
(e) => e.message,
'message',
'PlatformException(native_crypto, dummy error, null, null)',
)
.having(
(e) => e.code,
'code',
'platform_throws',
),
),
);
});
test('returns SecretKey on success', () async {
final data = Uint8List.fromList([1, 2, 3, 4, 5, 6]);
final sk = SecretKey(data);
mock
..setPbkdf2Expectations(
password: 'password',
salt: 'salt',
keyBytesCount: 6,
iterations: 10000,
algorithm: 'sha256',
)
..setResponse(() => data);
final pbkdf = Pbkdf2(keyBytesCount: 6, iterations: 10000);
final result = await pbkdf.derive(
password: 'password',
salt: 'salt',
);
expect(
result,
sk,
);
});
test('return empty SecretKey when keyBytesCount is set to 0', () async {
final sk = SecretKey(Uint8List(0));
mock
..setPbkdf2Expectations(
password: 'password',
salt: 'salt',
keyBytesCount: 0,
iterations: 10000,
algorithm: 'sha256',
)
..setResponse(() => Uint8List(0));
final pbkdf = Pbkdf2(keyBytesCount: 0, iterations: 10000);
final result = await pbkdf.derive(
password: 'password',
salt: 'salt',
);
expect(
result,
sk,
);
});
});
}

View File

@ -3,7 +3,7 @@
// -----
// File: secret_key_test.dart
// Created Date: 26/05/2022 10:52:41
// Last Modified: 26/05/2022 19:24:44
// Last Modified: 26/05/2022 22:38:07
// -----
// Copyright (c) 2022
@ -20,6 +20,32 @@ void main() {
final MockNativeCryptoPlatform mock = MockNativeCryptoPlatform();
NativeCryptoPlatform.instance = mock;
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]));
});
});
group('fromSecureRandom', () {
test('handles returning random bytes', () async {
mock
@ -96,30 +122,4 @@ void main() {
);
});
});
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]));
});
});
}