diff --git a/packages/core/lib/settings/config.dart b/packages/core/lib/settings/config.dart index 68cacd18..682787c0 100644 --- a/packages/core/lib/settings/config.dart +++ b/packages/core/lib/settings/config.dart @@ -105,7 +105,7 @@ Config loadPubspecConfig(File pubspecFile, {File? buildFile}) { final pubspec = Pubspec.fromJson(mergedMap); final pubspecLockFile = File( - normalize(join(basename(pubspecFile.parent.path), 'pubspec.lock')), + normalize(join(pubspecFile.parent.path, 'pubspec.lock')), ); final pubspecLockContent = switch (pubspecLockFile.existsSync()) { true => pubspecLockFile.readAsStringSync(), @@ -130,7 +130,7 @@ Config loadPubspecConfig(File pubspecFile, {File? buildFile}) { } final analysisOptionsFile = File( - normalize(join(basename(pubspecFile.parent.path), 'analysis_options.yaml')), + normalize(join(pubspecFile.parent.path, 'analysis_options.yaml')), ); final analysisOptionsContent = switch (analysisOptionsFile.existsSync()) { true => analysisOptionsFile.readAsStringSync(), diff --git a/packages/core/test/assets_gen_integrations_test.dart b/packages/core/test/assets_gen_integrations_test.dart index dd397d7e..e96b7bf2 100644 --- a/packages/core/test/assets_gen_integrations_test.dart +++ b/packages/core/test/assets_gen_integrations_test.dart @@ -459,5 +459,79 @@ void main() { isTrue, ); }); + + test('Integration version resolution in AssetsGenConfig', () { + // Test that version resolution is properly integrated into assets generation + // This validates the full flow from config loading to integration creation + + // Create a RiveIntegration with both resolved version and constraint + // When resolvedVersion is 0.13.0 (< 0.14.0), it should use Classic + // even if resolvedVersionConstraint would allow 0.14.0 + final integrationWithBoth = RiveIntegration( + '', + resolvedVersion: Version(0, 13, 0), + resolvedVersionConstraint: VersionConstraint.parse('^0.14.0'), + ); + // resolvedVersion takes priority: 0.13.0 < 0.14.0 => Classic + expect(integrationWithBoth, isA()); + + // Create a RiveIntegration with only resolvedVersion + final integrationVersionOnly = RiveIntegration( + '', + resolvedVersion: Version(0, 14, 0), + ); + expect(integrationVersionOnly, isA()); + + // Create a RiveIntegration with only resolvedVersionConstraint + final integrationConstraintOnly = RiveIntegration( + '', + resolvedVersionConstraint: VersionConstraint.parse('^0.14.0'), + ); + expect(integrationConstraintOnly, isA()); + }); + + test('Version resolution with various constraint formats', () { + // Test with ^0.13.x constraint (should use Classic) + final caretOld = RiveIntegration( + '', + resolvedVersionConstraint: VersionConstraint.parse('^0.13.5'), + ); + expect(caretOld, isA()); + + // Test with ^0.14.x constraint (should use 0140) + final caretNew = RiveIntegration( + '', + resolvedVersionConstraint: VersionConstraint.parse('^0.14.1'), + ); + expect(caretNew, isA()); + + // Test with >= constraint that includes 0.14.0 + final rangeIncludesNew = RiveIntegration( + '', + resolvedVersionConstraint: VersionConstraint.parse('>=0.13.0 <1.0.0'), + ); + expect(rangeIncludesNew, isA()); + + // Test with >= constraint that excludes 0.14.0 + final rangeExcludesNew = RiveIntegration( + '', + resolvedVersionConstraint: VersionConstraint.parse('>=0.13.0 <0.14.0'), + ); + expect(rangeExcludesNew, isA()); + + // Test with exact version < 0.14.0 + final exactOld = RiveIntegration( + '', + resolvedVersion: Version(0, 13, 99), + ); + expect(exactOld, isA()); + + // Test with exact version >= 0.14.0 + final exactNew = RiveIntegration( + '', + resolvedVersion: Version(0, 14, 0), + ); + expect(exactNew, isA()); + }); }); } diff --git a/packages/core/test/config_test.dart b/packages/core/test/config_test.dart new file mode 100644 index 00000000..7f4baabb --- /dev/null +++ b/packages/core/test/config_test.dart @@ -0,0 +1,231 @@ +import 'dart:io'; + +import 'package:flutter_gen_core/generators/integrations/lottie_integration.dart'; +import 'package:flutter_gen_core/generators/integrations/rive_integration.dart'; +import 'package:flutter_gen_core/generators/integrations/svg_integration.dart'; +import 'package:flutter_gen_core/generators/registry.dart'; +import 'package:flutter_gen_core/settings/config.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:test/test.dart'; + +void main() { + group('Config integration version resolution', () { + test('resolves versions from pubspec.lock', () { + final pubspecFile = File( + 'test_resources/integration_versions/pubspec.yaml', + ); + final config = loadPubspecConfig(pubspecFile); + + // Check that versions are resolved from pubspec.lock + expect( + config.integrationResolvedVersions[RiveIntegration], + equals(Version(0, 13, 5)), + ); + expect( + config.integrationResolvedVersions[SvgIntegration], + equals(Version(2, 0, 9)), + ); + expect( + config.integrationResolvedVersions[LottieIntegration], + equals(Version(5, 1, 0)), + ); + }); + + test('resolves version constraints from pubspec.yaml', () { + final pubspecFile = File( + 'test_resources/integration_versions/pubspec.yaml', + ); + final config = loadPubspecConfig(pubspecFile); + + // Check that constraints are resolved from pubspec.yaml + expect( + config.integrationVersionConstraints[RiveIntegration], + equals(VersionConstraint.parse('^0.13.0')), + ); + expect( + config.integrationVersionConstraints[SvgIntegration], + equals(VersionConstraint.parse('^2.0.0')), + ); + expect( + config.integrationVersionConstraints[LottieIntegration], + equals(VersionConstraint.parse('^5.0.0')), + ); + }); + + test('resolves Rive 0.14.0 versions correctly', () { + final pubspecFile = File( + 'test_resources/integration_versions_rive_014/pubspec.yaml', + ); + final config = loadPubspecConfig(pubspecFile); + + // Check that Rive 0.14.0+ version is resolved + expect( + config.integrationResolvedVersions[RiveIntegration], + equals(Version(0, 14, 1)), + ); + expect( + config.integrationVersionConstraints[RiveIntegration], + equals(VersionConstraint.parse('^0.14.0')), + ); + + // Check that flutter_svg is also resolved + expect( + config.integrationResolvedVersions[SvgIntegration], + equals(Version(2, 0, 10)), + ); + expect( + config.integrationVersionConstraints[SvgIntegration], + equals(VersionConstraint.parse('>=2.0.0 <3.0.0')), + ); + }); + + test('handles missing pubspec.lock gracefully', () { + // Use a pubspec without a corresponding .lock file + final pubspecFile = File( + 'test_resources/pubspec_assets_rive_integrations.yaml', + ); + final config = loadPubspecConfig(pubspecFile); + + // Should have empty or no resolved versions + // but should not crash + expect(config, isNotNull); + expect(config.integrationResolvedVersions, isA()); + expect(config.integrationVersionConstraints, isA()); + }); + + test('verifies only expected integration types are present', () { + final pubspecFile = File( + 'test_resources/integration_versions/pubspec.yaml', + ); + final config = loadPubspecConfig(pubspecFile); + + // Verify that only integration types from the registry are in the maps + final expectedTypes = integrationPackages.keys.toList(); + + for (final key in config.integrationVersionConstraints.keys) { + expect( + expectedTypes.contains(key), + isTrue, + reason: 'Unexpected integration type: $key', + ); + } + + for (final key in config.integrationResolvedVersions.keys) { + expect( + expectedTypes.contains(key), + isTrue, + reason: 'Unexpected integration type: $key', + ); + } + }); + + test('integration versions are used in AssetsGenConfig', () { + final pubspecFile = File( + 'test_resources/integration_versions/pubspec.yaml', + ); + final config = loadPubspecConfig(pubspecFile); + + // Verify that the resolved versions and constraints are available + expect(config.integrationResolvedVersions, isNotEmpty); + expect(config.integrationVersionConstraints, isNotEmpty); + + // Verify they can be passed to generators + expect( + config.integrationResolvedVersions[RiveIntegration], + isA(), + ); + expect( + config.integrationVersionConstraints[RiveIntegration], + isA(), + ); + }); + + test('version resolution with only constraint and no lock', () { + // Create a temporary pubspec file without a lock + final tempDir = Directory.systemTemp.createTempSync('flutter_gen_test'); + try { + final tempPubspec = File('${tempDir.path}/pubspec.yaml'); + tempPubspec.writeAsStringSync(''' +name: test_no_lock +environment: + sdk: ^3.0.0 +dependencies: + rive: ^0.13.0 +flutter_gen: + output: lib/gen/ + integrations: + rive: true +flutter: + assets: + - assets/ +'''); + + final config = loadPubspecConfig(tempPubspec); + + // Should have constraint but no resolved version + expect( + config.integrationVersionConstraints[RiveIntegration], + equals(VersionConstraint.parse('^0.13.0')), + ); + expect( + config.integrationResolvedVersions[RiveIntegration], + isNull, + ); + } finally { + tempDir.deleteSync(recursive: true); + } + }); + + test('version resolution with lock but no constraint', () { + // This tests the case where pubspec.lock has a version + // but pubspec.yaml doesn't specify a constraint (e.g., path dependency) + final tempDir = Directory.systemTemp.createTempSync('flutter_gen_test'); + try { + final tempPubspec = File('${tempDir.path}/pubspec.yaml'); + tempPubspec.writeAsStringSync(''' +name: test_lock_only +environment: + sdk: ^3.0.0 +dependencies: + rive: + path: ../rive +flutter_gen: + output: lib/gen/ + integrations: + rive: true +flutter: + assets: + - assets/ +'''); + + final tempLock = File('${tempDir.path}/pubspec.lock'); + tempLock.writeAsStringSync(''' +packages: + rive: + dependency: "direct main" + description: + path: "../rive" + relative: true + source: path + version: "0.13.5" +sdks: + dart: ">=3.0.0 <4.0.0" +'''); + + final config = loadPubspecConfig(tempPubspec); + + // Should have resolved version but no constraint + expect( + config.integrationResolvedVersions[RiveIntegration], + equals(Version(0, 13, 5)), + ); + expect( + config.integrationVersionConstraints[RiveIntegration], + isNull, + ); + } finally { + tempDir.deleteSync(recursive: true); + } + }); + }); +} diff --git a/packages/core/test/settings_test.dart b/packages/core/test/settings_test.dart index 3629b1f4..b2a32b2c 100644 --- a/packages/core/test/settings_test.dart +++ b/packages/core/test/settings_test.dart @@ -4,7 +4,9 @@ import 'package:flutter_gen_core/settings/flavored_asset.dart'; import 'package:flutter_gen_core/settings/pubspec.dart'; import 'package:flutter_gen_core/utils/error.dart' show InvalidSettingsException; +import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; +import 'package:yaml/yaml.dart'; void main() { group(AssetType, () { @@ -116,4 +118,229 @@ void main() { ); }); }); + + group('Pubspec.dependenciesVersionConstraint', () { + test('parses string version constraints', () { + final yaml = loadYaml(''' +name: test +environment: + sdk: ^3.0.0 +dependencies: + rive: ^0.13.0 + flutter_svg: ^2.0.0 + lottie: ">=1.0.0 <2.0.0" +flutter_gen: + output: lib/gen/ +flutter: + assets: + - assets/ +'''); + final pubspec = Pubspec.fromJson(yaml); + + expect(pubspec.dependenciesVersionConstraint['rive'], isNotNull); + expect( + pubspec.dependenciesVersionConstraint['rive'], + equals(VersionConstraint.parse('^0.13.0')), + ); + + expect(pubspec.dependenciesVersionConstraint['flutter_svg'], isNotNull); + expect( + pubspec.dependenciesVersionConstraint['flutter_svg'], + equals(VersionConstraint.parse('^2.0.0')), + ); + + expect(pubspec.dependenciesVersionConstraint['lottie'], isNotNull); + expect( + pubspec.dependenciesVersionConstraint['lottie'], + equals(VersionConstraint.parse('>=1.0.0 <2.0.0')), + ); + }); + + test('parses map with version key', () { + final yaml = loadYaml(''' +name: test +environment: + sdk: ^3.0.0 +dependencies: + rive: + version: ^0.14.0 + flutter_svg: + version: ">=2.0.0 <3.0.0" +flutter_gen: + output: lib/gen/ +flutter: + assets: + - assets/ +'''); + final pubspec = Pubspec.fromJson(yaml); + + expect(pubspec.dependenciesVersionConstraint['rive'], isNotNull); + expect( + pubspec.dependenciesVersionConstraint['rive'], + equals(VersionConstraint.parse('^0.14.0')), + ); + + expect(pubspec.dependenciesVersionConstraint['flutter_svg'], isNotNull); + expect( + pubspec.dependenciesVersionConstraint['flutter_svg'], + equals(VersionConstraint.parse('>=2.0.0 <3.0.0')), + ); + }); + + test('handles path dependencies without version', () { + final yaml = loadYaml(''' +name: test +environment: + sdk: ^3.0.0 +dependencies: + rive: + path: ../rive + flutter_svg: ^2.0.0 +flutter_gen: + output: lib/gen/ +flutter: + assets: + - assets/ +'''); + final pubspec = Pubspec.fromJson(yaml); + + // Path dependency should be null since no version constraint + expect(pubspec.dependenciesVersionConstraint['rive'], isNull); + + // String version should still work + expect(pubspec.dependenciesVersionConstraint['flutter_svg'], isNotNull); + expect( + pubspec.dependenciesVersionConstraint['flutter_svg'], + equals(VersionConstraint.parse('^2.0.0')), + ); + }); + + test('handles git dependencies without version', () { + final yaml = loadYaml(''' +name: test +environment: + sdk: ^3.0.0 +dependencies: + rive: + git: + url: https://github.com/example/rive.git + ref: main + lottie: ^5.0.0 +flutter_gen: + output: lib/gen/ +flutter: + assets: + - assets/ +'''); + final pubspec = Pubspec.fromJson(yaml); + + // Git dependency should be null since no version constraint + expect(pubspec.dependenciesVersionConstraint['rive'], isNull); + + // String version should still work + expect(pubspec.dependenciesVersionConstraint['lottie'], isNotNull); + expect( + pubspec.dependenciesVersionConstraint['lottie'], + equals(VersionConstraint.parse('^5.0.0')), + ); + }); + + test('handles invalid version strings gracefully', () { + final yaml = loadYaml(''' +name: test +environment: + sdk: ^3.0.0 +dependencies: + rive: invalid_version + flutter_svg: ^2.0.0 +flutter_gen: + output: lib/gen/ +flutter: + assets: + - assets/ +'''); + final pubspec = Pubspec.fromJson(yaml); + + // Invalid version should be null + expect(pubspec.dependenciesVersionConstraint['rive'], isNull); + + // Valid version should work + expect(pubspec.dependenciesVersionConstraint['flutter_svg'], isNotNull); + }); + + test('handles dependencies with version key containing invalid version', () { + final yaml = loadYaml(''' +name: test +environment: + sdk: ^3.0.0 +dependencies: + rive: + version: invalid_version + lottie: ^5.0.0 +flutter_gen: + output: lib/gen/ +flutter: + assets: + - assets/ +'''); + final pubspec = Pubspec.fromJson(yaml); + + // Invalid version in map should be null + expect(pubspec.dependenciesVersionConstraint['rive'], isNull); + + // Valid string version should work + expect(pubspec.dependenciesVersionConstraint['lottie'], isNotNull); + }); + + test('handles null dependencies', () { + final yaml = loadYaml(''' +name: test +environment: + sdk: ^3.0.0 +flutter_gen: + output: lib/gen/ +flutter: + assets: + - assets/ +'''); + final pubspec = Pubspec.fromJson(yaml); + + // Should return empty map for null dependencies + expect(pubspec.dependenciesVersionConstraint, isEmpty); + }); + + test('handles mixed dependency formats', () { + final yaml = loadYaml(''' +name: test +environment: + sdk: ^3.0.0 +dependencies: + rive: ^0.13.0 + flutter_svg: + version: ^2.0.0 + lottie: + path: ../lottie + another_package: + git: + url: https://github.com/example/package.git +flutter_gen: + output: lib/gen/ +flutter: + assets: + - assets/ +'''); + final pubspec = Pubspec.fromJson(yaml); + + expect( + pubspec.dependenciesVersionConstraint['rive'], + equals(VersionConstraint.parse('^0.13.0')), + ); + expect( + pubspec.dependenciesVersionConstraint['flutter_svg'], + equals(VersionConstraint.parse('^2.0.0')), + ); + expect(pubspec.dependenciesVersionConstraint['lottie'], isNull); + expect(pubspec.dependenciesVersionConstraint['another_package'], isNull); + }); + }); } diff --git a/packages/core/test_resources/integration_versions/pubspec.lock b/packages/core/test_resources/integration_versions/pubspec.lock new file mode 100644 index 00000000..e2f8a807 --- /dev/null +++ b/packages/core/test_resources/integration_versions/pubspec.lock @@ -0,0 +1,29 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + rive: + dependency: "direct main" + description: + name: rive + sha256: "abc123" + url: "https://pub.dev" + source: hosted + version: "0.13.5" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "def456" + url: "https://pub.dev" + source: hosted + version: "2.0.9" + lottie: + dependency: "direct main" + description: + name: lottie + sha256: "ghi789" + url: "https://pub.dev" + source: hosted + version: "5.1.0" +sdks: + dart: ">=3.0.0 <4.0.0" diff --git a/packages/core/test_resources/integration_versions/pubspec.yaml b/packages/core/test_resources/integration_versions/pubspec.yaml new file mode 100644 index 00000000..fecd6e60 --- /dev/null +++ b/packages/core/test_resources/integration_versions/pubspec.yaml @@ -0,0 +1,20 @@ +name: test_integration_versions + +environment: + sdk: ^3.0.0 + +dependencies: + rive: ^0.13.0 + flutter_svg: ^2.0.0 + lottie: ^5.0.0 + +flutter_gen: + output: lib/gen/ + integrations: + rive: true + flutter_svg: true + lottie: true + +flutter: + assets: + - assets/ diff --git a/packages/core/test_resources/integration_versions_rive_014/pubspec.lock b/packages/core/test_resources/integration_versions_rive_014/pubspec.lock new file mode 100644 index 00000000..8009d48b --- /dev/null +++ b/packages/core/test_resources/integration_versions_rive_014/pubspec.lock @@ -0,0 +1,21 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + rive: + dependency: "direct main" + description: + name: rive + sha256: "xyz123" + url: "https://pub.dev" + source: hosted + version: "0.14.1" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: "uvw456" + url: "https://pub.dev" + source: hosted + version: "2.0.10" +sdks: + dart: ">=3.0.0 <4.0.0" diff --git a/packages/core/test_resources/integration_versions_rive_014/pubspec.yaml b/packages/core/test_resources/integration_versions_rive_014/pubspec.yaml new file mode 100644 index 00000000..7bd8c58d --- /dev/null +++ b/packages/core/test_resources/integration_versions_rive_014/pubspec.yaml @@ -0,0 +1,18 @@ +name: test_integration_versions_rive_014 + +environment: + sdk: ^3.0.0 + +dependencies: + rive: ^0.14.0 + flutter_svg: ">=2.0.0 <3.0.0" + +flutter_gen: + output: lib/gen/ + integrations: + rive: true + flutter_svg: true + +flutter: + assets: + - assets/