blob: 00b0f0d7c4823d9a94b93c6c58a95c3b221e2cbc [file] [log] [blame]
// Copyright 2022 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 'dart:convert';
import 'package:auto_submit/service/github_service.dart';
import 'package:github/github.dart';
import 'package:shelf/src/response.dart';
import '../../utilities/mocks.dart';
/// A fake GithubService implementation.
class FakeGithubService implements GithubService {
FakeGithubService({
MockGitHub? client,
String? checkRunsMock,
String? commitMock,
String? pullRequest,
String? compareTwoCommitsMock,
String? successMergeMock,
String? createCommentMock,
String? pullRequestMergeMock,
}) : github = client ?? MockGitHub();
@override
final MockGitHub github;
String? checkRunsMock;
String? commitMock;
PullRequest? pullRequestMock;
String? compareTwoCommitsMock;
String? successMergeMock;
String? createCommentMock;
String? pullRequestMergeMock;
String? pullRequestFilesJsonMock;
Issue? githubIssueMock;
String? githubFileContents;
bool useMergeRequestMockList = false;
bool trackMergeRequestCalls = false;
PullRequestMerge? mergeRequestMock;
List<PullRequestMerge> pullRequestMergeMockList = [];
/// map to track pull request calls using pull number and repository slug.
Map<int, RepositorySlug> verifyPullRequestMergeCallMap = {};
bool throwOnCreateIssue = false;
/// Setting either of these flags to true will pop the front element from the
/// list. Setting either to false will just return the non list version from
/// the appropriate method.
bool usePullRequestList = false;
bool usePullRequestFilesList = false;
List<String?> pullRequestFilesMockList = [];
List<PullRequest?> pullRequestMockList = [];
IssueComment? issueComment;
bool useRealComment = false;
bool labelRemoved = false;
bool compareReturnValue = false;
bool skipRealCompare = false;
set checkRunsData(String? checkRunsMock) {
this.checkRunsMock = checkRunsMock;
}
set commitData(String? commitMock) {
this.commitMock = commitMock;
}
set pullRequestData(PullRequest? pullRequestMock) {
this.pullRequestMock = pullRequestMock;
}
set compareTwoCommitsData(String? compareTwoCommitsMock) {
this.compareTwoCommitsMock = compareTwoCommitsMock;
}
set successMergeData(String? successMergeMock) {
this.successMergeMock = successMergeMock;
}
set createCommentData(String? createCommentMock) {
this.createCommentMock = createCommentMock;
}
set pullRequestMergeData(String? pullRequestMergeMock) {
this.pullRequestMergeMock = pullRequestMergeMock;
}
set pullrequestFilesData(String? pullRequestFilesMock) {
pullRequestFilesJsonMock = pullRequestFilesMock;
}
set githubIssue(Issue? issue) {
githubIssueMock = issue;
}
@override
Future<List<CheckRun>> getCheckRuns(
RepositorySlug slug,
String ref,
) async {
final rawBody = json.decode(checkRunsMock!) as Map<String, dynamic>;
final List<dynamic> checkRunsBody = rawBody['check_runs']! as List<dynamic>;
final List<CheckRun> checkRuns = <CheckRun>[];
if ((checkRunsBody[0] as Map<String, dynamic>).isNotEmpty) {
checkRuns.addAll(
checkRunsBody.map((dynamic checkRun) => CheckRun.fromJson(checkRun as Map<String, dynamic>)).toList(),
);
}
return checkRuns;
}
@override
Future<List<CheckRun>> getCheckRunsFiltered({
required RepositorySlug slug,
required String ref,
String? checkName,
CheckRunStatus? status,
CheckRunFilter? filter,
}) async {
final List<CheckRun> checkRuns = await getCheckRuns(slug, ref);
if (checkName != null) {
final List<CheckRun> checkRunsFilteredByName = [];
for (CheckRun checkRun in checkRuns) {
if (checkRun.name == checkName) {
checkRunsFilteredByName.add(checkRun);
}
}
return checkRunsFilteredByName;
}
return checkRuns;
}
@override
Future<RepositoryCommit> getCommit(RepositorySlug slug, String sha) async {
final RepositoryCommit commit = RepositoryCommit.fromJson(jsonDecode(commitMock!) as Map<String, dynamic>);
return commit;
}
@override
Future<PullRequest> getPullRequest(RepositorySlug slug, int pullRequestNumber) async {
PullRequest pullRequest;
if (usePullRequestList && pullRequestMockList.isNotEmpty) {
pullRequest = pullRequestMockList.removeAt(0)!;
} else if (usePullRequestList && pullRequestMockList.isEmpty) {
throw Exception('List is empty.');
} else {
pullRequest = pullRequestMock!;
}
return pullRequest;
}
@override
Future<GitHubComparison> compareTwoCommits(RepositorySlug slug, String refBase, String refHead) async {
final GitHubComparison githubComparison =
GitHubComparison.fromJson(jsonDecode(compareTwoCommitsMock!) as Map<String, dynamic>);
return githubComparison;
}
@override
Future<bool> removeLabel(RepositorySlug slug, int issueNumber, String label) async {
labelRemoved = true;
return labelRemoved;
}
@override
Future<List<IssueLabel>> addLabels(RepositorySlug slug, int issueNumber, List<String> labels) async {
final List<IssueLabel> labelsAdded = [];
for (String labelName in labels) {
labelsAdded.add(IssueLabel(name: labelName));
}
return labelsAdded;
}
@override
Future<IssueComment> createComment(RepositorySlug slug, int number, String commentBody) async {
if (useRealComment) {
issueComment = IssueComment(id: number, body: commentBody);
} else {
issueComment = IssueComment.fromJson(jsonDecode(createCommentMock!) as Map<String, dynamic>);
}
return issueComment!;
}
@override
Future<bool> updateBranch(RepositorySlug slug, int number, String headSha) async {
return true;
}
@override
Future<Response> autoMergeBranch(PullRequest pullRequest) {
// TODO: implement autoMergeBranch
throw UnimplementedError();
}
@override
Future<List<PullRequestFile>> getPullRequestFiles(RepositorySlug slug, PullRequest pullRequest) async {
String pullRequestData;
if (usePullRequestFilesList && pullRequestFilesMockList.isNotEmpty) {
pullRequestData = pullRequestFilesMockList.removeAt(0)!;
} else if (usePullRequestFilesList && pullRequestFilesMockList.isEmpty) {
throw Exception('File list is empty.');
} else {
pullRequestData = pullRequestFilesJsonMock as String;
}
final List<PullRequestFile> pullRequestFileList = [];
final dynamic parsedList = jsonDecode(pullRequestData);
for (dynamic d in parsedList) {
final PullRequestFile file = PullRequestFile.fromJson(d as Map<String, dynamic>);
pullRequestFileList.add(file);
}
return pullRequestFileList;
}
@override
Future<Issue> createIssue({
required RepositorySlug slug,
required String title,
required String body,
List<String>? labels,
String? assignee,
List<String>? assignees,
String? state,
}) async {
if (throwOnCreateIssue) {
throw GitHubError(github, 'Exception on github create issue.');
}
return githubIssueMock!;
}
@override
Future<Issue> getIssue({required RepositorySlug slug, required int issueNumber}) async {
return githubIssueMock!;
}
bool throwExceptionOnMerge = false;
/// If useMergeRequestMockList is true then we will return elements from that
/// list until it is empty.
///
/// The developer should track the number of times this method is called as
/// managing an empty list is not done here.
@override
Future<PullRequestMerge> mergePullRequest(
RepositorySlug slug,
int number, {
String? commitMessage,
MergeMethod? mergeMethod,
String? requestSha,
}) async {
if (throwExceptionOnMerge) {
throw Exception('Exception occurred during merging of pull request.');
}
verifyPullRequestMergeCallMap[number] = slug;
if (useMergeRequestMockList) {
return pullRequestMergeMockList.removeAt(0);
} else {
return mergeRequestMock!;
}
}
void verifyMergePullRequests(Map<int, RepositorySlug> expected) {
assert(verifyPullRequestMergeCallMap.length == expected.length);
verifyPullRequestMergeCallMap.forEach((key, value) {
assert(expected.containsKey(key));
assert(expected[key] == value);
});
}
bool throwExceptionFileContents = false;
List<String> fileContentsMockList = [];
@override
Future<String> getFileContents(RepositorySlug slug, String path, {String? ref}) async {
if (throwExceptionFileContents) {
throw 'Contents do not point to a file.';
}
// Assume that the list is not empty.
return fileContentsMockList.removeAt(0);
}
TeamMembershipState? teamMembershipStateMock = TeamMembershipState('active');
String defaultBranch = 'main';
bool throwOnDefaultBranch = false;
Exception exception = Exception('Generic exception.');
@override
Future<String> getDefaultBranch(RepositorySlug slug) async {
if (throwOnDefaultBranch) {
throw exception;
} else {
return defaultBranch;
}
}
Repository repositoryMock = Repository();
@override
Future<Repository> getRepository(RepositorySlug slug) async {
return repositoryMock;
}
Map<String, bool> isTeamMemberMockMap = <String, bool>{};
@override
Future<bool> isTeamMember(String team, String user, String org) async {
if (!isTeamMemberMockMap.containsKey(user)) {
return false;
}
return isTeamMemberMockMap[user]!;
}
@override
Future<PullRequest> createPullRequest({
required RepositorySlug slug,
String? title,
String? head,
required String base,
bool draft = false,
String? body,
}) {
// TODO: implement createPullRequest
throw UnimplementedError();
}
@override
Future<List<PullRequest>> listPullRequests(
RepositorySlug slug, {
int? pages,
String? base,
String direction = 'desc',
String? head,
String sort = 'created',
String state = 'open',
}) {
// TODO: implement listPullRequests
throw UnimplementedError();
}
String? branchMockData;
set branchMock(String data) => branchMock = data;
@override
Future<Branch> getBranch(RepositorySlug slug, String branchName) async {
return Branch.fromJson(json.decode(branchMockData!));
}
bool addReviewersToPullRequestMock = true;
@override
Future<bool> addReviewersToPullRequest(
RepositorySlug slug,
int pullRequestNumber,
List<String> reviewerLogins,
) async {
return addReviewersToPullRequestMock;
}
bool addAssigneeMock = true;
@override
Future<bool> addAssignee(
RepositorySlug slug,
int number,
List<String> assignees,
) async {
return addAssigneeMock;
}
bool deleteBranchMock = true;
@override
Future<bool> deleteBranch(RepositorySlug slug, String branchName) async {
return deleteBranchMock;
}
}