Idgen dart
This commit is contained in:
parent
12a701e1c5
commit
3745b39726
29
.gitignore
vendored
29
.gitignore
vendored
@ -1,27 +1,8 @@
|
||||
# See https://www.dartlang.org/guides/libraries/private-files
|
||||
|
||||
# Files and directories created by pub
|
||||
# https://dart.dev/guides/libraries/private-files
|
||||
# Created by `dart pub`
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
||||
# If you're building an application, you may want to check-in your pubspec.lock
|
||||
|
||||
# Avoid committing pubspec.lock for library packages; see
|
||||
# https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
pubspec.lock
|
||||
|
||||
# Directory created by dartdoc
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
||||
|
||||
# dotenv environment variables file
|
||||
.env*
|
||||
|
||||
# Avoid committing generated Javascript files:
|
||||
*.dart.js
|
||||
*.info.json # Produced by the --dump-info flag.
|
||||
*.js # When generated by dart2js. Don't specify *.js if your
|
||||
# project includes source files written in JavaScript.
|
||||
*.js_
|
||||
*.js.deps
|
||||
*.js.map
|
||||
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
|
3
CHANGELOG.md
Normal file
3
CHANGELOG.md
Normal file
@ -0,0 +1,3 @@
|
||||
## 1.0.0
|
||||
|
||||
- Initial version.
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) [2024] [SticksDev]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
||||
This package allows you to generate unique and random IDs for your Flutter/dart applications using the ID generator provided
|
||||
by [team hydra](https://teamhydra.dev/).
|
||||
|
||||
## Features
|
||||
|
||||
This generator provides the following ID types:
|
||||
|
||||
- UUIDv4 generation
|
||||
- NanoID generation (with and without custom alphabet)
|
||||
- Word generation
|
||||
- 2FA generation
|
||||
- Keypair generation
|
||||
- Snowflake generation (discord-like snowflake)
|
||||
- License key generation
|
||||
|
||||
## Getting started
|
||||
|
||||
You will need a valid username and token to use this package. If you do not have one and would like to use this package, please contact us on our [discord server](https://discord.gg/zira) in the `#other-support` channel and someone will assist you.
|
||||
|
||||
## Usage
|
||||
|
||||
TODO: Include short and useful examples for package users. Add longer examples
|
||||
to `/example` folder.
|
||||
|
||||
```dart
|
||||
const like = 'sample';
|
||||
```
|
1
analysis_options.yaml
Normal file
1
analysis_options.yaml
Normal file
@ -0,0 +1 @@
|
||||
include: package:lints/recommended.yaml
|
11
example/idgen_dart_example.dart
Normal file
11
example/idgen_dart_example.dart
Normal file
@ -0,0 +1,11 @@
|
||||
// Import the package
|
||||
import 'package:teamhydra_idgen/teamhydra_idgen.dart';
|
||||
|
||||
void main() async {
|
||||
IDGen idgen = IDGen(username: 'your_username', token: 'your_token');
|
||||
|
||||
// Generate a new ID, in this example we are generating a UUID V4
|
||||
IDGenResponse uuid =
|
||||
await idgen.generateUUIDV4(); // all generations are async
|
||||
print('Generated UUID: ${uuid.id}'); // print the generated ID
|
||||
}
|
40
lib/src/idgen_dart_base.dart
Normal file
40
lib/src/idgen_dart_base.dart
Normal file
@ -0,0 +1,40 @@
|
||||
/// Response class for IDs generated by IDGen.
|
||||
class IDGenResponse {
|
||||
final String id;
|
||||
|
||||
IDGenResponse({required this.id});
|
||||
|
||||
factory IDGenResponse.fromJson(Map<String, dynamic> json) {
|
||||
return IDGenResponse(
|
||||
id: json['id'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Response class for keypairs generated by IDGen.
|
||||
class IDKeypairResponse implements IDGenResponse {
|
||||
@override
|
||||
final String id;
|
||||
final String privateID;
|
||||
|
||||
IDKeypairResponse({required this.id, required this.privateID});
|
||||
|
||||
factory IDKeypairResponse.fromJson(Map<String, dynamic> json) {
|
||||
return IDKeypairResponse(
|
||||
id: json['id'],
|
||||
privateID: json['privateID'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom exception for IDGen, thrown when an error occurs when generating an ID.
|
||||
class IDGenException implements Exception {
|
||||
final String message;
|
||||
|
||||
IDGenException(this.message);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return message;
|
||||
}
|
||||
}
|
83
lib/src/idgen_http.dart
Normal file
83
lib/src/idgen_http.dart
Normal file
@ -0,0 +1,83 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:teamhydra_idgen/src/idgen_dart_base.dart';
|
||||
|
||||
class IDGenHTTPWorker {
|
||||
final Dio _dio = Dio();
|
||||
final String _baseURL = 'https://id.hydra.workers.dev';
|
||||
|
||||
final String username;
|
||||
final String token;
|
||||
|
||||
IDGenHTTPWorker({required this.username, required this.token});
|
||||
|
||||
Future<IDGenResponse> generate(
|
||||
String type, Map<String, dynamic>? data) async {
|
||||
try {
|
||||
final response = await _dio.post(_baseURL,
|
||||
data: {
|
||||
'username': username,
|
||||
'token': token,
|
||||
'type': type,
|
||||
...?data,
|
||||
},
|
||||
options: Options(contentType: Headers.jsonContentType));
|
||||
|
||||
return IDGenResponse.fromJson(response.data);
|
||||
} on DioException catch (e) {
|
||||
Map<String, dynamic>? errorData;
|
||||
|
||||
// Do we have a response?
|
||||
if (e.response != null) {
|
||||
// Try decoding the response
|
||||
try {
|
||||
errorData = jsonDecode(e.response!.data);
|
||||
} catch (_) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
if (errorData != null && errorData['error'] != null) {
|
||||
throw IDGenException(
|
||||
'Server rejected ID generation: ${errorData['error']}');
|
||||
} else if (errorData != null) {
|
||||
throw IDGenException('Server rejected ID generation: $errorData');
|
||||
} else {
|
||||
throw IDGenException(
|
||||
'An error occurred during generation ($type): ${e.message}');
|
||||
}
|
||||
} catch (e) {
|
||||
throw IDGenException(
|
||||
'An unknown error occurred during generation ($type): $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<IDKeypairResponse> generateKeypair() async {
|
||||
try {
|
||||
final response = await _dio.post(_baseURL,
|
||||
data: {
|
||||
'username': username,
|
||||
'token': token,
|
||||
'type': 'keypair',
|
||||
},
|
||||
options: Options(contentType: Headers.jsonContentType));
|
||||
|
||||
return IDKeypairResponse.fromJson(response.data);
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response?.data;
|
||||
if (errorData != null && errorData['error'] != null) {
|
||||
throw IDGenException(
|
||||
'Server rejected ID generation: ${errorData['error']}');
|
||||
} else if (errorData != null) {
|
||||
throw IDGenException('Server rejected ID generation: $errorData');
|
||||
} else {
|
||||
throw IDGenException(
|
||||
'An error occurred during generation (keypair): ${e.message}');
|
||||
}
|
||||
} catch (e) {
|
||||
throw IDGenException(
|
||||
'An unknown error occurred during generation (keypair): $e');
|
||||
}
|
||||
}
|
||||
}
|
145
lib/src/idgen_main.dart
Normal file
145
lib/src/idgen_main.dart
Normal file
@ -0,0 +1,145 @@
|
||||
import 'package:teamhydra_idgen/src/idgen_http.dart';
|
||||
import 'package:teamhydra_idgen/teamhydra_idgen.dart';
|
||||
|
||||
/// The main class to use when generating an ID
|
||||
///
|
||||
/// All returned IDs are in the form of a [IDGenResponse] object which contains the ID.
|
||||
/// If an error occurs, an [IDGenException] is thrown.
|
||||
class IDGen {
|
||||
final String username;
|
||||
final String token;
|
||||
final IDGenHTTPWorker _worker;
|
||||
|
||||
/// Create a new IDGen class to generate IDs
|
||||
///
|
||||
/// [username] and [token] are required to authenticate with the IDGen API.
|
||||
IDGen({required this.username, required this.token})
|
||||
: _worker = IDGenHTTPWorker(username: username, token: token);
|
||||
|
||||
/// Generate a new UUID V4
|
||||
///
|
||||
/// Returns a [IDGenResponse] object containing the generated ID.
|
||||
/// Throws an [IDGenException] if an error occurs.
|
||||
Future<IDGenResponse> generateUUIDV4() async {
|
||||
return await _worker.generate('uuid', null);
|
||||
}
|
||||
|
||||
/// Generate a new nanoID
|
||||
///
|
||||
/// Returns a [IDGenResponse] object containing the generated ID.
|
||||
/// Optionally, you can pass a [size] parameter to specify the length of the nanoID, default is 10.
|
||||
/// You can also pass a [alphabet] parameter to specify the characters used in the nanoID, default is provided by the API.
|
||||
///
|
||||
/// Throws an [IDGenException] if an error occurs.
|
||||
///
|
||||
/// Throws an [ArgumentError] if the size is not between 1 and 256 or the alphabet is empty.
|
||||
Future<IDGenResponse> generateNanoID({int? size, String? alphabet}) async {
|
||||
// Ensure length is between 1 and 256 (if specified)
|
||||
if (size != null && (size < 1 || size > 256)) {
|
||||
throw ArgumentError(
|
||||
'Cannot generate a nanoID with a length of $size, must be between 1 and 256');
|
||||
}
|
||||
|
||||
// Ensure alphabet is not empty (if specified)
|
||||
if (alphabet != null && alphabet.isEmpty) {
|
||||
throw ArgumentError('Cannot generate a nanoID with an empty alphabet');
|
||||
}
|
||||
|
||||
// Ensure alphabet is at least 3 characters long and not longer than 256
|
||||
if (alphabet != null && (alphabet.length < 3 || alphabet.length > 256)) {
|
||||
throw ArgumentError(
|
||||
'Cannot generate a nanoID with an alphabet of length ${alphabet.length}, must be between 3 and 256');
|
||||
}
|
||||
|
||||
return await _worker.generate('nanoid', {
|
||||
if (size != null) 'length': size else 'length': 10,
|
||||
if (alphabet != null) 'alphabet': alphabet,
|
||||
});
|
||||
}
|
||||
|
||||
/// Generate a 2FA code pair
|
||||
///
|
||||
/// Returns a [IDGenResponse] object containing the generated ID.
|
||||
///
|
||||
/// Optionally, you can pass a [length] parameter to specify the length of the 2FA code, default is 6.
|
||||
///
|
||||
/// Throws an [IDGenException] if an error occurs.
|
||||
///
|
||||
/// Throws an [ArgumentError] if the length is not between 1 and 256.
|
||||
Future<IDGenResponse> generate2FACode({int? length}) async {
|
||||
// Ensure length is between 1 and 256 (if specified)
|
||||
if (length != null && (length < 1 || length > 256)) {
|
||||
throw ArgumentError(
|
||||
'Cannot generate a 2FA code with a length of $length, must be between 1 and 256');
|
||||
}
|
||||
|
||||
return await _worker.generate('2fa', {
|
||||
if (length != null) 'length': length,
|
||||
});
|
||||
}
|
||||
|
||||
/// Generate a license key
|
||||
///
|
||||
/// Returns a [IDGenResponse] object containing the generated ID.
|
||||
/// Keys are generated with a 25 character length, resulting in a 5-5-5-5-5 format.
|
||||
///
|
||||
/// Throws an [IDGenException] if an error occurs.
|
||||
Future<IDGenResponse> generateLicenseKey() async {
|
||||
return await _worker.generate('license', null);
|
||||
}
|
||||
|
||||
/// Generate word based string
|
||||
///
|
||||
/// Returns a [IDGenResponse] object containing the generated ID.
|
||||
/// Optionally, you can pass a [length] parameter to specify the length of the word based string, default is 5.
|
||||
/// You can also pass a [separator] parameter to specify the separator used in the word based string, options are 'slug', 'title' and 'formal'. Default is 'slug'.
|
||||
///
|
||||
/// Slug: lowercase words separated by hyphens
|
||||
///
|
||||
/// Title: Title case words separated by spaces
|
||||
///
|
||||
/// Formal: Title case words with no spaces or separators
|
||||
///
|
||||
/// Throws an [IDGenException] if an error occurs.
|
||||
///
|
||||
/// Throws an [ArgumentError] if the length is not between 1 and 16 or the separator is invalid.
|
||||
Future<IDGenResponse> generateWordBasedString(
|
||||
{int? length, String? separator}) async {
|
||||
// Ensure length is between 1 and 256 (if specified)
|
||||
if (length != null && (length < 1 || length > 16)) {
|
||||
throw ArgumentError(
|
||||
'Cannot generate a word based string with a length of $length, must be between 1 and 16');
|
||||
}
|
||||
|
||||
// Ensure separator is valid (if specified)
|
||||
if (separator != null &&
|
||||
separator != 'slug' &&
|
||||
separator != 'title' &&
|
||||
separator != 'formal') {
|
||||
throw ArgumentError(
|
||||
'Cannot generate a word based string with an invalid separator');
|
||||
}
|
||||
|
||||
return await _worker.generate('word', {
|
||||
if (length != null) 'length': length else 'length': 5,
|
||||
if (separator != null) 'style': separator else 'style': 'slug',
|
||||
});
|
||||
}
|
||||
|
||||
/// Generate a snowflake ID
|
||||
///
|
||||
/// Returns a [IDKeypairResponse] object containing
|
||||
///
|
||||
/// Throws an [IDGenException] if an error occurs.
|
||||
Future<IDGenResponse> generateSnowflakeID() async {
|
||||
return await _worker.generate('snowflake', null);
|
||||
}
|
||||
|
||||
/// Generate a keypair
|
||||
///
|
||||
/// Returns a [IDKeypairResponse] object containing the generated ID and secret key.
|
||||
/// Throws an [IDGenException] if an error occurs.
|
||||
Future<IDKeypairResponse> generateKeypair() async {
|
||||
return await _worker.generateKeypair();
|
||||
}
|
||||
}
|
5
lib/teamhydra_idgen.dart
Normal file
5
lib/teamhydra_idgen.dart
Normal file
@ -0,0 +1,5 @@
|
||||
/// Team Hydra ID Generator Library - Generate unique IDs for your projects, using the IDGen API.
|
||||
library;
|
||||
|
||||
export 'src/idgen_dart_base.dart';
|
||||
export 'src/idgen_main.dart';
|
17
pubspec.yaml
Normal file
17
pubspec.yaml
Normal file
@ -0,0 +1,17 @@
|
||||
name: teamhydra_idgen
|
||||
description: A library for generating unique IDs using Team Hydra's ID generation service.
|
||||
version: 1.0.0
|
||||
repository: https://teamhydra.io/Sticks/idgen-dart
|
||||
|
||||
environment:
|
||||
sdk: ^3.5.4
|
||||
|
||||
# Add regular dependencies here.
|
||||
dependencies:
|
||||
dio: ^5.7.0
|
||||
# path: ^1.8.0
|
||||
|
||||
dev_dependencies:
|
||||
lints: ^4.0.0
|
||||
test: ^1.24.0
|
||||
dotenv: ^4.2.0
|
318
test/idgen_dart_test.dart
Normal file
318
test/idgen_dart_test.dart
Normal file
@ -0,0 +1,318 @@
|
||||
import 'dart:io';
|
||||
import 'package:teamhydra_idgen/teamhydra_idgen.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
Map<String, String> loadRequiredVarsFromEnv() {
|
||||
// Load the .env file from the current directory
|
||||
final currentDir = Directory.current;
|
||||
final envFile = File('${currentDir.path}/.env');
|
||||
|
||||
if (!envFile.existsSync()) {
|
||||
throw Exception(
|
||||
'Could not locate the .env file in the current directory (tried path: ${envFile.path})');
|
||||
}
|
||||
|
||||
final lines = envFile
|
||||
.readAsLinesSync()
|
||||
.where((line) => line.isNotEmpty && !line.startsWith('#'))
|
||||
.toList(); // Filter out empty lines and comments
|
||||
|
||||
String username = '';
|
||||
String token = '';
|
||||
|
||||
// Get the username and token (IDGEN_USERNAME and IDGEN_TOKEN)
|
||||
for (final line in lines) {
|
||||
if (line.startsWith('IDGEN_USERNAME=')) {
|
||||
username = line.split('=')[1].trim();
|
||||
} else if (line.startsWith('IDGEN_TOKEN=')) {
|
||||
token = line.split('=')[1].trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove " from the strings
|
||||
username = username.replaceAll('"', '');
|
||||
token = token.replaceAll('"', '');
|
||||
|
||||
if (username.isEmpty || token.isEmpty) {
|
||||
throw Exception(
|
||||
'IDGEN_USERNAME or IDGEN_TOKEN is missing from the .env file');
|
||||
}
|
||||
|
||||
return {'username': username, 'token': token};
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Load the .env file and get the username and token
|
||||
final env = loadRequiredVarsFromEnv();
|
||||
|
||||
if (env['username'] == null ||
|
||||
env['token'] == null ||
|
||||
env['username']!.isEmpty ||
|
||||
env['token']!.isEmpty) {
|
||||
print('Please provide a valid username and token in the .env file');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
final username = env['username']!;
|
||||
final token = env['token']!;
|
||||
|
||||
print(
|
||||
"[IDGen] Loaded credentials for username: $username and token (last 4): ${token.substring(token.length - 4)} to run tests");
|
||||
|
||||
group('IDGen', () {
|
||||
final idGen = IDGen(username: username, token: token);
|
||||
|
||||
// Ensure it errors when invalid user/token combo is used
|
||||
test('Invalid user/token combo', () async {
|
||||
final idGen = IDGen(username: 'invalid', token: 'invalid');
|
||||
|
||||
try {
|
||||
await idGen.generateUUIDV4();
|
||||
fail('Should have thrown an exception');
|
||||
} on IDGenException catch (e) {
|
||||
expect(e.message,
|
||||
'Server rejected ID generation: Invalid username or token');
|
||||
} catch (e) {
|
||||
fail('Should have thrown an IDGenException');
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure it generates a UUID V4
|
||||
test('Generate UUID V4', () async {
|
||||
final response = await idGen.generateUUIDV4();
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.id.length, 36);
|
||||
});
|
||||
|
||||
// Ensure it generates a nanoID
|
||||
test('Generate nanoID', () async {
|
||||
final response = await idGen.generateNanoID();
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.id.length, 10);
|
||||
});
|
||||
|
||||
// Ensure it generates a nanoID with a custom size
|
||||
test('Generate nanoID with custom size', () async {
|
||||
final response = await idGen.generateNanoID(size: 20);
|
||||
print('[IDGen] Generated nanoID with size 20: ${response.id}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.id.length, 20);
|
||||
});
|
||||
|
||||
// Ensure it generates a nanoID with a custom alphabet
|
||||
test('Generate nanoID with custom alphabet', () async {
|
||||
final response =
|
||||
await idGen.generateNanoID(alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
|
||||
|
||||
print('[IDGen] Generated nanoID with custom alphabet: ${response.id}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.id.length, 10);
|
||||
});
|
||||
|
||||
// All together now
|
||||
test('Generate nanoID with custom size and alphabet', () async {
|
||||
final response = await idGen.generateNanoID(
|
||||
size: 20, alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
|
||||
print(
|
||||
'[IDGen] Generated nanoID with size 20 and custom alphabet: ${response.id}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.id.length, 20);
|
||||
});
|
||||
|
||||
// Ensure it throws an error when generating a nanoID with an empty alphabet
|
||||
test('Generate nanoID with empty alphabet', () async {
|
||||
try {
|
||||
await idGen.generateNanoID(alphabet: '');
|
||||
fail('Should have thrown an exception');
|
||||
} on ArgumentError catch (e) {
|
||||
expect(e.message, 'Cannot generate a nanoID with an empty alphabet');
|
||||
} catch (e) {
|
||||
fail('Should have thrown an ArgumentError');
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure it throws an error when generating a nanoID with an invalid alphabet length
|
||||
test('Generate nanoID with invalid alphabet length', () async {
|
||||
try {
|
||||
await idGen.generateNanoID(alphabet: 'AB');
|
||||
fail('Should have thrown an exception');
|
||||
} on ArgumentError catch (e) {
|
||||
expect(e.message,
|
||||
'Cannot generate a nanoID with an alphabet of length 2, must be between 3 and 256');
|
||||
} catch (e) {
|
||||
fail('Should have thrown an ArgumentError');
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure it throws an error when generating a nanoID with an invalid size
|
||||
test('Generate nanoID with invalid size', () async {
|
||||
try {
|
||||
await idGen.generateNanoID(size: 0);
|
||||
fail('Should have thrown an exception');
|
||||
} on ArgumentError catch (e) {
|
||||
expect(e.message,
|
||||
'Cannot generate a nanoID with a length of 0, must be between 1 and 256');
|
||||
} catch (e) {
|
||||
fail('Should have thrown an ArgumentError');
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure it generates a 2FA code pair
|
||||
test('Generate 2FA code pair', () async {
|
||||
final response = await idGen.generate2FACode();
|
||||
print('[IDGen] Generated 2FA code: ${response.id}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.id.length, 6);
|
||||
});
|
||||
|
||||
// Ensure it generates a 2FA code pair with a custom length
|
||||
test('Generate 2FA code pair with custom length', () async {
|
||||
final response = await idGen.generate2FACode(length: 10);
|
||||
print('[IDGen] Generated 2FA code with length 10: ${response.id}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.id.length, 10);
|
||||
});
|
||||
|
||||
// Ensure it throws an error when generating a 2FA code with an invalid length
|
||||
test('Generate 2FA code pair with invalid length', () async {
|
||||
try {
|
||||
await idGen.generate2FACode(length: 0);
|
||||
fail('Should have thrown an exception');
|
||||
} on ArgumentError catch (e) {
|
||||
expect(e.message,
|
||||
'Cannot generate a 2FA code with a length of 0, must be between 1 and 256');
|
||||
} catch (e) {
|
||||
fail('Should have thrown an ArgumentError');
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure it generates a license key
|
||||
test('Generate license key', () async {
|
||||
final response = await idGen.generateLicenseKey();
|
||||
print('[IDGen] Generated license key: ${response.id}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.id.length, 29);
|
||||
|
||||
// Make sure it follows the 5-5-5-5-5 format
|
||||
final parts = response.id.split('-');
|
||||
expect(parts.length, 5);
|
||||
});
|
||||
|
||||
// Ensure it generates a word based string
|
||||
test('Generate word based string', () async {
|
||||
final response = await idGen.generateWordBasedString();
|
||||
print('[IDGen] Generated word based string: ${response.id}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
});
|
||||
|
||||
// Ensure it generates a word based string with a custom length
|
||||
test('Generate word based string with custom length', () async {
|
||||
final response = await idGen.generateWordBasedString(length: 10);
|
||||
print(
|
||||
'[IDGen] Generated word based string with length 10: ${response.id}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
|
||||
// Should contain -'s as the default separator
|
||||
expect(response.id.contains('-'), isTrue);
|
||||
});
|
||||
|
||||
// Ensure it can generate all separators for word based strings
|
||||
test('Generate word based string with custom separator', () async {
|
||||
final responseSlug =
|
||||
await idGen.generateWordBasedString(separator: 'slug');
|
||||
print(
|
||||
'[IDGen] Generated word based string with slug separator: ${responseSlug.id}');
|
||||
|
||||
final responseTitle =
|
||||
await idGen.generateWordBasedString(separator: 'title');
|
||||
print(
|
||||
'[IDGen] Generated word based string with title separator: ${responseTitle.id}');
|
||||
|
||||
final responseFormal =
|
||||
await idGen.generateWordBasedString(separator: 'formal');
|
||||
print(
|
||||
'[IDGen] Generated word based string with formal separator: ${responseFormal.id}');
|
||||
|
||||
expect(responseSlug.id, isNotNull);
|
||||
expect(responseSlug.id, isNotEmpty);
|
||||
|
||||
expect(responseTitle.id, isNotNull);
|
||||
expect(responseTitle.id, isNotEmpty);
|
||||
|
||||
expect(responseFormal.id, isNotNull);
|
||||
expect(responseFormal.id, isNotEmpty);
|
||||
});
|
||||
});
|
||||
|
||||
// Ensure it errors when a invalid separator is used for word based strings
|
||||
test('Generate word based string with invalid separator', () async {
|
||||
final idGen = IDGen(username: username, token: token);
|
||||
try {
|
||||
await idGen.generateWordBasedString(separator: 'invalid');
|
||||
fail('Should have thrown an exception');
|
||||
} on ArgumentError catch (e) {
|
||||
expect(e.message,
|
||||
'Cannot generate a word based string with an invalid separator');
|
||||
} catch (e) {
|
||||
fail('Should have thrown an ArgumentError');
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure it errors when a invalid length is used for word based strings
|
||||
test('Generate word based string with invalid length', () async {
|
||||
final idGen = IDGen(username: username, token: token);
|
||||
try {
|
||||
await idGen.generateWordBasedString(length: 0);
|
||||
fail('Should have thrown an exception');
|
||||
} on ArgumentError catch (e) {
|
||||
expect(e.message,
|
||||
'Cannot generate a word based string with a length of 0, must be between 1 and 16');
|
||||
} catch (e) {
|
||||
fail('Should have thrown an ArgumentError');
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure it generates a snowflake ID
|
||||
test('Generate snowflake ID', () async {
|
||||
final idGen = IDGen(username: username, token: token);
|
||||
final response = await idGen.generateSnowflakeID();
|
||||
print('[IDGen] Generated snowflake ID: ${response.id}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.id.length, 20);
|
||||
});
|
||||
|
||||
// Ensure it generates a keypair
|
||||
test('Generate keypair', () async {
|
||||
final idGen = IDGen(username: username, token: token);
|
||||
final response = await idGen.generateKeypair();
|
||||
print(
|
||||
'[IDGen] Generated keypair: ${response.id} and secret: ${response.privateID}');
|
||||
|
||||
expect(response.id, isNotNull);
|
||||
expect(response.id, isNotEmpty);
|
||||
expect(response.privateID, isNotNull);
|
||||
expect(response.privateID, isNotEmpty);
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user