From 748106a2de89c77e08e3585f8bdd00c58b612e19 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 16 Jun 2025 09:58:30 +0100 Subject: [PATCH 1/3] fix: regex patterns --- .../lib/src/firebase/firebase_android_writes.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/flutterfire_cli/lib/src/firebase/firebase_android_writes.dart b/packages/flutterfire_cli/lib/src/firebase/firebase_android_writes.dart index 51fca337..5e1f2bc6 100644 --- a/packages/flutterfire_cli/lib/src/firebase/firebase_android_writes.dart +++ b/packages/flutterfire_cli/lib/src/firebase/firebase_android_writes.dart @@ -482,8 +482,9 @@ AndroidGradleContents _applyGoogleServicesPlugin( .contains(_androidAppBuildGradleGoogleServicesRegex); if (!pluginExists) { - final pattern = - RegExp(r'id "com\.android\.application" version "[^"]*" apply false'); + final pattern = RegExp( + "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", + ); final match = pattern.firstMatch(androidGradleSettingsFileContents); if (match != null) { @@ -630,7 +631,7 @@ AndroidGradleContents _applyFirebaseAndroidPlugin({ if (!pluginExists) { final pattern = RegExp( - r'id "com\.google\.gms\.google-services" version "\d+\.\d+\.\d+" apply false', + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", ); final match = pattern.firstMatch(androidGradleSettingsFileContents); @@ -1059,7 +1060,7 @@ AndroidGradleContents _applyFirebaseAndroidPluginKts({ if (!pluginExists) { final pattern = RegExp( - r'id\("com\.google\.gms\.google-services"\) version\("\d+\.\d+\.\d+"\) apply false', + "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", ); final match = pattern.firstMatch(androidGradleSettingsKtsFileContents); From 8504bf0ba78ccb636b62b26d4072b553a1ec9995 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 16 Jun 2025 10:05:38 +0100 Subject: [PATCH 2/3] test: android regexes --- .../test/firebase_android_writes_test.dart | 334 ++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 packages/flutterfire_cli/test/firebase_android_writes_test.dart diff --git a/packages/flutterfire_cli/test/firebase_android_writes_test.dart b/packages/flutterfire_cli/test/firebase_android_writes_test.dart new file mode 100644 index 00000000..df7b1f03 --- /dev/null +++ b/packages/flutterfire_cli/test/firebase_android_writes_test.dart @@ -0,0 +1,334 @@ +import 'package:test/test.dart'; + +void main() { + group('Firebase Android Writes - Regex Pattern Tests', () { + group('Android Application Pattern Tests', () { + test('should match android application with double quotes', () { + final pattern = RegExp( + "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", + ); + + final testString = + 'id "com.android.application" version "8.1.0" apply false'; + expect(pattern.hasMatch(testString), isTrue); + + final match = pattern.firstMatch(testString); + expect(match, isNotNull); + expect(match!.group(1), equals('"com.android.application"')); + expect(match.group(2), equals('"8.1.0"')); + }); + + test('should match android application with single quotes', () { + final pattern = RegExp( + "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", + ); + + final testString = + "id 'com.android.application' version '8.1.0' apply false"; + expect(pattern.hasMatch(testString), isTrue); + + final match = pattern.firstMatch(testString); + expect(match, isNotNull); + expect(match!.group(1), equals("'com.android.application'")); + expect(match.group(2), equals("'8.1.0'")); + }); + + test('should match android application with mixed quotes', () { + final pattern = RegExp( + "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", + ); + + final testStrings = [ + 'id "com.android.application" version \'8.1.0\' apply false', + 'id \'com.android.application\' version "8.1.0" apply false', + ]; + + for (final testString in testStrings) { + expect(pattern.hasMatch(testString), isTrue, + reason: 'Failed for: $testString'); + } + }); + + test('should not match invalid android application patterns', () { + final pattern = RegExp( + "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", + ); + + final invalidStrings = [ + 'id com.android.application version 8.1.0 apply false', // no quotes + 'id "com.android.library" version "8.1.0" apply false', // wrong plugin + 'id "com.android.application" version "8.1.0"', // missing apply false + ]; + + for (final testString in invalidStrings) { + expect(pattern.hasMatch(testString), isFalse, + reason: 'Should not match: $testString'); + } + }); + }); + + group('Google Services Pattern Tests', () { + test('should match google services with double quotes', () { + final pattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + final testString = + 'id "com.google.gms.google-services" version "4.4.0" apply false'; + expect(pattern.hasMatch(testString), isTrue); + + final match = pattern.firstMatch(testString); + expect(match, isNotNull); + expect(match!.group(1), equals('"com.google.gms.google-services"')); + expect(match.group(2), equals('"4.4.0"')); + }); + + test('should match google services with single quotes', () { + final pattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + final testString = + "id 'com.google.gms.google-services' version '4.4.0' apply false"; + expect(pattern.hasMatch(testString), isTrue); + + final match = pattern.firstMatch(testString); + expect(match, isNotNull); + expect(match!.group(1), equals("'com.google.gms.google-services'")); + expect(match.group(2), equals("'4.4.0'")); + }); + + test('should match google services with mixed quotes', () { + final pattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + final testStrings = [ + 'id "com.google.gms.google-services" version \'4.4.0\' apply false', + 'id \'com.google.gms.google-services\' version "4.4.0" apply false', + ]; + + for (final testString in testStrings) { + expect(pattern.hasMatch(testString), isTrue, + reason: 'Failed for: $testString'); + } + }); + + test('should match different version formats', () { + final pattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + final testStrings = [ + 'id "com.google.gms.google-services" version "4.3.15" apply false', + 'id "com.google.gms.google-services" version "4.4.0" apply false', + 'id "com.google.gms.google-services" version "5.0.1" apply false', + "id 'com.google.gms.google-services' version '10.2.3' apply false", + ]; + + for (final testString in testStrings) { + expect(pattern.hasMatch(testString), isTrue, + reason: 'Failed for: $testString'); + } + }); + }); + + group('Kotlin DSL Google Services Pattern Tests', () { + test('should match kotlin DSL with double quotes', () { + final pattern = RegExp( + "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", + ); + + final testString = + 'id("com.google.gms.google-services") version("4.4.0") apply false'; + expect(pattern.hasMatch(testString), isTrue); + + final match = pattern.firstMatch(testString); + expect(match, isNotNull); + expect(match!.group(1), equals('"com.google.gms.google-services"')); + expect(match.group(2), equals('"4.4.0"')); + }); + + test('should match kotlin DSL with single quotes', () { + final pattern = RegExp( + "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", + ); + + final testString = + "id('com.google.gms.google-services') version('4.4.0') apply false"; + expect(pattern.hasMatch(testString), isTrue); + + final match = pattern.firstMatch(testString); + expect(match, isNotNull); + expect(match!.group(1), equals("'com.google.gms.google-services'")); + expect(match.group(2), equals("'4.4.0'")); + }); + + test('should match kotlin DSL with mixed quotes', () { + final pattern = RegExp( + "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", + ); + + final testStrings = [ + 'id("com.google.gms.google-services") version(\'4.4.0\') apply false', + 'id(\'com.google.gms.google-services\') version("4.4.0") apply false', + ]; + + for (final testString in testStrings) { + expect(pattern.hasMatch(testString), isTrue, + reason: 'Failed for: $testString'); + } + }); + }); + + group('Firebase Performance Plugin Pattern Tests', () { + test('should match performance plugin patterns with various quotes', () { + // Pattern used in settings.gradle + final pattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + // Test that performance plugin would be found after google services + final gradleContent = ''' +plugins { + id "com.android.application" version "8.1.0" apply false + id "com.google.gms.google-services" version "4.4.0" apply false + id 'com.google.firebase.firebase-perf' version "1.4.2" apply false + id "com.google.firebase.crashlytics" version '2.9.9' apply false +} +'''; + + expect(pattern.hasMatch(gradleContent), isTrue); + + // Test that it works with the actual example from the user + final performancePattern = + "id 'com.google.firebase.firebase-perf' version \"1.4.2\" apply false"; + final crashlyticsPattern = + 'id "com.google.firebase.crashlytics" version \'2.9.9\' apply false'; + + expect(gradleContent.contains(performancePattern), isTrue); + expect(gradleContent.contains(crashlyticsPattern), isTrue); + }); + }); + + group('Real-world gradle content patterns', () { + test('should handle user-reported mixed quote scenarios', () { + final androidAppPattern = RegExp( + "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", + ); + + final googleServicesPattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + // Example content from the user's issue + final gradleContent = ''' +plugins { + id "com.google.gms.google-services" version "4.4.0" apply false + id 'com.google.firebase.firebase-perf' version "1.4.2" apply false + id "com.google.firebase.crashlytics" version '2.9.9' apply false +} +'''; + + // Should find the google services plugin + expect(googleServicesPattern.hasMatch(gradleContent), isTrue); + + // Should find performance and crashlytics patterns if we create patterns for them + final perfPattern = RegExp( + "id ([\"']com\\.google\\.firebase\\.firebase-perf[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + final crashlyticsPattern = RegExp( + "id ([\"']com\\.google\\.firebase\\.crashlytics[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + expect(perfPattern.hasMatch(gradleContent), isTrue); + expect(crashlyticsPattern.hasMatch(gradleContent), isTrue); + }); + + test('should work with kotlin DSL mixed quotes', () { + final kotlinPattern = RegExp( + "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", + ); + + final kotlinContent = ''' +plugins { + id("com.android.application") version("8.1.0") apply false + id("com.google.gms.google-services") version("4.4.0") apply false + id('com.google.firebase.firebase-perf') version("1.4.2") apply false + id("com.google.firebase.crashlytics") version('2.9.9') apply false +} +'''; + + expect(kotlinPattern.hasMatch(kotlinContent), isTrue); + }); + }); + + group('Edge cases and error scenarios', () { + test('should not match malformed patterns', () { + final pattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + final badPatterns = [ + 'id "com.google.gms.google-services version "4.4.0" apply false', // missing quote + 'id "com.google.gms.google-services" version 4.4.0 apply false', // no version quotes + 'id "com.google.gms.google-services" version "4.4" apply false', // wrong version format + 'id "com.google.gms.google-services" version "4.4.0"', // missing apply false + ]; + + for (final badPattern in badPatterns) { + expect(pattern.hasMatch(badPattern), isFalse, + reason: 'Should not match: $badPattern'); + } + }); + + test('should handle empty and whitespace-only strings', () { + final pattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + expect(pattern.hasMatch(''), isFalse); + expect(pattern.hasMatch(' '), isFalse); + expect(pattern.hasMatch('\n\t'), isFalse); + }); + }); + + group('Version number validation', () { + test('should match valid semantic version numbers', () { + final pattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + final validVersions = [ + 'id "com.google.gms.google-services" version "0.0.1" apply false', + 'id "com.google.gms.google-services" version "1.0.0" apply false', + 'id "com.google.gms.google-services" version "99.99.99" apply false', + 'id "com.google.gms.google-services" version "4.3.15" apply false', + ]; + + for (final version in validVersions) { + expect(pattern.hasMatch(version), isTrue, + reason: 'Should match version: $version'); + } + }); + + test('should not match invalid version formats', () { + final pattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", + ); + + final invalidVersions = [ + 'id "com.google.gms.google-services" version "4.4" apply false', // missing patch + 'id "com.google.gms.google-services" version "1" apply false', // too short + 'id "com.google.gms.google-services" version "1.0.0.1" apply false', // too long + 'id "com.google.gms.google-services" version "1.0.a" apply false', // non-numeric + ]; + + for (final version in invalidVersions) { + expect(pattern.hasMatch(version), isFalse, + reason: 'Should not match version: $version'); + } + }); + }); + }); +} From abc036f7d549ea6eff8c984015f65318264f89ea Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 16 Jun 2025 10:22:14 +0100 Subject: [PATCH 3/3] test: android write regexes --- .../src/firebase/firebase_android_writes.dart | 28 +++- .../test/firebase_android_writes_test.dart | 155 ++++++++---------- 2 files changed, 89 insertions(+), 94 deletions(-) diff --git a/packages/flutterfire_cli/lib/src/firebase/firebase_android_writes.dart b/packages/flutterfire_cli/lib/src/firebase/firebase_android_writes.dart index 5e1f2bc6..045622b0 100644 --- a/packages/flutterfire_cli/lib/src/firebase/firebase_android_writes.dart +++ b/packages/flutterfire_cli/lib/src/firebase/firebase_android_writes.dart @@ -74,6 +74,22 @@ const _performancePluginClassPathFallbackVersion = '1.4.1'; const _flutterFireConfigCommentStart = '// START: FlutterFire Configuration'; const _flutterFireConfigCommentEnd = '// END: FlutterFire Configuration'; +// Public regex patterns for testing +/// Pattern for matching Android application plugin with mixed quotes in settings.gradle +final androidApplicationPluginPattern = RegExp( + "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", +); + +/// Pattern for matching Google Services plugin with mixed quotes in settings.gradle +final googleServicesPluginPattern = RegExp( + "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", +); + +/// Pattern for matching Kotlin DSL Google Services plugin with mixed quotes in settings.gradle.kts +final kotlinGoogleServicesPluginPattern = RegExp( + "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", +); + String _applyGradleSettingsDependency( String dependency, String version, { @@ -482,9 +498,7 @@ AndroidGradleContents _applyGoogleServicesPlugin( .contains(_androidAppBuildGradleGoogleServicesRegex); if (!pluginExists) { - final pattern = RegExp( - "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", - ); + final pattern = androidApplicationPluginPattern; final match = pattern.firstMatch(androidGradleSettingsFileContents); if (match != null) { @@ -630,9 +644,7 @@ AndroidGradleContents _applyFirebaseAndroidPlugin({ androidGradleSettingsFileContents.contains(RegExp(pluginClassPath)); if (!pluginExists) { - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; final match = pattern.firstMatch(androidGradleSettingsFileContents); @@ -1059,9 +1071,7 @@ AndroidGradleContents _applyFirebaseAndroidPluginKts({ androidGradleSettingsKtsFileContents.contains(RegExp(pluginClassPath)); if (!pluginExists) { - final pattern = RegExp( - "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", - ); + final pattern = kotlinGoogleServicesPluginPattern; final match = pattern.firstMatch(androidGradleSettingsKtsFileContents); diff --git a/packages/flutterfire_cli/test/firebase_android_writes_test.dart b/packages/flutterfire_cli/test/firebase_android_writes_test.dart index df7b1f03..7607c39f 100644 --- a/packages/flutterfire_cli/test/firebase_android_writes_test.dart +++ b/packages/flutterfire_cli/test/firebase_android_writes_test.dart @@ -1,14 +1,13 @@ +import 'package:flutterfire_cli/src/firebase/firebase_android_writes.dart'; import 'package:test/test.dart'; void main() { group('Firebase Android Writes - Regex Pattern Tests', () { group('Android Application Pattern Tests', () { test('should match android application with double quotes', () { - final pattern = RegExp( - "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", - ); + final pattern = androidApplicationPluginPattern; - final testString = + const testString = 'id "com.android.application" version "8.1.0" apply false'; expect(pattern.hasMatch(testString), isTrue); @@ -19,11 +18,9 @@ void main() { }); test('should match android application with single quotes', () { - final pattern = RegExp( - "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", - ); + final pattern = androidApplicationPluginPattern; - final testString = + const testString = "id 'com.android.application' version '8.1.0' apply false"; expect(pattern.hasMatch(testString), isTrue); @@ -34,9 +31,7 @@ void main() { }); test('should match android application with mixed quotes', () { - final pattern = RegExp( - "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", - ); + final pattern = androidApplicationPluginPattern; final testStrings = [ 'id "com.android.application" version \'8.1.0\' apply false', @@ -44,15 +39,16 @@ void main() { ]; for (final testString in testStrings) { - expect(pattern.hasMatch(testString), isTrue, - reason: 'Failed for: $testString'); + expect( + pattern.hasMatch(testString), + isTrue, + reason: 'Failed for: $testString', + ); } }); test('should not match invalid android application patterns', () { - final pattern = RegExp( - "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", - ); + final pattern = androidApplicationPluginPattern; final invalidStrings = [ 'id com.android.application version 8.1.0 apply false', // no quotes @@ -61,19 +57,20 @@ void main() { ]; for (final testString in invalidStrings) { - expect(pattern.hasMatch(testString), isFalse, - reason: 'Should not match: $testString'); + expect( + pattern.hasMatch(testString), + isFalse, + reason: 'Should not match: $testString', + ); } }); }); group('Google Services Pattern Tests', () { test('should match google services with double quotes', () { - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; - final testString = + const testString = 'id "com.google.gms.google-services" version "4.4.0" apply false'; expect(pattern.hasMatch(testString), isTrue); @@ -84,11 +81,9 @@ void main() { }); test('should match google services with single quotes', () { - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; - final testString = + const testString = "id 'com.google.gms.google-services' version '4.4.0' apply false"; expect(pattern.hasMatch(testString), isTrue); @@ -99,9 +94,7 @@ void main() { }); test('should match google services with mixed quotes', () { - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; final testStrings = [ 'id "com.google.gms.google-services" version \'4.4.0\' apply false', @@ -109,15 +102,16 @@ void main() { ]; for (final testString in testStrings) { - expect(pattern.hasMatch(testString), isTrue, - reason: 'Failed for: $testString'); + expect( + pattern.hasMatch(testString), + isTrue, + reason: 'Failed for: $testString', + ); } }); test('should match different version formats', () { - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; final testStrings = [ 'id "com.google.gms.google-services" version "4.3.15" apply false', @@ -127,19 +121,20 @@ void main() { ]; for (final testString in testStrings) { - expect(pattern.hasMatch(testString), isTrue, - reason: 'Failed for: $testString'); + expect( + pattern.hasMatch(testString), + isTrue, + reason: 'Failed for: $testString', + ); } }); }); group('Kotlin DSL Google Services Pattern Tests', () { test('should match kotlin DSL with double quotes', () { - final pattern = RegExp( - "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", - ); + final pattern = kotlinGoogleServicesPluginPattern; - final testString = + const testString = 'id("com.google.gms.google-services") version("4.4.0") apply false'; expect(pattern.hasMatch(testString), isTrue); @@ -150,11 +145,9 @@ void main() { }); test('should match kotlin DSL with single quotes', () { - final pattern = RegExp( - "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", - ); + final pattern = kotlinGoogleServicesPluginPattern; - final testString = + const testString = "id('com.google.gms.google-services') version('4.4.0') apply false"; expect(pattern.hasMatch(testString), isTrue); @@ -165,9 +158,7 @@ void main() { }); test('should match kotlin DSL with mixed quotes', () { - final pattern = RegExp( - "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", - ); + final pattern = kotlinGoogleServicesPluginPattern; final testStrings = [ 'id("com.google.gms.google-services") version(\'4.4.0\') apply false', @@ -175,8 +166,11 @@ void main() { ]; for (final testString in testStrings) { - expect(pattern.hasMatch(testString), isTrue, - reason: 'Failed for: $testString'); + expect( + pattern.hasMatch(testString), + isTrue, + reason: 'Failed for: $testString', + ); } }); }); @@ -184,12 +178,10 @@ void main() { group('Firebase Performance Plugin Pattern Tests', () { test('should match performance plugin patterns with various quotes', () { // Pattern used in settings.gradle - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; // Test that performance plugin would be found after google services - final gradleContent = ''' + const gradleContent = ''' plugins { id "com.android.application" version "8.1.0" apply false id "com.google.gms.google-services" version "4.4.0" apply false @@ -201,9 +193,9 @@ plugins { expect(pattern.hasMatch(gradleContent), isTrue); // Test that it works with the actual example from the user - final performancePattern = + const performancePattern = "id 'com.google.firebase.firebase-perf' version \"1.4.2\" apply false"; - final crashlyticsPattern = + const crashlyticsPattern = 'id "com.google.firebase.crashlytics" version \'2.9.9\' apply false'; expect(gradleContent.contains(performancePattern), isTrue); @@ -213,16 +205,10 @@ plugins { group('Real-world gradle content patterns', () { test('should handle user-reported mixed quote scenarios', () { - final androidAppPattern = RegExp( - "id ([\"']com\\.android\\.application[\"']) version ([\"'][^\"']*[\"']) apply false", - ); - - final googleServicesPattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final googleServicesPattern = googleServicesPluginPattern; // Example content from the user's issue - final gradleContent = ''' + const gradleContent = ''' plugins { id "com.google.gms.google-services" version "4.4.0" apply false id 'com.google.firebase.firebase-perf' version "1.4.2" apply false @@ -246,11 +232,9 @@ plugins { }); test('should work with kotlin DSL mixed quotes', () { - final kotlinPattern = RegExp( - "id\\(([\"']com\\.google\\.gms\\.google-services[\"'])\\) version\\(([\"']\\d+\\.\\d+\\.\\d+[\"'])\\) apply false", - ); + final kotlinPattern = kotlinGoogleServicesPluginPattern; - final kotlinContent = ''' + const kotlinContent = ''' plugins { id("com.android.application") version("8.1.0") apply false id("com.google.gms.google-services") version("4.4.0") apply false @@ -265,9 +249,7 @@ plugins { group('Edge cases and error scenarios', () { test('should not match malformed patterns', () { - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; final badPatterns = [ 'id "com.google.gms.google-services version "4.4.0" apply false', // missing quote @@ -277,15 +259,16 @@ plugins { ]; for (final badPattern in badPatterns) { - expect(pattern.hasMatch(badPattern), isFalse, - reason: 'Should not match: $badPattern'); + expect( + pattern.hasMatch(badPattern), + isFalse, + reason: 'Should not match: $badPattern', + ); } }); test('should handle empty and whitespace-only strings', () { - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; expect(pattern.hasMatch(''), isFalse); expect(pattern.hasMatch(' '), isFalse); @@ -295,9 +278,7 @@ plugins { group('Version number validation', () { test('should match valid semantic version numbers', () { - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; final validVersions = [ 'id "com.google.gms.google-services" version "0.0.1" apply false', @@ -307,15 +288,16 @@ plugins { ]; for (final version in validVersions) { - expect(pattern.hasMatch(version), isTrue, - reason: 'Should match version: $version'); + expect( + pattern.hasMatch(version), + isTrue, + reason: 'Should match version: $version', + ); } }); test('should not match invalid version formats', () { - final pattern = RegExp( - "id ([\"']com\\.google\\.gms\\.google-services[\"']) version ([\"']\\d+\\.\\d+\\.\\d+[\"']) apply false", - ); + final pattern = googleServicesPluginPattern; final invalidVersions = [ 'id "com.google.gms.google-services" version "4.4" apply false', // missing patch @@ -325,8 +307,11 @@ plugins { ]; for (final version in invalidVersions) { - expect(pattern.hasMatch(version), isFalse, - reason: 'Should not match version: $version'); + expect( + pattern.hasMatch(version), + isFalse, + reason: 'Should not match version: $version', + ); } }); });