| // 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:file/file.dart'; |
| import 'package:file/memory.dart'; |
| import 'package:flutter_tools/src/base/io.dart'; |
| import 'package:flutter_tools/src/base/net.dart'; |
| import 'package:flutter_tools/src/reporting/github_template.dart'; |
| |
| import '../src/common.dart'; |
| import '../src/context.dart'; |
| import '../src/testbed.dart'; |
| |
| const String _kShortURL = 'https://www.example.com/short'; |
| |
| void main() { |
| group('GitHub template creator', () { |
| testUsingContext('similar issues URL', () async { |
| final GitHubTemplateCreator creator = GitHubTemplateCreator(); |
| expect( |
| await creator.toolCrashSimilarIssuesGitHubURL('this is a 100% error'), |
| _kShortURL |
| ); |
| }, overrides: <Type, Generator>{ |
| HttpClientFactory: () => () => SuccessShortenURLFakeHttpClient(), |
| FileSystem: () => MemoryFileSystem(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('similar issues URL with network failure', () async { |
| final GitHubTemplateCreator creator = GitHubTemplateCreator(); |
| expect( |
| await creator.toolCrashSimilarIssuesGitHubURL('this is a 100% error'), |
| 'https://github.com/flutter/flutter/issues?q=is%3Aissue+this+is+a+100%25+error' |
| ); |
| }, overrides: <Type, Generator>{ |
| HttpClientFactory: () => () => FakeHttpClient(), |
| FileSystem: () => MemoryFileSystem(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| group('new issue template URL', () { |
| StackTrace stackTrace; |
| const String command = 'flutter test'; |
| const String errorString = 'this is a 100% error'; |
| const String exception = 'failing to succeed!!!'; |
| const String doctorText = ' [✓] Flutter (Channel report'; |
| FileSystem fs; |
| |
| setUp(() async { |
| stackTrace = StackTrace.fromString('trace'); |
| fs = MemoryFileSystem(); |
| }); |
| |
| testUsingContext('shortened', () async { |
| final GitHubTemplateCreator creator = GitHubTemplateCreator(); |
| expect( |
| await creator.toolCrashIssueTemplateGitHubURL(command, errorString, exception, stackTrace, doctorText), |
| _kShortURL |
| ); |
| }, overrides: <Type, Generator>{ |
| HttpClientFactory: () => () => SuccessShortenURLFakeHttpClient(), |
| FileSystem: () => MemoryFileSystem(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('with network failure', () async { |
| final GitHubTemplateCreator creator = GitHubTemplateCreator(); |
| expect( |
| await creator.toolCrashIssueTemplateGitHubURL(command, errorString, exception, stackTrace, doctorText), |
| 'https://github.com/flutter/flutter/issues/new?title=%5Btool_crash%5D+this+is+a+100%25+error&body=%23%' |
| '23+Command%0A%60%60%60%0Aflutter+test%0A%60%60%60%0A%0A%23%23+Steps+to+Reproduce%0A1.+...' |
| '%0A2.+...%0A3.+...%0A%0A%23%23+Logs%0Afailing+to+succeed%21%21%21%0A%60%60%60%0Atrace%0A' |
| '%60%60%60%0A%60%60%60%0A+%5B%E2%9C%93%5D+Flutter+%28Channel+report%0A%60%60%60%0A%0A%23%23' |
| '+Flutter+Application+Metadata%0ANo+pubspec+in+working+directory.%0A&labels=tool%2Csevere%3A+crash' |
| ); |
| }, overrides: <Type, Generator>{ |
| HttpClientFactory: () => () => FakeHttpClient(), |
| FileSystem: () => MemoryFileSystem(), |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| |
| testUsingContext('app metadata', () async { |
| final GitHubTemplateCreator creator = GitHubTemplateCreator(); |
| final Directory projectDirectory = fs.currentDirectory; |
| final File pluginsFile = projectDirectory.childFile('.flutter-plugins'); |
| |
| projectDirectory |
| .childFile('pubspec.yaml') |
| .writeAsStringSync(''' |
| name: failing_app |
| version: 2.0.1+100 |
| flutter: |
| uses-material-design: true |
| module: |
| androidX: true |
| androidPackage: com.example.failing.android |
| iosBundleIdentifier: com.example.failing.ios |
| '''); |
| |
| pluginsFile |
| .writeAsStringSync(''' |
| camera=/fake/pub.dartlang.org/camera-0.5.7+2/ |
| device_info=/fake/pub.dartlang.org/pub.dartlang.org/device_info-0.4.1+4/ |
| '''); |
| |
| final String actualURL = await creator.toolCrashIssueTemplateGitHubURL(command, errorString, exception, stackTrace, doctorText); |
| final String actualBody = Uri.parse(actualURL).queryParameters['body']; |
| const String expectedBody = '''## Command |
| ``` |
| flutter test |
| ``` |
| |
| ## Steps to Reproduce |
| 1. ... |
| 2. ... |
| 3. ... |
| |
| ## Logs |
| failing to succeed!!! |
| ``` |
| trace |
| ``` |
| ``` |
| [✓] Flutter (Channel report |
| ``` |
| |
| ## Flutter Application Metadata |
| **Version**: 2.0.1+100 |
| **Material**: true |
| **Android X**: true |
| **Module**: true |
| **Plugin**: false |
| **Android package**: com.example.failing.android |
| **iOS bundle identifier**: com.example.failing.ios |
| ### Plugins |
| camera-0.5.7+2 |
| device_info-0.4.1+4 |
| |
| '''; |
| |
| expect(actualBody, expectedBody); |
| }, overrides: <Type, Generator>{ |
| HttpClientFactory: () => () => FakeHttpClient(), |
| FileSystem: () => fs, |
| ProcessManager: () => FakeProcessManager.any(), |
| }); |
| }); |
| }); |
| } |
| |
| |
| class SuccessFakeHttpHeaders extends FakeHttpHeaders { |
| @override |
| List<String> operator [](String name) => <String>[_kShortURL]; |
| } |
| |
| class SuccessFakeHttpClientResponse extends FakeHttpClientResponse { |
| @override |
| int get statusCode => 201; |
| |
| @override |
| HttpHeaders get headers { |
| return SuccessFakeHttpHeaders(); |
| } |
| } |
| |
| class SuccessFakeHttpClientRequest extends FakeHttpClientRequest { |
| @override |
| Future<HttpClientResponse> close() async { |
| return SuccessFakeHttpClientResponse(); |
| } |
| } |
| |
| class SuccessShortenURLFakeHttpClient extends FakeHttpClient { |
| @override |
| Future<HttpClientRequest> postUrl(Uri url) async { |
| return SuccessFakeHttpClientRequest(); |
| } |
| } |