// Copyright 2014 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. import 'package:args/args.dart'; import 'package:conductor_core/src/globals.dart'; import 'package:conductor_core/src/proto/conductor_state.pb.dart' as pb; import './common.dart'; void main() { test('assertsEnabled returns true in test suite', () { expect(assertsEnabled(), true); }); group('getNewPrLink', () { const String userName = 'flutterer'; const String releaseChannel = 'beta'; const String releaseVersion = '1.2.0-3.4.pre'; const String candidateBranch = 'flutter-1.2-candidate.3'; const String workingBranch = 'cherrypicks-$candidateBranch'; const String dartRevision = 'fe9708ab688dcda9923f584ba370a66fcbc3811f'; const String engineCherrypick1 = 'a5a25cd702b062c24b2c67b8d30b5cb33e0ef6f0'; const String engineCherrypick2 = '94d06a2e1d01a3b0c693b94d70c5e1df9d78d249'; const String frameworkCherrypick = 'a5a25cd702b062c24b2c67b8d30b5cb33e0ef6f0'; final RegExp titlePattern = RegExp(r'&title=(.*)&'); final RegExp bodyPattern = RegExp(r'&body=(.*)$'); late pb.ConductorState state; setUp(() { state = pb.ConductorState( engine: pb.Repository( candidateBranch: candidateBranch, cherrypicks: <pb.Cherrypick>[ pb.Cherrypick(trunkRevision: engineCherrypick1), pb.Cherrypick(trunkRevision: engineCherrypick2), ], dartRevision: dartRevision, workingBranch: workingBranch, ), framework: pb.Repository( candidateBranch: candidateBranch, cherrypicks: <pb.Cherrypick>[ pb.Cherrypick(trunkRevision: frameworkCherrypick), ], workingBranch: workingBranch, ), releaseChannel: releaseChannel, releaseVersion: releaseVersion, ); }); test('throws on an invalid repoName', () { expect( () => getNewPrLink( repoName: 'flooter', userName: userName, state: state, ), throwsExceptionWith( 'Expected repoName to be one of flutter or engine but got flooter.', ), ); }); test('returns a valid URL for engine', () { final String link = getNewPrLink( repoName: 'engine', userName: userName, state: state, ); expect( link, contains('https://github.com/flutter/engine/compare/'), ); expect( link, contains('$candidateBranch...$userName:$workingBranch?expand=1'), ); expect( Uri.decodeQueryComponent( titlePattern.firstMatch(link)?.group(1) ?? ''), '[flutter_releases] Flutter $releaseChannel $releaseVersion Engine Cherrypicks'); final String expectedBody = ''' # Flutter $releaseChannel $releaseVersion Engine ## Scheduled Cherrypicks - Roll dart revision: dart-lang/sdk@${dartRevision.substring(0, 9)} - commit: flutter/engine@${engineCherrypick1.substring(0, 9)} - commit: flutter/engine@${engineCherrypick2.substring(0, 9)} '''; expect( Uri.decodeQueryComponent(bodyPattern.firstMatch(link)?.group(1) ?? ''), expectedBody, ); }); test('returns a valid URL for framework', () { final String link = getNewPrLink( repoName: 'flutter', userName: userName, state: state, ); expect( link, contains('https://github.com/flutter/flutter/compare/'), ); expect( link, contains('$candidateBranch...$userName:$workingBranch?expand=1'), ); expect( Uri.decodeQueryComponent( titlePattern.firstMatch(link)?.group(1) ?? ''), '[flutter_releases] Flutter $releaseChannel $releaseVersion Framework Cherrypicks'); final String expectedBody = ''' # Flutter $releaseChannel $releaseVersion Framework ## Scheduled Cherrypicks - commit: ${frameworkCherrypick.substring(0, 9)} '''; expect( Uri.decodeQueryComponent(bodyPattern.firstMatch(link)?.group(1) ?? ''), expectedBody, ); }); }); group('getBoolFromEnvOrArgs', () { const String flagName = 'a-cli-flag'; test('prefers env over argResults', () { final ArgResults argResults = FakeArgs(results: <String, Object>{ flagName: false, }); final Map<String, String> env = <String, String>{'A_CLI_FLAG': 'TRUE'}; final bool result = getBoolFromEnvOrArgs( flagName, argResults, env, ); expect(result, true); }); test('falls back to argResults if env is empty', () { final ArgResults argResults = FakeArgs(results: <String, Object>{ flagName: false, }); final Map<String, String> env = <String, String>{}; final bool result = getBoolFromEnvOrArgs( flagName, argResults, env, ); expect(result, false); }); }); } class FakeArgs implements ArgResults { FakeArgs({ this.arguments = const <String>[], this.name = 'fake-command', this.results = const <String, Object>{}, }); final Map<String, Object> results; @override final List<String> arguments; @override final String name; @override ArgResults? get command => throw Exception('Unimplemented'); @override List<String> get rest => throw Exception('Unimplemented'); @override Iterable<String> get options => throw Exception('Unimplemented'); @override bool wasParsed(String name) { return results[name] != null; } @override Object? operator[](String name) { return results[name]; } }