add: adding config package
This commit is contained in:
parent
5d53594f08
commit
40168bfe8d
11 changed files with 622 additions and 1 deletions
7
packages/config/.gitignore
vendored
Normal file
7
packages/config/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# https://dart.dev/guides/libraries/private-files
|
||||||
|
# Created by `dart pub`
|
||||||
|
.dart_tool/
|
||||||
|
|
||||||
|
# Avoid committing pubspec.lock for library packages; see
|
||||||
|
# https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||||
|
pubspec.lock
|
3
packages/config/CHANGELOG.md
Normal file
3
packages/config/CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
- Initial version.
|
10
packages/config/LICENSE.md
Normal file
10
packages/config/LICENSE.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
The Laravel Framework is Copyright (c) Taylor Otwell
|
||||||
|
The Fabric Framework is Copyright (c) Vieo, Inc.
|
||||||
|
|
||||||
|
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.
|
130
packages/config/README.md
Normal file
130
packages/config/README.md
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
# Platform Config
|
||||||
|
|
||||||
|
A Dart implementation of Laravel-inspired configuration management for the Protevus platform.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Flexible configuration storage and retrieval
|
||||||
|
- Support for nested configuration keys
|
||||||
|
- Type-safe retrieval methods (string, integer, float, boolean, array)
|
||||||
|
- Implementation of Dart's `Map` interface for familiar usage
|
||||||
|
- Macro system for extending functionality at runtime
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Add this package to your `pubspec.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
platform_config: ^1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run:
|
||||||
|
|
||||||
|
```
|
||||||
|
dart pub get
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Here's a basic example of how to use the `Repository` class:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import 'package:platform_config/platform_config.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
final config = Repository({
|
||||||
|
'app': {
|
||||||
|
'name': 'My App',
|
||||||
|
'debug': true,
|
||||||
|
},
|
||||||
|
'database': {
|
||||||
|
'default': 'mysql',
|
||||||
|
'connections': {
|
||||||
|
'mysql': {
|
||||||
|
'host': 'localhost',
|
||||||
|
'port': 3306,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get a value
|
||||||
|
print(config.get('app.name')); // Output: My App
|
||||||
|
|
||||||
|
// Get a typed value
|
||||||
|
final isDebug = config.boolean('app.debug');
|
||||||
|
print(isDebug); // Output: true
|
||||||
|
|
||||||
|
// Get a nested value
|
||||||
|
final dbPort = config.integer('database.connections.mysql.port');
|
||||||
|
print(dbPort); // Output: 3306
|
||||||
|
|
||||||
|
// Set a value
|
||||||
|
config.set('app.version', '1.0.0');
|
||||||
|
|
||||||
|
// Check if a key exists
|
||||||
|
print(config.has('app.version')); // Output: true
|
||||||
|
|
||||||
|
// Get multiple values
|
||||||
|
final values = config.getMany(['app.name', 'app.debug']);
|
||||||
|
print(values); // Output: {app.name: My App, app.debug: true}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Available Methods
|
||||||
|
|
||||||
|
- `get<T>(String key, [T? defaultValue])`: Get a value by key, optionally specifying a default value.
|
||||||
|
- `set(dynamic key, dynamic value)`: Set a value for a key.
|
||||||
|
- `has(String key)`: Check if a key exists in the configuration.
|
||||||
|
- `string(String key, [String? defaultValue])`: Get a string value.
|
||||||
|
- `integer(String key, [int? defaultValue])`: Get an integer value.
|
||||||
|
- `float(String key, [double? defaultValue])`: Get a float value.
|
||||||
|
- `boolean(String key, [bool? defaultValue])`: Get a boolean value.
|
||||||
|
- `array(String key, [List<dynamic>? defaultValue])`: Get an array value.
|
||||||
|
- `getMany(List<String> keys)`: Get multiple values at once.
|
||||||
|
- `all()`: Get all configuration items.
|
||||||
|
- `prepend(String key, dynamic value)`: Prepend a value to an array.
|
||||||
|
- `push(String key, dynamic value)`: Append a value to an array.
|
||||||
|
|
||||||
|
The `Repository` class also implements Dart's `Map` interface, so you can use it like a regular map:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
config['new.key'] = 'new value';
|
||||||
|
print(config['new.key']); // Output: new value
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The type-safe methods (`string()`, `integer()`, `float()`, `boolean()`, `array()`) will throw an `ArgumentError` if the value at the specified key is not of the expected type.
|
||||||
|
|
||||||
|
## Extending Functionality
|
||||||
|
|
||||||
|
You can extend the `Repository` class with custom methods using the macro system:
|
||||||
|
|
||||||
|
```dart
|
||||||
|
Repository.macro('getConnectionUrl', (Repository repo, String connection) {
|
||||||
|
final conn = repo.get('database.connections.$connection');
|
||||||
|
return 'mysql://${conn['username']}:${conn['password']}@${conn['host']}:${conn['port']}/${conn['database']}';
|
||||||
|
});
|
||||||
|
|
||||||
|
final config = Repository(/* ... */);
|
||||||
|
final mysqlUrl = config.callMacro('getConnectionUrl', ['mysql']);
|
||||||
|
print(mysqlUrl); // Output: mysql://user:password@localhost:3306/dbname
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
To run the tests for this package, use the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
dart test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the MIT License.
|
30
packages/config/analysis_options.yaml
Normal file
30
packages/config/analysis_options.yaml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# This file configures the static analysis results for your project (errors,
|
||||||
|
# warnings, and lints).
|
||||||
|
#
|
||||||
|
# This enables the 'recommended' set of lints from `package:lints`.
|
||||||
|
# This set helps identify many issues that may lead to problems when running
|
||||||
|
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
|
||||||
|
# style and format.
|
||||||
|
#
|
||||||
|
# If you want a smaller set of lints you can change this to specify
|
||||||
|
# 'package:lints/core.yaml'. These are just the most critical lints
|
||||||
|
# (the recommended set includes the core lints).
|
||||||
|
# The core lints are also what is used by pub.dev for scoring packages.
|
||||||
|
|
||||||
|
include: package:lints/recommended.yaml
|
||||||
|
|
||||||
|
# Uncomment the following section to specify additional rules.
|
||||||
|
|
||||||
|
# linter:
|
||||||
|
# rules:
|
||||||
|
# - camel_case_types
|
||||||
|
|
||||||
|
# analyzer:
|
||||||
|
# exclude:
|
||||||
|
# - path/to/excluded/files/**
|
||||||
|
|
||||||
|
# For more information about the core and recommended set of lints, see
|
||||||
|
# https://dart.dev/go/core-lints
|
||||||
|
|
||||||
|
# For additional information about configuring this file, see
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
104
packages/config/example/config_example.dart
Normal file
104
packages/config/example/config_example.dart
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import 'package:platform_config/platform_config.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// Create a new Repository instance with some initial configuration
|
||||||
|
final config = Repository({
|
||||||
|
'app': {
|
||||||
|
'name': 'Protevus Demo App',
|
||||||
|
'version': '1.0.0',
|
||||||
|
'debug': true,
|
||||||
|
},
|
||||||
|
'database': {
|
||||||
|
'default': 'mysql',
|
||||||
|
'connections': {
|
||||||
|
'mysql': {
|
||||||
|
'host': 'localhost',
|
||||||
|
'port': 3306,
|
||||||
|
'database': 'protevus_demo',
|
||||||
|
'username': 'demo_user',
|
||||||
|
'password': 'secret',
|
||||||
|
},
|
||||||
|
'redis': {
|
||||||
|
'host': 'localhost',
|
||||||
|
'port': 6379,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'cache': {
|
||||||
|
'default': 'redis',
|
||||||
|
'stores': {
|
||||||
|
'redis': {
|
||||||
|
'driver': 'redis',
|
||||||
|
'connection': 'default',
|
||||||
|
},
|
||||||
|
'file': {
|
||||||
|
'driver': 'file',
|
||||||
|
'path': '/tmp/cache',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'logging': {
|
||||||
|
'channels': ['file', 'console'],
|
||||||
|
'level': 'info',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Demonstrate usage of various methods
|
||||||
|
print('Application Name: ${config.string('app.name')}');
|
||||||
|
print('Debug Mode: ${config.boolean('app.debug') ? 'Enabled' : 'Disabled'}');
|
||||||
|
|
||||||
|
// Using get with a default value
|
||||||
|
print('API Version: ${config.get('app.api_version', 'v1')}');
|
||||||
|
|
||||||
|
// Accessing nested configuration
|
||||||
|
final dbConfig = config.get('database.connections.mysql');
|
||||||
|
print('Database Configuration:');
|
||||||
|
print(' Host: ${dbConfig['host']}');
|
||||||
|
print(' Port: ${dbConfig['port']}');
|
||||||
|
print(' Database: ${dbConfig['database']}');
|
||||||
|
|
||||||
|
// Using type-specific getters
|
||||||
|
final redisPort = config.integer('database.connections.redis.port');
|
||||||
|
print('Redis Port: $redisPort');
|
||||||
|
|
||||||
|
// Checking for existence of a key
|
||||||
|
if (config.has('cache.stores.memcached')) {
|
||||||
|
print('Memcached configuration exists');
|
||||||
|
} else {
|
||||||
|
print('Memcached configuration does not exist');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting a new value
|
||||||
|
config.set('app.timezone', 'UTC');
|
||||||
|
print('Timezone: ${config.string('app.timezone')}');
|
||||||
|
|
||||||
|
// Getting multiple values at once
|
||||||
|
final loggingConfig = config.getMany(['logging.channels', 'logging.level']);
|
||||||
|
print('Logging Configuration:');
|
||||||
|
print(' Channels: ${loggingConfig['logging.channels']}');
|
||||||
|
print(' Level: ${loggingConfig['logging.level']}');
|
||||||
|
|
||||||
|
// Using array method
|
||||||
|
final logChannels = config.array('logging.channels');
|
||||||
|
print('Log Channels: $logChannels');
|
||||||
|
|
||||||
|
// Demonstrating error handling
|
||||||
|
try {
|
||||||
|
config.integer('app.name');
|
||||||
|
} catch (e) {
|
||||||
|
print('Error: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using the Repository as a Map
|
||||||
|
config['new.feature.enabled'] = true;
|
||||||
|
print('New Feature Enabled: ${config['new.feature.enabled']}');
|
||||||
|
|
||||||
|
// Demonstrating Macroable functionality
|
||||||
|
Repository.macro('getConnectionUrl', (Repository repo, String connection) {
|
||||||
|
final conn = repo.get('database.connections.$connection');
|
||||||
|
return 'mysql://${conn['username']}:${conn['password']}@${conn['host']}:${conn['port']}/${conn['database']}';
|
||||||
|
});
|
||||||
|
|
||||||
|
final mysqlUrl = config.callMacro('getConnectionUrl', ['mysql']);
|
||||||
|
print('MySQL Connection URL: $mysqlUrl');
|
||||||
|
}
|
3
packages/config/lib/platform_config.dart
Normal file
3
packages/config/lib/platform_config.dart
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
library platform_config;
|
||||||
|
|
||||||
|
export 'src/repository.dart';
|
206
packages/config/lib/src/repository.dart
Normal file
206
packages/config/lib/src/repository.dart
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
import 'package:platform_contracts/contracts.dart';
|
||||||
|
import 'package:platform_collections/collections.dart';
|
||||||
|
|
||||||
|
class Repository implements ConfigContract, Map<String, dynamic> {
|
||||||
|
static final Map<String, Function> _macros = {};
|
||||||
|
|
||||||
|
final Map<String, dynamic> _items;
|
||||||
|
|
||||||
|
Repository([Map<String, dynamic> items = const {}])
|
||||||
|
: _items = Map.from(items);
|
||||||
|
|
||||||
|
static void macro(String name, Function macro) {
|
||||||
|
_macros[name] = macro;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool has(String key) {
|
||||||
|
return Arr.has(_items, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
T? get<T>(String key, [T? defaultValue]) {
|
||||||
|
final value = Arr.get(_items, key);
|
||||||
|
if (value is T) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> getMany(List<String> keys) {
|
||||||
|
return Map.fromEntries(keys.map((key) => MapEntry(key, get(key))));
|
||||||
|
}
|
||||||
|
|
||||||
|
String string(String key, [String? defaultValue]) {
|
||||||
|
final value = get<dynamic>(key);
|
||||||
|
if (value is String) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (value == null && defaultValue != null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
throw ArgumentError(
|
||||||
|
'Configuration value for key [$key] must be a string, ${value.runtimeType} given.');
|
||||||
|
}
|
||||||
|
|
||||||
|
int integer(String key, [int? defaultValue]) {
|
||||||
|
final value = get<dynamic>(key);
|
||||||
|
if (value is int) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (value == null && defaultValue != null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
throw ArgumentError(
|
||||||
|
'Configuration value for key [$key] must be an integer, ${value.runtimeType} given.');
|
||||||
|
}
|
||||||
|
|
||||||
|
double float(String key, [double? defaultValue]) {
|
||||||
|
final value = get<dynamic>(key);
|
||||||
|
if (value is double) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (value == null && defaultValue != null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
throw ArgumentError(
|
||||||
|
'Configuration value for key [$key] must be a double, ${value.runtimeType} given.');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(String key, [bool? defaultValue]) {
|
||||||
|
final value = get<dynamic>(key);
|
||||||
|
if (value is bool) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (value == null && defaultValue != null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
throw ArgumentError(
|
||||||
|
'Configuration value for key [$key] must be a boolean, ${value.runtimeType} given.');
|
||||||
|
}
|
||||||
|
|
||||||
|
List<dynamic> array(String key, [List<dynamic>? defaultValue]) {
|
||||||
|
final value = get<dynamic>(key);
|
||||||
|
if (value is List) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (value == null && defaultValue != null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
throw ArgumentError(
|
||||||
|
'Configuration value for key [$key] must be a List, ${value.runtimeType} given.');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void set(dynamic key, dynamic value) {
|
||||||
|
Arr.set(_items, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void prepend(String key, dynamic value) {
|
||||||
|
final list = array(key, []);
|
||||||
|
list.insert(0, value);
|
||||||
|
set(key, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void push(String key, dynamic value) {
|
||||||
|
final list = array(key, []);
|
||||||
|
list.add(value);
|
||||||
|
set(key, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> all() => Map.from(_items);
|
||||||
|
|
||||||
|
// Implement Map interface
|
||||||
|
@override
|
||||||
|
dynamic operator [](Object? key) => get(key as String);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void operator []=(String key, dynamic value) => set(key, value);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void clear() => _items.clear();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<String> get keys => _items.keys;
|
||||||
|
|
||||||
|
@override
|
||||||
|
dynamic remove(Object? key) => _items.remove(key);
|
||||||
|
|
||||||
|
// Other Map interface methods...
|
||||||
|
@override
|
||||||
|
void addAll(Map<String, dynamic> other) => other.forEach(set);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addEntries(Iterable<MapEntry<String, dynamic>> newEntries) {
|
||||||
|
for (final entry in newEntries) {
|
||||||
|
set(entry.key, entry.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<RK, RV> cast<RK, RV>() => _items.cast<RK, RV>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool containsKey(Object? key) => has(key as String);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool containsValue(Object? value) => _items.containsValue(value);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<MapEntry<String, dynamic>> get entries => _items.entries;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void forEach(void Function(String key, dynamic value) action) {
|
||||||
|
_items.forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isEmpty => _items.isEmpty;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isNotEmpty => _items.isNotEmpty;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get length => _items.length;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<K2, V2> map<K2, V2>(
|
||||||
|
MapEntry<K2, V2> Function(String key, dynamic value) convert) {
|
||||||
|
return _items.map(convert);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
dynamic putIfAbsent(String key, dynamic Function() ifAbsent) {
|
||||||
|
return _items.putIfAbsent(key, ifAbsent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void removeWhere(bool Function(String key, dynamic value) test) {
|
||||||
|
_items.removeWhere(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
dynamic update(String key, dynamic Function(dynamic value) update,
|
||||||
|
{dynamic Function()? ifAbsent}) {
|
||||||
|
return _items.update(key, update, ifAbsent: ifAbsent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void updateAll(dynamic Function(String key, dynamic value) update) {
|
||||||
|
_items.updateAll(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<dynamic> get values => _items.values;
|
||||||
|
|
||||||
|
dynamic callMacro(String name, List<dynamic> arguments) {
|
||||||
|
if (_macros.containsKey(name)) {
|
||||||
|
return Function.apply(_macros[name]!, [this, ...arguments]);
|
||||||
|
}
|
||||||
|
throw NoSuchMethodError.withInvocation(
|
||||||
|
this, Invocation.method(Symbol(name), arguments));
|
||||||
|
}
|
||||||
|
}
|
18
packages/config/pubspec.yaml
Normal file
18
packages/config/pubspec.yaml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
name: platform_config
|
||||||
|
description: A Dart implementation of Laravel's Config package for the Protevus platform.
|
||||||
|
version: 1.0.0
|
||||||
|
homepage: https://protevus.com
|
||||||
|
documentation: https://docs.protevus.com
|
||||||
|
repository: https://github.com/protevus/platformo
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
platform_contracts: ^1.0.0
|
||||||
|
platform_collections: ^1.0.0
|
||||||
|
platform_macroable: ^1.0.0
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
test: ^1.16.0
|
||||||
|
lints: ^2.0.0
|
110
packages/config/test/repository_test.dart
Normal file
110
packages/config/test/repository_test.dart
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import 'package:platform_config/src/repository.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late Repository config;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
config = Repository({
|
||||||
|
'app': {
|
||||||
|
'name': 'My App',
|
||||||
|
'debug': true,
|
||||||
|
},
|
||||||
|
'database': {
|
||||||
|
'default': 'mysql',
|
||||||
|
'connections': {
|
||||||
|
'mysql': {
|
||||||
|
'host': 'localhost',
|
||||||
|
'port': 3306,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'numbers': [1, 2, 3, 4, 5],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Repository', () {
|
||||||
|
test('has() returns correct boolean for existing and non-existing keys',
|
||||||
|
() {
|
||||||
|
expect(config.has('app.name'), isTrue);
|
||||||
|
expect(config.has('app.non_existent'), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get() returns correct values for existing keys', () {
|
||||||
|
expect(config.get('app.name'), equals('My App'));
|
||||||
|
expect(config.get('database.connections.mysql.port'), equals(3306));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get() returns default value for non-existing keys', () {
|
||||||
|
expect(config.get('non_existent', 'default'), equals('default'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string() returns correct string value', () {
|
||||||
|
expect(config.string('app.name'), equals('My App'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('string() throws ArgumentError for non-string values', () {
|
||||||
|
expect(() => config.string('app.debug'), throwsArgumentError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('integer() returns correct integer value', () {
|
||||||
|
expect(config.integer('database.connections.mysql.port'), equals(3306));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('integer() throws ArgumentError for non-integer values', () {
|
||||||
|
expect(() => config.integer('app.name'), throwsArgumentError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('boolean() returns correct boolean value', () {
|
||||||
|
expect(config.boolean('app.debug'), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('boolean() throws ArgumentError for non-boolean values', () {
|
||||||
|
expect(() => config.boolean('app.name'), throwsArgumentError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('array() returns correct list value', () {
|
||||||
|
expect(config.array('numbers'), equals([1, 2, 3, 4, 5]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('array() throws ArgumentError for non-list values', () {
|
||||||
|
expect(() => config.array('app.name'), throwsArgumentError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('set() correctly sets a new value', () {
|
||||||
|
config.set('new.key', 'new value');
|
||||||
|
expect(config.get('new.key'), equals('new value'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('prepend() correctly prepends a value to an array', () {
|
||||||
|
config.prepend('numbers', 0);
|
||||||
|
expect(config.array('numbers'), equals([0, 1, 2, 3, 4, 5]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('push() correctly appends a value to an array', () {
|
||||||
|
config.push('numbers', 6);
|
||||||
|
expect(config.array('numbers'), equals([1, 2, 3, 4, 5, 6]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('all() returns all config items', () {
|
||||||
|
expect(
|
||||||
|
config.all(),
|
||||||
|
equals({
|
||||||
|
'app': {
|
||||||
|
'name': 'My App',
|
||||||
|
'debug': true,
|
||||||
|
},
|
||||||
|
'database': {
|
||||||
|
'default': 'mysql',
|
||||||
|
'connections': {
|
||||||
|
'mysql': {
|
||||||
|
'host': 'localhost',
|
||||||
|
'port': 3306,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'numbers': [1, 2, 3, 4, 5],
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
/// This contract defines the standard way to interact with configuration values
|
/// This contract defines the standard way to interact with configuration values
|
||||||
/// in the application. It provides methods to get, set, and manipulate
|
/// in the application. It provides methods to get, set, and manipulate
|
||||||
/// configuration values in a consistent manner.
|
/// configuration values in a consistent manner.
|
||||||
abstract class Repository {
|
abstract class ConfigContract {
|
||||||
/// Determine if the given configuration value exists.
|
/// Determine if the given configuration value exists.
|
||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
|
|
Loading…
Reference in a new issue