Skip to content

Commit

Permalink
feat: start adding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
alestiago committed Jul 10, 2024
1 parent a5c0c18 commit dc0780a
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 29 deletions.
17 changes: 11 additions & 6 deletions very_good_core/hooks/lib/src/models/android_application_id.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@ extension type AndroidApplicationId(String value) {
required String organizationName,
required String projectName,
}) {
return AndroidApplicationId(
'${organizationName.snakeCase}.${projectName.snakeCase}',
);
final segments = <String>[];
for (final segment in organizationName.split('.')) {
if (segment.isEmpty) continue;
segments.add(segment.snakeCase);
}
segments.add(projectName.snakeCase);

return AndroidApplicationId(segments.join('.'));
}

/// Checks if the provided [applicationId] is valid, returning `true` if it is
/// Checks if the [AndroidApplicationId] is valid, returning `true` if it is
/// and `false` otherwise.
///
/// Although the application ID looks like a traditional Kotlin or Java
Expand All @@ -39,8 +44,8 @@ extension type AndroidApplicationId(String value) {
/// See also:
///
/// * [Set the application ID Android documentation](https://developer.android.com/build/configure-app-module#set-application-id)
static bool isValid(AndroidApplicationId applicationId) {
final segments = applicationId.value.split('.');
bool get isValid {
final segments = value.split('.');
if (segments.length < 2) {
// It must have at least two segments (one or more dots).
return false;
Expand Down
11 changes: 8 additions & 3 deletions very_good_core/hooks/lib/src/models/ios_application_id.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ extension type IosApplicationId(String value) {
required String organizationName,
required String projectName,
}) {
return IosApplicationId(
'${organizationName.paramCase}.${projectName.paramCase}',
);
final parts = <String>[];
for (final part in organizationName.split('.')) {
if (part.isEmpty) continue;
parts.add(part.paramCase);
}
parts.add(projectName.paramCase);

return IosApplicationId(parts.join('.'));
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:equatable/equatable.dart';
import 'package:very_good_core_hooks/very_good_core_hooks.dart';

/// The variables specified by this hook.
Expand Down Expand Up @@ -49,7 +50,7 @@ enum _VeryGoodCoreConfigurationVariables {
/// {@template very_good_core_configuration}
/// Configuration for the `very_good_core` brick.
/// {@endtemplate}
class VeryGoodCoreConfiguration {
class VeryGoodCoreConfiguration extends Equatable {
/// {@macro very_good_core_configuration}
VeryGoodCoreConfiguration({
String? projectName,
Expand Down Expand Up @@ -77,52 +78,53 @@ class VeryGoodCoreConfiguration {
organizationName: this.organizationName,
projectName: this.projectName,
);
if (!AndroidApplicationId.isValid(this.androidApplicationId)) {
if (!this.androidApplicationId.isValid) {
throw InvalidAndroidApplicationIdFormat(this.androidApplicationId);
}

this.androidNamespace = androidNamespace ??
AndroidNamespace.fromApplicationId(this.androidApplicationId);
}

/// Deserializes a [VeryGoodCoreConfiguration] from a `Map<String, dynamic>`.
factory VeryGoodCoreConfiguration.fromJson(Map<String, dynamic> json) {
/// Deserializes a [VeryGoodCoreConfiguration] from a `Map<String, dynamic>`
/// used to represent the configuration in the `HookContext.vars` map.
factory VeryGoodCoreConfiguration.fromHooksVars(Map<String, dynamic> vars) {
final projectName =
json[_VeryGoodCoreConfigurationVariables.projectName.key];
vars[_VeryGoodCoreConfigurationVariables.projectName.key];
if (projectName is! String?) {
throw ArgumentError.value(
json,
'json',
vars,
'vars',
'''Expected a value for key "${_VeryGoodCoreConfigurationVariables.projectName.key}" to be of type String?, got $projectName.''',
);
}

final organizationName =
json[_VeryGoodCoreConfigurationVariables.organizationName.key];
vars[_VeryGoodCoreConfigurationVariables.organizationName.key];
if (organizationName is! String?) {
throw ArgumentError.value(
json,
'json',
vars,
'vars',
'''Expected a value for key "${_VeryGoodCoreConfigurationVariables.organizationName.key}" to be of type String?, got $organizationName.''',
);
}

final applicationId =
json[_VeryGoodCoreConfigurationVariables.applicationId.key];
vars[_VeryGoodCoreConfigurationVariables.applicationId.key];
if (applicationId is! String?) {
throw ArgumentError.value(
json,
'json',
vars,
'vars',
'''Expected a value for key "${_VeryGoodCoreConfigurationVariables.applicationId.key}" to be of type String?, got $applicationId.''',
);
}

final description =
json[_VeryGoodCoreConfigurationVariables.description.key];
vars[_VeryGoodCoreConfigurationVariables.description.key];
if (description is! String?) {
throw ArgumentError.value(
json,
'json',
vars,
'vars',
'''Expected a value for key "${_VeryGoodCoreConfigurationVariables.description.key}" to be of type String?, got $description.''',
);
}
Expand Down Expand Up @@ -160,4 +162,15 @@ class VeryGoodCoreConfiguration {

/// {@macro android_application_id}
late final AndroidApplicationId androidApplicationId;

@override
List<Object?> get props => [
projectName,
organizationName,
description,
windowsApplicationId,
iosApplicationId,
androidNamespace,
androidApplicationId,
];
}
11 changes: 8 additions & 3 deletions very_good_core/hooks/lib/src/models/windows_application_id.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ extension type WindowsApplicationId(String value) {
required String organizationName,
required String projectName,
}) {
return WindowsApplicationId(
'${organizationName.paramCase}.${projectName.paramCase}',
);
final parts = <String>[];
for (final part in organizationName.split('.')) {
if (part.isEmpty) continue;
parts.add(part.paramCase);
}
parts.add(projectName.paramCase);

return WindowsApplicationId(parts.join('.'));
}
}
2 changes: 1 addition & 1 deletion very_good_core/hooks/pre_gen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:mason/mason.dart';
import 'package:very_good_core_hooks/very_good_core_hooks.dart';

void run(HookContext context) {
final configuration = VeryGoodCoreConfiguration.fromJson(context.vars);
final configuration = VeryGoodCoreConfiguration.fromHooksVars(context.vars);

context.vars = {
/// Below are all the variables that are accessible in the templates.
Expand Down
1 change: 1 addition & 0 deletions very_good_core/hooks/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ environment:
sdk: ^3.4.0

dependencies:
equatable: ^2.0.5
mason: ^0.1.0-dev.52

dev_dependencies:
Expand Down
24 changes: 24 additions & 0 deletions very_good_core/hooks/test/pre_gen_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,30 @@ void main() {
context = _MockHookContext();
});

test('populates variables', () {
final vars = {
'project_name': 'my_app',
'org_name': 'com.example',
'application_id': 'app_id',
'description': 'A new Flutter project.',
};
when(() => context.vars).thenReturn(vars);

pre_gen.run(context);

expect(
context.vars,
{
'project_name': 'my_app',
'org_name': 'com.example',
'application_id': 'app_id',
'description': 'A new Flutter project.',
'application_id_android': 'com.example.my_app',
'application_id': 'com.example.my-app',
},
);
});

group('application_id_android', () {
test('when specified is unmodified', () {
final vars = <String, String>{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import 'package:test/test.dart';
import 'package:very_good_core_hooks/very_good_core_hooks.dart';

void main() {
group('$AndroidApplicationId', () {
group('fallback', () {
test(
'concatenates organization name with project name in snake case',
() {
const organizationName = 'com.example.hello-world';
const projectName = 'my app';
final androidApplicationId = AndroidApplicationId.fallback(
organizationName: organizationName,
projectName: projectName,
);
expect(androidApplicationId.value, 'com.example.hello_world.my_app');
},
);

test(
'ignores empty segments',
() {
const organizationName = 'com..example..hello-world';
const projectName = 'my app';
final androidApplicationId = AndroidApplicationId.fallback(
organizationName: organizationName,
projectName: projectName,
);
expect(androidApplicationId.value, 'com.example.hello_world.my_app');
},
);
});

group('isValid', () {
group('returns true', () {
test('when Android ID is valid', () {
final androidApplicationId = AndroidApplicationId('com.example.app');
expect(androidApplicationId.isValid, isTrue);
});
});

group('returns false', () {
test('when Android ID has less than two segments', () {
final androidApplicationId = AndroidApplicationId('com');
expect(androidApplicationId.isValid, isFalse);
});

test('when Android ID has a segment that starts with a non-letter', () {
final androidApplicationId = AndroidApplicationId('1com.example.app');
expect(androidApplicationId.isValid, isFalse);
});

test('when Android ID has a segment with a special character', () {
final androidApplicationId = AndroidApplicationId('com.example.app!');
expect(androidApplicationId.isValid, isFalse);
});
});
});
});
}
Loading

0 comments on commit dc0780a

Please sign in to comment.