diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle b/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle index 260a842616c..c926d6ff45e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation "androidx.annotation:annotation:1.9.1" - implementation 'com.google.android.gms:play-services-maps:18.2.0' + implementation 'com.google.android.gms:play-services-maps:19.2.0' implementation 'com.google.maps.android:android-maps-utils:3.6.0' androidTestImplementation 'androidx.test:runner:1.6.2' androidTestImplementation 'androidx.test:rules:1.6.1' diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Constants.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Constants.java new file mode 100644 index 00000000000..6f6136c1847 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Constants.java @@ -0,0 +1,11 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.plugins.googlemaps; + +abstract class Constants { + + // Current package version. + public static final String FGM_PLUGIN_VERSION = "2.16.1"; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index c4208f003c6..4bd7a3545b3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -7,6 +7,7 @@ import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.android.gms.maps.MapsInitializer.Renderer; import com.google.android.gms.maps.model.CameraPosition; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.platform.PlatformView; @@ -31,6 +32,11 @@ public class GoogleMapFactory extends PlatformViewFactory { @Override @NonNull public PlatformView create(@NonNull Context context, int id, @Nullable Object args) { + final boolean shouldInitializeRenderer = !googleMapInitializer.hasRendererInitializationStarted(); + if (shouldInitializeRenderer) { + googleMapInitializer.initializeWithRendererRequest(Renderer.LATEST); + } + final Messages.PlatformMapViewCreationParams params = Objects.requireNonNull((Messages.PlatformMapViewCreationParams) args); final GoogleMapBuilder builder = new GoogleMapBuilder(); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java index e4bea6b8ffa..ff0eb9063c7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java @@ -7,7 +7,7 @@ import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; +import com.google.android.gms.maps.MapsApiSettings; import com.google.android.gms.maps.MapsInitializer; import com.google.android.gms.maps.OnMapsSdkInitializedCallback; import io.flutter.plugin.common.BinaryMessenger; @@ -15,9 +15,11 @@ /** GoogleMaps initializer used to initialize the Google Maps SDK with preferred settings. */ final class GoogleMapInitializer implements OnMapsSdkInitializedCallback, Messages.MapsInitializerApi { + private final Context context; private static Messages.Result initializationResult; private boolean rendererInitialized = false; + private boolean rendererInitializationRequested = false; GoogleMapInitializer(Context context, BinaryMessenger binaryMessenger) { this.context = context; @@ -41,14 +43,9 @@ public void initializeWithPreferredRenderer( } } - /** - * Initializes map renderer to with preferred renderer type. - * - *

This method is visible for testing purposes only and should never be used outside this - * class. - */ - @VisibleForTesting + /** Initializes map renderer with preferred renderer type. */ public void initializeWithRendererRequest(@Nullable MapsInitializer.Renderer renderer) { + rendererInitializationRequested = true; MapsInitializer.initialize(context, renderer, this); } @@ -59,6 +56,12 @@ public void onMapsSdkInitialized(@NonNull MapsInitializer.Renderer renderer) { if (initializationResult != null) { switch (renderer) { case LATEST: + // Set Android-specific Maps SDK attribution Id. This value should not be changed + // without discussing it first with code owners. + MapsApiSettings.addInternalUsageAttributionId( + context, + "gmp_flutter_googlemapsflutter_v" + Constants.FGM_PLUGIN_VERSION + "_android" + ); initializationResult.success(Messages.PlatformRendererType.LATEST); break; case LEGACY: @@ -74,4 +77,9 @@ public void onMapsSdkInitialized(@NonNull MapsInitializer.Renderer renderer) { initializationResult = null; } } + + /** Returns true if renderer initialization has started or renderer has been initialized. */ + boolean hasRendererInitializationStarted() { + return rendererInitialized || rendererInitializationRequested; + } } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/version_check.yaml b/packages/google_maps_flutter/google_maps_flutter_android/version_check.yaml new file mode 100644 index 00000000000..c87e6aa36b1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/version_check.yaml @@ -0,0 +1,10 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file is used to check that the version string in the Constants.java file is up to date and matches +# the version in pubspec.yaml. +checks: + - filepath: android/src/main/java/io/flutter/plugins/googlemaps/Constants.java + regexp: public static final String FGM_PLUGIN_VERSION = "([\.0-9]+)"; + errorMessage: "Version string in Constants.java is not up to date. Please update it to the latest version." diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FGMConstants.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FGMConstants.h new file mode 100644 index 00000000000..55f225bd779 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FGMConstants.h @@ -0,0 +1,11 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FGMCONSTANTS_H +#define FGMCONSTANTS_H + +// Google Maps Flutter Plugin version +#define FGM_PLUGIN_VERSION "2.15.2" + +#endif \ No newline at end of file diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.m index 70bde9022a0..89af24e46b8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.m @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "FLTGoogleMapsPlugin.h" +#import "FGMConstants.h" #pragma mark - GoogleMaps plugin implementation @@ -10,6 +11,15 @@ @implementation FLTGoogleMapsPlugin + (void)registerWithRegistrar:(NSObject *)registrar { FLTGoogleMapFactory *googleMapFactory = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + + Class gmssClass = [GMSServices class]; + SEL internalUsageAttributionIDSelector = @selector(addInternalUsageAttributionID:); + + if ([gmssClass respondsToSelector:internalUsageAttributionIDSelector]) { + NSString *attributionId = [NSString stringWithFormat:@"gmp_flutter_googlemapsflutter_v%s_ios", FGM_PLUGIN_VERSION]; + [GMSServices performSelector:internalUsageAttributionIDSelector withObject:attributionId]; + } + [registrar registerViewFactory:googleMapFactory withId:@"plugins.flutter.dev/google_maps_ios" gestureRecognizersBlockingPolicy: diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/version_check.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/version_check.yaml new file mode 100644 index 00000000000..54fd0873705 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/version_check.yaml @@ -0,0 +1,10 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file is used to check that the version string in the FGMConstants.h file is up to date and matches +# the version in pubspec.yaml. +checks: + - filepath: ios/Classes/FGMConstants.h + regexp: define FGM_PLUGIN_VERSION "([\.0-9]+)" + errorMessage: "Version string in FGMConstants.h is not up to date. Please update it to the latest version." diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/constants.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/constants.dart new file mode 100644 index 00000000000..33152f12f23 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/constants.dart @@ -0,0 +1,6 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// Google Maps Flutter Web plugin version. +const String fgmPluginVersion = '0.5.12'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/version_check.yaml b/packages/google_maps_flutter/google_maps_flutter_web/version_check.yaml new file mode 100644 index 00000000000..1184b1f3de1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/version_check.yaml @@ -0,0 +1,10 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file is used to check that the version string in the Constants.dart file is up to date and matches +# the version in pubspec.yaml. +checks: + - filepath: lib/src/constants.dart + regexp: const String fgmPluginVersion = '([\.0-9]+)'; + errorMessage: "Version string in constants.dart is not up to date. Please update it to the latest version." diff --git a/script/tool/lib/src/common/repository_package.dart b/script/tool/lib/src/common/repository_package.dart index 2a18c2e6e2b..c527421c6e8 100644 --- a/script/tool/lib/src/common/repository_package.dart +++ b/script/tool/lib/src/common/repository_package.dart @@ -74,6 +74,10 @@ class RepositoryPackage { File get prePublishScript => directory.childDirectory('tool').childFile('pre_publish.dart'); + /// The verion_check.yaml file that is used to check the version of + /// the package present in the platform implementation. + File get versionCheckFile => directory.childFile('version_check.yaml'); + /// Returns the directory containing support for [platform]. Directory platformDirectory(FlutterPlatform platform) { late final String directoryName; diff --git a/script/tool/lib/src/version_check_command.dart b/script/tool/lib/src/version_check_command.dart index c3e36bb7087..c21c01341f4 100644 --- a/script/tool/lib/src/version_check_command.dart +++ b/script/tool/lib/src/version_check_command.dart @@ -7,6 +7,7 @@ import 'package:http/http.dart' as http; import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:pub_semver/pub_semver.dart'; +import 'package:yaml/yaml.dart'; import 'common/git_version_finder.dart'; import 'common/output_utils.dart'; @@ -223,6 +224,15 @@ class VersionCheckCommand extends PackageLoopingCommand { errors.add('CHANGELOG.md failed validation.'); } + final YamlMap? versionCheckYaml = tryParseVersionCheckYaml(package); + if (!validateVersionCheckYamlVersion( + versionCheckYaml: versionCheckYaml, + version: pubspec.version, + package: package, + )) { + errors.add('Invalid version_check.yaml.'); + } + // If there are no other issues, make sure that there isn't a missing // change to the version and/or CHANGELOG. if (getBoolArg(_checkForMissingChanges) && @@ -583,4 +593,124 @@ ${indentation}The first version listed in CHANGELOG.md is $fromChangeLog. return null; } + + @visibleForTesting + YamlMap? tryParseVersionCheckYaml(RepositoryPackage package) { + final File versionCheckFile = package.directory.childFile( + 'version_check.yaml', + ); + if (!versionCheckFile.existsSync()) { + return null; + } + + try { + final String content = versionCheckFile.readAsStringSync(); + return loadYaml(content) as YamlMap; + } catch (e) { + printError('Invalid version_check.yaml format: $e'); + return null; + } + } + + /// Validates versions using the version_check.yaml file. + /// + /// This checks that the version in the specified file matches the version + /// in the pubspec.yaml file. + /// + /// version_check.yaml should contain a list of checks, each with the + /// following fields: + /// - filepath: The path to the file to check (could be platform-specific, + /// e.g. .java on Android, .h on iOS etc). + /// - regexp: The regex pattern to match the version string. Group 1 of the + /// regex should contain the version string (e.g. 1.0.4). + /// - errorMessage: The error message to display if the version does + /// not match. + /// + /// No validation is performed if the version_check.yaml file does not exist. + /// + /// Returns true if the validation passes, false otherwise. + @visibleForTesting + bool validateVersionCheckYamlVersion({ + required YamlMap? versionCheckYaml, + required Version? version, + required RepositoryPackage package, + }) { + // Skip validation if the yaml file doesn't exist. + if (versionCheckYaml == null || version == null) { + return true; + } + + final YamlList? checks = versionCheckYaml['checks'] as YamlList?; + if (checks == null) { + printError('Invalid version_check.yaml: Missing checks.'); + return false; + } + + bool result = true; + for (final YamlNode entry in checks.nodes) { + final YamlMap node = entry as YamlMap; + final String? filepath = node['filepath'] as String?; + final String? regex = node['regexp'] as String?; + final String? errorMessage = node['errorMessage'] as String?; + + if (filepath == null || filepath.isEmpty) { + printError('Invalid version_check.yaml: Missing filepath.'); + result = false; + continue; + } + + if (regex == null || regex.isEmpty) { + printError('Invalid version_check.yaml: Missing regexp.'); + result = false; + continue; + } + + if (errorMessage == null || filepath.isEmpty) { + printError('Invalid version_check.yaml: Missing errorMessage.'); + result = false; + continue; + } + + final File targetFile = package.directory.childFile(filepath); + if (!targetFile.existsSync()) { + printError( + 'File "$filepath" specified in version_check.yaml does not exist.', + ); + result = false; + continue; + } + + if (!targetFile.absolute.path.startsWith(package.directory.path)) { + printError( + 'File path "$filepath" in version_check.yaml targets outside the package directory.', + ); + result = false; + continue; + } + + final RegExp versionRegex = RegExp(regex); + final String fileContent = targetFile.readAsStringSync(); + final Match? match = versionRegex.firstMatch(fileContent); + + if (match == null || match.groupCount < 1) { + printError( + 'No version string found in "$filepath" using the provided regex.', + ); + result = false; + continue; + } + + final String foundVersion = match.group(1)!; + if (foundVersion != version.toString()) { + printError('Version mismatch in "$filepath":\n' + 'Expected: $version\n' + 'Found: $foundVersion\n' + 'Error message: $errorMessage'); + result = false; + continue; + } + } + + return result; + } } diff --git a/script/tool/test/version_check_command_test.dart b/script/tool/test/version_check_command_test.dart index a2e04bd710e..d4e9c181cd2 100644 --- a/script/tool/test/version_check_command_test.dart +++ b/script/tool/test/version_check_command_test.dart @@ -1552,6 +1552,360 @@ ${indentation}HTTP response: null ])); }); }); + + group('validateVersionCheckYamlVersion', () { + test('validation passes if version_check.yaml is not present', () { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + final VersionCheckCommand command = + runner.commands['version-check']! as VersionCheckCommand; + expect(plugin.versionCheckFile.existsSync(), isFalse); + + final bool result = command.validateVersionCheckYamlVersion( + versionCheckYaml: null, + version: Version.parse('1.0.0'), + package: plugin, + ); + expect(result, isTrue); + }); + }); + + test('validation failed when filepath is not present', () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +checks: + - regexp: const prefixPluginVersion = "([\.0-9]+)" + errorMessage: "Version string is not up to date." +'''); + + bool hasError = false; + final List log = await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); + expect( + log.contains('Invalid version_check.yaml: Missing filepath.'), + isTrue, + ); + }); + + test( + 'validation failed when regexp is not present', + () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +checks: + - filepath: constants.dart + errorMessage: "Version string is not up to date." +'''); + + bool hasError = false; + final List log = await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); + expect( + log.contains('Invalid version_check.yaml: Missing regexp.'), + isTrue, + ); + }, + ); + + test('validation failed when errorMessage is not present', () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +checks: + - filepath: constants.dart + regexp: const prefixPluginVersion = "([\.0-9]+)" +'''); + + bool hasError = false; + final List log = await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); + expect( + log.contains('Invalid version_check.yaml: Missing errorMessage.'), + isTrue, + ); + }); + + test("validation fails when file doesn't exist", () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +checks: + - filepath: constants.dart + regexp: const prefixPluginVersion = "([\.0-9]+)" + errorMessage: "Version string is not up to date." +'''); + + bool hasError = false; + final List log = await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); + expect( + log.contains( + 'File "constants.dart" specified in version_check.yaml does not exist.', + ), + isTrue, + ); + }); + + test('validation fails file is outside the package direcry', () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +checks: + - filepath: /home/user/constants.dart + regexp: const prefixPluginVersion = "([\.0-9]+)" + errorMessage: "Version string is not up to date." +'''); + + final File constantsFile = + plugin.directory.fileSystem.file('/home/user/constants.dart'); + constantsFile.createSync(recursive: true); + expect(constantsFile.existsSync(), isTrue); + constantsFile.writeAsStringSync('const prefixPluginVersion = "0.1.0";'); + + bool hasError = false; + final List log = await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); + expect( + log.contains( + 'File path "/home/user/constants.dart" in version_check.yaml targets outside the package directory.', + ), + isTrue, + ); + }); + + test('validation fails when no text matching regex found', () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +checks: + - filepath: lib/constants.dart + regexp: const prefixPluginVersion = "([\.0-9]+)" + errorMessage: "Version string is not up to date." +'''); + + final File constantsFile = + plugin.directory.childFile('lib/constants.dart'); + constantsFile.createSync(recursive: true); + expect(constantsFile.existsSync(), isTrue); + constantsFile.writeAsStringSync(''' +const String version = "0.1.0"; +'''); + + bool hasError = false; + final List log = await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); + expect( + log.contains( + 'No version string found in "lib/constants.dart" using the provided regex.', + ), + isTrue, + ); + }); + + test('Validation fails when "checks" item is not present', () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +definitely_not_checks: + - filepath: lib/constants.dart + regexp: const prefixPluginVersion = "([\.0-9]+)" + errorMessage: "Version string is not up to date." +'''); + + bool hasError = false; + final List log = await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); + expect( + log.contains('Invalid version_check.yaml: Missing checks.'), + isTrue, + ); + }); + + test('validation fails on versions mismatch', () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +checks: + - filepath: lib/constants.dart + regexp: const prefixPluginVersion = "([\.0-9]+)" + errorMessage: "Version string is not up to date." +'''); + + final File constantsFile = + plugin.directory.childFile('lib/constants.dart'); + constantsFile.createSync(recursive: true); + expect(constantsFile.existsSync(), isTrue); + constantsFile.writeAsStringSync('const prefixPluginVersion = "0.1.0";'); + + bool hasError = false; + final List log = await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); + expect( + log.contains( + ''' +Version mismatch in "lib/constants.dart": +Expected: 1.0.0 +Found: 0.1.0 +Error message: Version string is not up to date.''', + ), + isTrue, + ); + }); + + test('Validation fails when one of the checks fails', () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +checks: + - filepath: lib/constants.dart + regexp: const prefixPluginVersion = "([\.0-9]+)" + errorMessage: "Version string is not up to date." + - filepath: lib/another_constants.dart + regexp: const prefixPluginVersion = "([\.0-9]+)" + errorMessage: "Version string is not up to date 2." +'''); + + final File constantsFile = + plugin.directory.childFile('lib/constants.dart'); + constantsFile.createSync(recursive: true); + expect(constantsFile.existsSync(), isTrue); + constantsFile.writeAsStringSync('const prefixPluginVersion = "1.0.0";'); + + final File anotherConstantsFile = + plugin.directory.childFile('lib/another_constants.dart'); + anotherConstantsFile.createSync(recursive: true); + expect(anotherConstantsFile.existsSync(), isTrue); + anotherConstantsFile + .writeAsStringSync('const prefixPluginVersion = "0.2.0";'); + + bool hasError = false; + final List log = await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isTrue); + expect(log.contains('Version string is not up to date.'), isFalse); + expect( + log.contains( + ''' +Version mismatch in "lib/another_constants.dart": +Expected: 1.0.0 +Found: 0.2.0 +Error message: Version string is not up to date 2.''', + ), + isTrue, + ); + }); + + test('validation passes on no version mismatch', () async { + final RepositoryPackage plugin = + createFakePlugin('plugin', packagesDir, version: '1.0.0'); + expect(plugin.versionCheckFile.existsSync(), isFalse); + plugin.versionCheckFile.createSync(); + plugin.versionCheckFile.writeAsStringSync(r''' +checks: + - filepath: lib/constants.dart + regexp: const prefixPluginVersion = "([\.0-9]+)" + errorMessage: "Version string is not up to date." +'''); + + final File constantsFile = + plugin.directory.childFile('lib/constants.dart'); + constantsFile.createSync(recursive: true); + expect(constantsFile.existsSync(), isTrue); + constantsFile.writeAsStringSync('const prefixPluginVersion = "1.0.0";'); + + bool hasError = false; + await runCapturingPrint( + runner, + ['version-check'], + errorHandler: (Error e) { + expect(e, isA()); + hasError = true; + }, + ); + expect(hasError, isFalse); + }); }); group('Pre 1.0', () {