|  | // 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. | 
|  |  | 
|  | import 'package:args/command_runner.dart'; | 
|  | import 'package:file/file.dart'; | 
|  | import 'package:flutter_plugin_tools/src/common/core.dart'; | 
|  | import 'package:flutter_plugin_tools/src/license_check_command.dart'; | 
|  | import 'package:git/git.dart'; | 
|  | import 'package:path/path.dart' as p; | 
|  | import 'package:platform/platform.dart'; | 
|  | import 'package:test/test.dart'; | 
|  |  | 
|  | import 'mocks.dart'; | 
|  | import 'util.dart'; | 
|  |  | 
|  | void main() { | 
|  | group('LicenseCheckCommand', () { | 
|  | late CommandRunner<void> runner; | 
|  | late Platform platform; | 
|  | late RecordingProcessRunner gitProcessRunner; | 
|  | late Directory packagesDir; | 
|  | late Directory root; | 
|  |  | 
|  | setUp(() { | 
|  | platform = MockPlatformWithSeparator(); | 
|  | final GitDir gitDir; | 
|  | (:packagesDir, processRunner: _, :gitProcessRunner, :gitDir) = | 
|  | configureBaseCommandMocks(platform: platform); | 
|  | root = packagesDir.parent; | 
|  |  | 
|  | final LicenseCheckCommand command = LicenseCheckCommand( | 
|  | packagesDir, | 
|  | platform: platform, | 
|  | gitDir: gitDir, | 
|  | ); | 
|  | runner = | 
|  | CommandRunner<void>('license_test', 'Test for $LicenseCheckCommand'); | 
|  | runner.addCommand(command); | 
|  | }); | 
|  |  | 
|  | /// Writes a copyright+license block to [file], defaulting to a standard | 
|  | /// block for this repository. | 
|  | /// | 
|  | /// [commentString] is added to the start of each line. | 
|  | /// [prefix] is added to the start of the entire block. | 
|  | /// [suffix] is added to the end of the entire block. | 
|  | void writeLicense( | 
|  | File file, { | 
|  | String comment = '// ', | 
|  | String prefix = '', | 
|  | String suffix = '', | 
|  | String copyright = | 
|  | 'Copyright 2013 The Flutter Authors. All rights reserved.', | 
|  | List<String> license = const <String>[ | 
|  | 'Use of this source code is governed by a BSD-style license that can be', | 
|  | 'found in the LICENSE file.', | 
|  | ], | 
|  | bool useCrlf = false, | 
|  | }) { | 
|  | final List<String> lines = <String>['$prefix$comment$copyright']; | 
|  | for (final String line in license) { | 
|  | lines.add('$comment$line'); | 
|  | } | 
|  | final String newline = useCrlf ? '\r\n' : '\n'; | 
|  | file.writeAsStringSync(lines.join(newline) + suffix + newline); | 
|  | } | 
|  |  | 
|  | /// Mocks `git ls-files` to return all files in `root`, simulating a | 
|  | /// repository where everything present is checked in. | 
|  | void mockGitFilesListWithAllFiles(Directory root) { | 
|  | final String fileList = root | 
|  | .listSync(recursive: true, followLinks: false) | 
|  | .whereType<File>() | 
|  | .map((File f) => p.posix | 
|  | .joinAll(p.split(p.relative(f.absolute.path, from: root.path)))) | 
|  | .join('\n'); | 
|  |  | 
|  | gitProcessRunner.mockProcessesForExecutable['git-ls-files'] = | 
|  | <FakeProcessInfo>[ | 
|  | FakeProcessInfo(MockProcess(stdout: '$fileList\n')), | 
|  | ]; | 
|  | } | 
|  |  | 
|  | test('looks at only expected extensions', () async { | 
|  | final Map<String, bool> extensions = <String, bool>{ | 
|  | 'c': true, | 
|  | 'cc': true, | 
|  | 'cpp': true, | 
|  | 'dart': true, | 
|  | 'h': true, | 
|  | 'html': true, | 
|  | 'java': true, | 
|  | 'json': false, | 
|  | 'kt': true, | 
|  | 'm': true, | 
|  | 'md': false, | 
|  | 'mm': true, | 
|  | 'png': false, | 
|  | 'swift': true, | 
|  | 'sh': true, | 
|  | 'yaml': false, | 
|  | }; | 
|  |  | 
|  | const String filenameBase = 'a_file'; | 
|  | for (final String fileExtension in extensions.keys) { | 
|  | root.childFile('$filenameBase.$fileExtension').createSync(); | 
|  | } | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = await runCapturingPrint( | 
|  | runner, <String>['license-check'], errorHandler: (Error e) { | 
|  | // Ignore failure; the files are empty so the check is expected to fail, | 
|  | // but this test isn't for that behavior. | 
|  | }); | 
|  |  | 
|  | extensions.forEach((String fileExtension, bool shouldCheck) { | 
|  | final Matcher logLineMatcher = | 
|  | contains('Checking $filenameBase.$fileExtension'); | 
|  | expect(output, shouldCheck ? logLineMatcher : isNot(logLineMatcher)); | 
|  | }); | 
|  | }); | 
|  |  | 
|  | test('ignore list overrides extension matches', () async { | 
|  | final List<String> ignoredFiles = <String>[ | 
|  | // Ignored base names. | 
|  | 'flutter_export_environment.sh', | 
|  | 'GeneratedPluginRegistrant.java', | 
|  | 'GeneratedPluginRegistrant.m', | 
|  | 'generated_plugin_registrant.cc', | 
|  | 'generated_plugin_registrant.cpp', | 
|  | 'web_plugin_registrant.dart', | 
|  | // Ignored path suffixes. | 
|  | 'foo.g.dart', | 
|  | 'foo.mocks.dart', | 
|  | // Ignored files. | 
|  | 'resource.h', | 
|  | ]; | 
|  |  | 
|  | for (final String name in ignoredFiles) { | 
|  | root.childFile(name).createSync(); | 
|  | } | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | for (final String name in ignoredFiles) { | 
|  | expect(output, isNot(contains('Checking $name'))); | 
|  | } | 
|  | }); | 
|  |  | 
|  | test('ignores submodules', () async { | 
|  | const String submoduleName = 'a_submodule'; | 
|  |  | 
|  | final File submoduleSpec = root.childFile('.gitmodules'); | 
|  | submoduleSpec.writeAsStringSync(''' | 
|  | [submodule "$submoduleName"] | 
|  | path = $submoduleName | 
|  | url = https://github.com/foo/$submoduleName | 
|  | '''); | 
|  |  | 
|  | const List<String> submoduleFiles = <String>[ | 
|  | '$submoduleName/foo.dart', | 
|  | '$submoduleName/a/b/bar.dart', | 
|  | '$submoduleName/LICENSE', | 
|  | ]; | 
|  | for (final String filePath in submoduleFiles) { | 
|  | root.childFile(filePath).createSync(recursive: true); | 
|  | } | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | for (final String filePath in submoduleFiles) { | 
|  | expect(output, isNot(contains('Checking $filePath'))); | 
|  | } | 
|  | }); | 
|  |  | 
|  | test('ignores files that are not checked in', () async { | 
|  | mockGitFilesListWithAllFiles(root); | 
|  | // Add files after creating the mock output from created files. | 
|  | final Directory packageDir = root | 
|  | .childDirectory('FlutterGeneratedPluginSwiftPackage') | 
|  | ..createSync(); | 
|  | packageDir.childFile('Package.swift').createSync(); | 
|  | packageDir | 
|  | .childDirectory('Sources') | 
|  | .childDirectory('FlutterGeneratedPluginSwiftPackage') | 
|  | .childFile('FlutterGeneratedPluginSwiftPackage.swift') | 
|  | .createSync(recursive: true); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | expect(output, | 
|  | isNot(contains('Checking FlutterGeneratedPluginSwiftPackage'))); | 
|  | }); | 
|  |  | 
|  | test('passes if all checked files have license blocks', () async { | 
|  | final File checked = root.childFile('checked.cc'); | 
|  | checked.createSync(); | 
|  | writeLicense(checked); | 
|  | final File notChecked = root.childFile('not_checked.md'); | 
|  | notChecked.createSync(); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | // Sanity check that the test did actually check a file. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains('Checking checked.cc'), | 
|  | contains('All files passed validation!'), | 
|  | ])); | 
|  | }); | 
|  |  | 
|  | test('passes correct license blocks on Windows', () async { | 
|  | final File checked = root.childFile('checked.cc'); | 
|  | checked.createSync(); | 
|  | writeLicense(checked, useCrlf: true); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | // Sanity check that the test did actually check a file. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains('Checking checked.cc'), | 
|  | contains('All files passed validation!'), | 
|  | ])); | 
|  | }); | 
|  |  | 
|  | test('handles the comment styles for all supported languages', () async { | 
|  | final File fileA = root.childFile('file_a.cc'); | 
|  | fileA.createSync(); | 
|  | writeLicense(fileA); | 
|  | final File fileB = root.childFile('file_b.sh'); | 
|  | fileB.createSync(); | 
|  | writeLicense(fileB, comment: '# '); | 
|  | final File fileC = root.childFile('file_c.html'); | 
|  | fileC.createSync(); | 
|  | writeLicense(fileC, comment: '', prefix: '<!-- ', suffix: ' -->'); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | // Sanity check that the test did actually check the files. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains('Checking file_a.cc'), | 
|  | contains('Checking file_b.sh'), | 
|  | contains('Checking file_c.html'), | 
|  | contains('All files passed validation!'), | 
|  | ])); | 
|  | }); | 
|  |  | 
|  | test('fails if any checked files are missing license blocks', () async { | 
|  | final File goodA = root.childFile('good.cc'); | 
|  | goodA.createSync(); | 
|  | writeLicense(goodA); | 
|  | final File goodB = root.childFile('good.h'); | 
|  | goodB.createSync(); | 
|  | writeLicense(goodB); | 
|  | root.childFile('bad.cc').createSync(); | 
|  | root.childFile('bad.h').createSync(); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | Error? commandError; | 
|  | final List<String> output = await runCapturingPrint( | 
|  | runner, <String>['license-check'], errorHandler: (Error e) { | 
|  | commandError = e; | 
|  | }); | 
|  |  | 
|  | expect(commandError, isA<ToolExit>()); | 
|  | // Failure should give information about the problematic files. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains( | 
|  | 'The license block for these files is missing or incorrect:'), | 
|  | contains('  bad.cc'), | 
|  | contains('  bad.h'), | 
|  | ])); | 
|  | // Failure shouldn't print the success message. | 
|  | expect(output, isNot(contains(contains('All files passed validation!')))); | 
|  | }); | 
|  |  | 
|  | test('fails if any checked files are missing just the copyright', () async { | 
|  | final File good = root.childFile('good.cc'); | 
|  | good.createSync(); | 
|  | writeLicense(good); | 
|  | final File bad = root.childFile('bad.cc'); | 
|  | bad.createSync(); | 
|  | writeLicense(bad, copyright: ''); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | Error? commandError; | 
|  | final List<String> output = await runCapturingPrint( | 
|  | runner, <String>['license-check'], errorHandler: (Error e) { | 
|  | commandError = e; | 
|  | }); | 
|  |  | 
|  | expect(commandError, isA<ToolExit>()); | 
|  | // Failure should give information about the problematic files. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains( | 
|  | 'The license block for these files is missing or incorrect:'), | 
|  | contains('  bad.cc'), | 
|  | ])); | 
|  | // Failure shouldn't print the success message. | 
|  | expect(output, isNot(contains(contains('All files passed validation!')))); | 
|  | }); | 
|  |  | 
|  | test('fails if any checked files are missing just the license', () async { | 
|  | final File good = root.childFile('good.cc'); | 
|  | good.createSync(); | 
|  | writeLicense(good); | 
|  | final File bad = root.childFile('bad.cc'); | 
|  | bad.createSync(); | 
|  | writeLicense(bad, license: <String>[]); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | Error? commandError; | 
|  | final List<String> output = await runCapturingPrint( | 
|  | runner, <String>['license-check'], errorHandler: (Error e) { | 
|  | commandError = e; | 
|  | }); | 
|  |  | 
|  | expect(commandError, isA<ToolExit>()); | 
|  | // Failure should give information about the problematic files. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains( | 
|  | 'The license block for these files is missing or incorrect:'), | 
|  | contains('  bad.cc'), | 
|  | ])); | 
|  | // Failure shouldn't print the success message. | 
|  | expect(output, isNot(contains(contains('All files passed validation!')))); | 
|  | }); | 
|  |  | 
|  | test('fails if any third-party code is not in a third_party directory', | 
|  | () async { | 
|  | final File thirdPartyFile = root.childFile('third_party.cc'); | 
|  | thirdPartyFile.createSync(); | 
|  | writeLicense(thirdPartyFile, copyright: 'Copyright 2017 Someone Else'); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | Error? commandError; | 
|  | final List<String> output = await runCapturingPrint( | 
|  | runner, <String>['license-check'], errorHandler: (Error e) { | 
|  | commandError = e; | 
|  | }); | 
|  |  | 
|  | expect(commandError, isA<ToolExit>()); | 
|  | // Failure should give information about the problematic files. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains( | 
|  | 'The license block for these files is missing or incorrect:'), | 
|  | contains('  third_party.cc'), | 
|  | ])); | 
|  | // Failure shouldn't print the success message. | 
|  | expect(output, isNot(contains(contains('All files passed validation!')))); | 
|  | }); | 
|  |  | 
|  | test('succeeds for third-party code in a third_party directory', () async { | 
|  | final File thirdPartyFile = root | 
|  | .childDirectory('a_plugin') | 
|  | .childDirectory('lib') | 
|  | .childDirectory('src') | 
|  | .childDirectory('third_party') | 
|  | .childFile('file.cc'); | 
|  | thirdPartyFile.createSync(recursive: true); | 
|  | writeLicense(thirdPartyFile, | 
|  | copyright: 'Copyright 2017 Workiva Inc.', | 
|  | license: <String>[ | 
|  | 'Licensed under the Apache License, Version 2.0 (the "License");', | 
|  | 'you may not use this file except in compliance with the License.' | 
|  | ]); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | // Sanity check that the test did actually check the file. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains('Checking a_plugin/lib/src/third_party/file.cc'), | 
|  | contains('All files passed validation!'), | 
|  | ])); | 
|  | }); | 
|  |  | 
|  | test('allows first-party code in a third_party directory', () async { | 
|  | final File firstPartyFileInThirdParty = root | 
|  | .childDirectory('a_plugin') | 
|  | .childDirectory('lib') | 
|  | .childDirectory('src') | 
|  | .childDirectory('third_party') | 
|  | .childFile('first_party.cc'); | 
|  | firstPartyFileInThirdParty.createSync(recursive: true); | 
|  | writeLicense(firstPartyFileInThirdParty); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | // Sanity check that the test did actually check the file. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains('Checking a_plugin/lib/src/third_party/first_party.cc'), | 
|  | contains('All files passed validation!'), | 
|  | ])); | 
|  | }); | 
|  |  | 
|  | test('fails for licenses that the tool does not expect', () async { | 
|  | final File good = root.childFile('good.cc'); | 
|  | good.createSync(); | 
|  | writeLicense(good); | 
|  | final File bad = root.childDirectory('third_party').childFile('bad.cc'); | 
|  | bad.createSync(recursive: true); | 
|  | writeLicense(bad, license: <String>[ | 
|  | 'This program is free software: you can redistribute it and/or modify', | 
|  | 'it under the terms of the GNU General Public License', | 
|  | ]); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | Error? commandError; | 
|  | final List<String> output = await runCapturingPrint( | 
|  | runner, <String>['license-check'], errorHandler: (Error e) { | 
|  | commandError = e; | 
|  | }); | 
|  |  | 
|  | expect(commandError, isA<ToolExit>()); | 
|  | // Failure should give information about the problematic files. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains( | 
|  | 'No recognized license was found for the following third-party files:'), | 
|  | contains('  third_party/bad.cc'), | 
|  | ])); | 
|  | // Failure shouldn't print the success message. | 
|  | expect(output, isNot(contains(contains('All files passed validation!')))); | 
|  | }); | 
|  |  | 
|  | test('Apache is not recognized for new authors without validation changes', | 
|  | () async { | 
|  | final File good = root.childFile('good.cc'); | 
|  | good.createSync(); | 
|  | writeLicense(good); | 
|  | final File bad = root.childDirectory('third_party').childFile('bad.cc'); | 
|  | bad.createSync(recursive: true); | 
|  | writeLicense( | 
|  | bad, | 
|  | copyright: 'Copyright 2017 Some New Authors.', | 
|  | license: <String>[ | 
|  | 'Licensed under the Apache License, Version 2.0 (the "License");', | 
|  | 'you may not use this file except in compliance with the License.' | 
|  | ], | 
|  | ); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | Error? commandError; | 
|  | final List<String> output = await runCapturingPrint( | 
|  | runner, <String>['license-check'], errorHandler: (Error e) { | 
|  | commandError = e; | 
|  | }); | 
|  |  | 
|  | expect(commandError, isA<ToolExit>()); | 
|  | // Failure should give information about the problematic files. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains( | 
|  | 'No recognized license was found for the following third-party files:'), | 
|  | contains('  third_party/bad.cc'), | 
|  | ])); | 
|  | // Failure shouldn't print the success message. | 
|  | expect(output, isNot(contains(contains('All files passed validation!')))); | 
|  | }); | 
|  |  | 
|  | test('passes if all first-party LICENSE files are correctly formatted', | 
|  | () async { | 
|  | final File license = root.childFile('LICENSE'); | 
|  | license.createSync(); | 
|  | license.writeAsStringSync(_correctLicenseFileText); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | // Sanity check that the test did actually check the file. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains('Checking LICENSE'), | 
|  | contains('All files passed validation!'), | 
|  | ])); | 
|  | }); | 
|  |  | 
|  | test('passes correct LICENSE files on Windows', () async { | 
|  | final File license = root.childFile('LICENSE'); | 
|  | license.createSync(); | 
|  | license | 
|  | .writeAsStringSync(_correctLicenseFileText.replaceAll('\n', '\r\n')); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | // Sanity check that the test did actually check the file. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains('Checking LICENSE'), | 
|  | contains('All files passed validation!'), | 
|  | ])); | 
|  | }); | 
|  |  | 
|  | test('fails if any first-party LICENSE files are incorrectly formatted', | 
|  | () async { | 
|  | final File license = root.childFile('LICENSE'); | 
|  | license.createSync(); | 
|  | license.writeAsStringSync(_incorrectLicenseFileText); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | Error? commandError; | 
|  | final List<String> output = await runCapturingPrint( | 
|  | runner, <String>['license-check'], errorHandler: (Error e) { | 
|  | commandError = e; | 
|  | }); | 
|  |  | 
|  | expect(commandError, isA<ToolExit>()); | 
|  | expect(output, isNot(contains(contains('All files passed validation!')))); | 
|  | }); | 
|  |  | 
|  | test('ignores third-party LICENSE format', () async { | 
|  | final File license = | 
|  | root.childDirectory('third_party').childFile('LICENSE'); | 
|  | license.createSync(recursive: true); | 
|  | license.writeAsStringSync(_incorrectLicenseFileText); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | // The file shouldn't be checked. | 
|  | expect(output, isNot(contains(contains('Checking third_party/LICENSE')))); | 
|  | }); | 
|  |  | 
|  | test('outputs all errors at the end', () async { | 
|  | root.childFile('bad.cc').createSync(); | 
|  | root | 
|  | .childDirectory('third_party') | 
|  | .childFile('bad.cc') | 
|  | .createSync(recursive: true); | 
|  | final File license = root.childFile('LICENSE'); | 
|  | license.createSync(); | 
|  | license.writeAsStringSync(_incorrectLicenseFileText); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  |  | 
|  | Error? commandError; | 
|  | final List<String> output = await runCapturingPrint( | 
|  | runner, <String>['license-check'], errorHandler: (Error e) { | 
|  | commandError = e; | 
|  | }); | 
|  |  | 
|  | expect(commandError, isA<ToolExit>()); | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains('Checking LICENSE'), | 
|  | contains('Checking bad.cc'), | 
|  | contains('Checking third_party/bad.cc'), | 
|  | contains( | 
|  | 'The following LICENSE files do not follow the expected format:'), | 
|  | contains('  LICENSE'), | 
|  | contains( | 
|  | 'The license block for these files is missing or incorrect:'), | 
|  | contains('  bad.cc'), | 
|  | contains( | 
|  | 'No recognized license was found for the following third-party files:'), | 
|  | contains('  third_party/bad.cc'), | 
|  | ])); | 
|  | }); | 
|  |  | 
|  | test('passes if Package.swift has license blocks', () async { | 
|  | final File checked = root.childFile('Package.swift'); | 
|  | checked.createSync(); | 
|  | writeLicense(checked, prefix: '// swift-tools-version: 5.9\n'); | 
|  | mockGitFilesListWithAllFiles(root); | 
|  | final List<String> output = | 
|  | await runCapturingPrint(runner, <String>['license-check']); | 
|  |  | 
|  | // Sanity check that the test did actually check a file. | 
|  | expect( | 
|  | output, | 
|  | containsAllInOrder(<Matcher>[ | 
|  | contains('Checking Package.swift'), | 
|  | contains('All files passed validation!'), | 
|  | ])); | 
|  | }); | 
|  | }); | 
|  | } | 
|  |  | 
|  | class MockPlatformWithSeparator extends MockPlatform { | 
|  | @override | 
|  | String get pathSeparator => isWindows ? r'\' : '/'; | 
|  | } | 
|  |  | 
|  | const String _correctLicenseFileText = ''' | 
|  | Copyright 2013 The Flutter Authors. All rights reserved. | 
|  |  | 
|  | Redistribution and use in source and binary forms, with or without modification, | 
|  | are permitted provided that the following conditions are met: | 
|  |  | 
|  | * Redistributions of source code must retain the above copyright | 
|  | notice, this list of conditions and the following disclaimer. | 
|  | * Redistributions in binary form must reproduce the above | 
|  | copyright notice, this list of conditions and the following | 
|  | disclaimer in the documentation and/or other materials provided | 
|  | with the distribution. | 
|  | * Neither the name of Google Inc. nor the names of its | 
|  | contributors may be used to endorse or promote products derived | 
|  | from this software without specific prior written permission. | 
|  |  | 
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | 
|  | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 
|  | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
|  | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | 
|  | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 
|  | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
|  | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | 
|  | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 
|  | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | '''; | 
|  |  | 
|  | // A common incorrect version created by copying text intended for a code file, | 
|  | // with comment markers. | 
|  | const String _incorrectLicenseFileText = ''' | 
|  | // Copyright 2013 The Flutter Authors. All rights reserved. | 
|  | // | 
|  | // Redistribution and use in source and binary forms, with or without | 
|  | // modification, are permitted provided that the following conditions are | 
|  | // met: | 
|  | // | 
|  | //    * Redistributions of source code must retain the above copyright | 
|  | // notice, this list of conditions and the following disclaimer. | 
|  | //    * Redistributions in binary form must reproduce the above | 
|  | // copyright notice, this list of conditions and the following disclaimer | 
|  | // in the documentation and/or other materials provided with the | 
|  | // distribution. | 
|  | //    * Neither the name of Google Inc. nor the names of its | 
|  | // contributors may be used to endorse or promote products derived from | 
|  | // this software without specific prior written permission. | 
|  | // | 
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | '''; |