// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.acceptance.server.change;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.testutil.TestChanges.newChange;
import static com.google.gerrit.testutil.TestChanges.newPatchSet;
import static java.util.Collections.singleton;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.extensions.api.changes.FixInput;
import com.google.gerrit.extensions.common.ProblemInfo;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.change.ConsistencyChecker;
import com.google.gerrit.testutil.TestChanges;
import com.google.inject.Inject;
import com.google.inject.Provider;

import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;

import java.util.List;

@NoHttpd
public class ConsistencyCheckerIT extends AbstractDaemonTest {
  @Inject
  private Provider<ConsistencyChecker> checkerProvider;

  private RevCommit tip;
  private Account.Id adminId;
  private ConsistencyChecker checker;

  @Before
  public void setUp() throws Exception {
    // Ignore client clone of project; repurpose as server-side TestRepository.
    testRepo = new TestRepository<>(
        (InMemoryRepository) repoManager.openRepository(project));
    tip = testRepo.getRevWalk().parseCommit(
        testRepo.getRepository().getRef("HEAD").getObjectId());
    adminId = admin.getId();
    checker = checkerProvider.get();
  }

  @Test
  public void validNewChange() throws Exception {
    Change c = insertChange();
    insertPatchSet(c);
    incrementPatchSet(c);
    insertPatchSet(c);
    assertProblems(c);
  }

  @Test
  public void validMergedChange() throws Exception {
    Change c = insertChange();
    c.setStatus(Change.Status.MERGED);
    insertPatchSet(c);
    incrementPatchSet(c);

    incrementPatchSet(c);
    RevCommit commit2 = testRepo.branch(c.currentPatchSetId().toRefName()).commit()
        .parent(tip).create();
    PatchSet ps2 = newPatchSet(c.currentPatchSetId(), commit2, adminId);
    db.patchSets().insert(singleton(ps2));

    testRepo.branch(c.getDest().get()).update(commit2);
    assertProblems(c);
  }

  @Test
  public void missingOwner() throws Exception {
    Change c = newChange(project, new Account.Id(2));
    db.changes().insert(singleton(c));
    RevCommit commit = testRepo.branch(c.currentPatchSetId().toRefName()).commit()
        .parent(tip).create();
    PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
    db.patchSets().insert(singleton(ps));

    assertProblems(c, "Missing change owner: 2");
  }

  @Test
  public void missingRepo() throws Exception {
    Change c = newChange(new Project.NameKey("otherproject"), adminId);
    db.changes().insert(singleton(c));
    insertMissingPatchSet(c, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
    assertProblems(c, "Destination repository not found: otherproject");
  }

  @Test
  public void invalidRevision() throws Exception {
    Change c = insertChange();

    db.patchSets().insert(singleton(newPatchSet(c.currentPatchSetId(),
            "fooooooooooooooooooooooooooooooooooooooo", adminId)));
    incrementPatchSet(c);
    insertPatchSet(c);

    assertProblems(c,
        "Invalid revision on patch set 1:"
        + " fooooooooooooooooooooooooooooooooooooooo");
  }

  // No test for ref existing but object missing; InMemoryRepository won't let
  // us do such a thing.

  @Test
  public void patchSetObjectAndRefMissing() throws Exception {
    Change c = insertChange();
    PatchSet ps = newPatchSet(c.currentPatchSetId(),
        ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), adminId);
    db.patchSets().insert(singleton(ps));

    assertProblems(c,
        "Ref missing: " + ps.getId().toRefName(),
        "Object missing: patch set 1: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
  }

  @Test
  public void patchSetObjectAndRefMissingWithFix() throws Exception {
    Change c = insertChange();
    PatchSet ps = newPatchSet(c.currentPatchSetId(),
        ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"), adminId);
    db.patchSets().insert(singleton(ps));

    String refName = ps.getId().toRefName();
    List<ProblemInfo> problems = checker.check(c, new FixInput()).problems();
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo("Ref missing: " + refName);
    assertThat(p.status).isNull();
  }

  @Test
  public void patchSetRefMissing() throws Exception {
    Change c = insertChange();
    PatchSet ps = insertPatchSet(c);
    String refName = ps.getId().toRefName();
    testRepo.update("refs/other/foo", ObjectId.fromString(ps.getRevision().get()));
    deleteRef(refName);

    assertProblems(c, "Ref missing: " + refName);
  }

  @Test
  public void patchSetRefMissingWithFix() throws Exception {
    Change c = insertChange();
    PatchSet ps = insertPatchSet(c);
    String refName = ps.getId().toRefName();
    testRepo.update("refs/other/foo", ObjectId.fromString(ps.getRevision().get()));
    deleteRef(refName);

    List<ProblemInfo> problems = checker.check(c, new FixInput()).problems();
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo("Ref missing: " + refName);
    assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
    assertThat(p.outcome).isEqualTo("Repaired patch set ref");

    assertThat(testRepo.getRepository().getRef(refName).getObjectId().name())
        .isEqualTo(ps.getRevision().get());
  }

  @Test
  public void patchSetObjectAndRefMissingWithDeletingPatchSet()
      throws Exception {
    Change c = insertChange();
    PatchSet ps1 = insertPatchSet(c);
    incrementPatchSet(c);
    PatchSet ps2 = insertMissingPatchSet(c,
        "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");

    FixInput fix = new FixInput();
    fix.deletePatchSetIfCommitMissing = true;
    List<ProblemInfo> problems = checker.check(c, fix).problems();
    assertThat(problems).hasSize(2);
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo("Ref missing: " + ps2.getId().toRefName());
    assertThat(p.status).isNull();
    p = problems.get(1);
    assertThat(p.message).isEqualTo(
        "Object missing: patch set 2: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
    assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
    assertThat(p.outcome).isEqualTo("Deleted patch set");

    c = db.changes().get(c.getId());
    assertThat(c.currentPatchSetId().get()).isEqualTo(1);
    assertThat(db.patchSets().get(ps1.getId())).isNotNull();
    assertThat(db.patchSets().get(ps2.getId())).isNull();
  }

  @Test
  public void patchSetMultipleObjectsMissingWithDeletingPatchSets()
      throws Exception {
    Change c = insertChange();
    PatchSet ps1 = insertPatchSet(c);

    incrementPatchSet(c);
    PatchSet ps2 = insertMissingPatchSet(c,
        "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");

    incrementPatchSet(c);
    PatchSet ps3 = insertPatchSet(c);

    incrementPatchSet(c);
    PatchSet ps4 = insertMissingPatchSet(c,
        "c0ffeeeec0ffeeeec0ffeeeec0ffeeeec0ffeeee");

    FixInput fix = new FixInput();
    fix.deletePatchSetIfCommitMissing = true;
    List<ProblemInfo> problems = checker.check(c, fix).problems();
    assertThat(problems).hasSize(4);

    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo("Ref missing: " + ps4.getId().toRefName());
    assertThat(p.status).isNull();

    p = problems.get(1);
    assertThat(p.message).isEqualTo(
        "Object missing: patch set 4: c0ffeeeec0ffeeeec0ffeeeec0ffeeeec0ffeeee");
    assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
    assertThat(p.outcome).isEqualTo("Deleted patch set");

    p = problems.get(2);
    assertThat(p.message).isEqualTo("Ref missing: " + ps2.getId().toRefName());
    assertThat(p.status).isNull();

    p = problems.get(3);
    assertThat(p.message).isEqualTo(
        "Object missing: patch set 2: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
    assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
    assertThat(p.outcome).isEqualTo("Deleted patch set");

    c = db.changes().get(c.getId());
    assertThat(c.currentPatchSetId().get()).isEqualTo(3);
    assertThat(db.patchSets().get(ps1.getId())).isNotNull();
    assertThat(db.patchSets().get(ps2.getId())).isNull();
    assertThat(db.patchSets().get(ps3.getId())).isNotNull();
    assertThat(db.patchSets().get(ps4.getId())).isNull();
  }

  @Test
  public void onlyPatchSetObjectMissingWithFix() throws Exception {
    Change c = insertChange();
    PatchSet ps1 = insertMissingPatchSet(c,
        "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");

    FixInput fix = new FixInput();
    fix.deletePatchSetIfCommitMissing = true;
    List<ProblemInfo> problems = checker.check(c, fix).problems();
    assertThat(problems).hasSize(2);
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo("Ref missing: " + ps1.getId().toRefName());
    assertThat(p.status).isNull();
    p = problems.get(1);
    assertThat(p.message).isEqualTo(
        "Object missing: patch set 1: deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
    assertThat(p.status).isEqualTo(ProblemInfo.Status.FIX_FAILED);
    assertThat(p.outcome)
        .isEqualTo("Cannot delete patch set; no patch sets would remain");

    c = db.changes().get(c.getId());
    assertThat(c.currentPatchSetId().get()).isEqualTo(1);
    assertThat(db.patchSets().get(ps1.getId())).isNotNull();
  }

  @Test
  public void currentPatchSetMissing() throws Exception {
    Change c = insertChange();
    assertProblems(c, "Current patch set 1 not found");
  }

  @Test
  public void duplicatePatchSetRevisions() throws Exception {
    Change c = insertChange();
    PatchSet ps1 = insertPatchSet(c);
    String rev = ps1.getRevision().get();
    incrementPatchSet(c);
    PatchSet ps2 = insertMissingPatchSet(c, rev);
    updatePatchSetRef(ps2);

    assertProblems(c,
        "Multiple patch sets pointing to " + rev + ": [1, 2]");
  }

  @Test
  public void missingDestRef() throws Exception {
    String ref = "refs/heads/master";
    // Detach head so we're allowed to delete ref.
    testRepo.reset(testRepo.getRepository().getRef(ref).getObjectId());
    RefUpdate ru = testRepo.getRepository().updateRef(ref);
    ru.setForceUpdate(true);
    assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED);
    Change c = insertChange();
    RevCommit commit = testRepo.commit().create();
    PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
    updatePatchSetRef(ps);
    db.patchSets().insert(singleton(ps));

    assertProblems(c, "Destination ref not found (may be new branch): " + ref);
  }

  @Test
  public void mergedChangeIsNotMerged() throws Exception {
    Change c = insertChange();
    c.setStatus(Change.Status.MERGED);
    PatchSet ps = insertPatchSet(c);
    String rev = ps.getRevision().get();

    assertProblems(c,
        "Patch set 1 (" + rev + ") is not merged into destination ref"
        + " refs/heads/master (" + tip.name()
        + "), but change status is MERGED");
  }

  @Test
  public void newChangeIsMerged() throws Exception {
    Change c = insertChange();
    RevCommit commit = testRepo.branch(c.currentPatchSetId().toRefName()).commit()
        .parent(tip).create();
    PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
    db.patchSets().insert(singleton(ps));
    testRepo.branch(c.getDest().get()).update(commit);

    assertProblems(c,
        "Patch set 1 (" + commit.name() + ") is merged into destination ref"
        + " refs/heads/master (" + commit.name()
        + "), but change status is NEW");
  }

  @Test
  public void newChangeIsMergedWithFix() throws Exception {
    Change c = insertChange();
    RevCommit commit = testRepo.branch(c.currentPatchSetId().toRefName()).commit()
        .parent(tip).create();
    PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
    db.patchSets().insert(singleton(ps));
    testRepo.branch(c.getDest().get()).update(commit);

    List<ProblemInfo> problems = checker.check(c, new FixInput()).problems();
    assertThat(problems).hasSize(1);
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo(
        "Patch set 1 (" + commit.name() + ") is merged into destination ref"
        + " refs/heads/master (" + commit.name()
        + "), but change status is NEW");
    assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
    assertThat(p.outcome).isEqualTo("Marked change as merged");

    c = db.changes().get(c.getId());
    assertThat(c.getStatus()).isEqualTo(Change.Status.MERGED);
    assertProblems(c);
  }

  @Test
  public void expectedMergedCommitIsLatestPatchSet() throws Exception {
    Change c = insertChange();
    c.setStatus(Change.Status.MERGED);
    PatchSet ps = insertPatchSet(c);
    RevCommit commit = parseCommit(ps);
    testRepo.update(c.getDest().get(), commit);

    FixInput fix = new FixInput();
    fix.expectMergedAs = commit.name();
    assertThat(checker.check(c, fix).problems()).isEmpty();
  }

  @Test
  public void expectedMergedCommitNotMergedIntoDestination() throws Exception {
    Change c = insertChange();
    c.setStatus(Change.Status.MERGED);
    PatchSet ps = insertPatchSet(c);
    RevCommit commit = parseCommit(ps);
    testRepo.update(c.getDest().get(), commit);

    FixInput fix = new FixInput();
    RevCommit other =
        testRepo.commit().message(commit.getFullMessage()).create();
    fix.expectMergedAs = other.name();
    List<ProblemInfo> problems = checker.check(c, fix).problems();
    assertThat(problems).hasSize(1);
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo(
        "Expected merged commit " + other.name()
        + " is not merged into destination ref refs/heads/master"
        + " (" + commit.name() + ")");
  }

  @Test
  public void createNewPatchSetForExpectedMergeCommitWithNoChangeId()
      throws Exception {
    Change c = insertChange();
    c.setStatus(Change.Status.MERGED);
    RevCommit parent =
        testRepo.branch(c.getDest().get()).commit().message("parent").create();
    PatchSet ps = insertPatchSet(c);
    RevCommit commit = parseCommit(ps);

    RevCommit mergedAs = testRepo.commit().parent(parent)
        .message(commit.getShortMessage()).create();
    testRepo.getRevWalk().parseBody(mergedAs);
    assertThat(mergedAs.getFooterLines(FooterConstants.CHANGE_ID)).isEmpty();
    testRepo.update(c.getDest().get(), mergedAs);

    assertProblems(c, "Patch set 1 (" + commit.name() + ") is not merged into"
        + " destination ref refs/heads/master (" + mergedAs.name()
        + "), but change status is MERGED");

    FixInput fix = new FixInput();
    fix.expectMergedAs = mergedAs.name();
    List<ProblemInfo> problems = checker.check(c, fix).problems();
    assertThat(problems).hasSize(1);
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo(
        "No patch set found for merged commit " + mergedAs.name());
    assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
    assertThat(p.outcome).isEqualTo("Inserted as patch set 2");

    c = db.changes().get(c.getId());
    PatchSet.Id psId2 = new PatchSet.Id(c.getId(), 2);
    assertThat(c.currentPatchSetId()).isEqualTo(psId2);
    assertThat(db.patchSets().get(psId2).getRevision().get())
        .isEqualTo(mergedAs.name());

    assertProblems(c);
  }

  @Test
  public void createNewPatchSetForExpectedMergeCommitWithChangeId()
      throws Exception {
    Change c = insertChange();
    c.setStatus(Change.Status.MERGED);
    RevCommit parent =
        testRepo.branch(c.getDest().get()).commit().message("parent").create();
    PatchSet ps = insertPatchSet(c);
    RevCommit commit = parseCommit(ps);

    RevCommit mergedAs = testRepo.commit().parent(parent)
        .message(commit.getShortMessage() + "\n"
            + "\n"
            + "Change-Id: " + c.getKey().get() + "\n").create();
    testRepo.getRevWalk().parseBody(mergedAs);
    assertThat(mergedAs.getFooterLines(FooterConstants.CHANGE_ID))
        .containsExactly(c.getKey().get());
    testRepo.update(c.getDest().get(), mergedAs);

    assertProblems(c, "Patch set 1 (" + commit.name() + ") is not merged into"
        + " destination ref refs/heads/master (" + mergedAs.name()
        + "), but change status is MERGED");

    FixInput fix = new FixInput();
    fix.expectMergedAs = mergedAs.name();
    List<ProblemInfo> problems = checker.check(c, fix).problems();
    assertThat(problems).hasSize(1);
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo(
        "No patch set found for merged commit " + mergedAs.name());
    assertThat(p.status).isEqualTo(ProblemInfo.Status.FIXED);
    assertThat(p.outcome).isEqualTo("Inserted as patch set 2");

    c = db.changes().get(c.getId());
    PatchSet.Id psId2 = new PatchSet.Id(c.getId(), 2);
    assertThat(c.currentPatchSetId()).isEqualTo(psId2);
    assertThat(db.patchSets().get(psId2).getRevision().get())
        .isEqualTo(mergedAs.name());

    assertProblems(c);
  }

  @Test
  public void expectedMergedCommitIsOldPatchSetOfSameChange()
      throws Exception {
    Change c = insertChange();
    c.setStatus(Change.Status.MERGED);
    PatchSet ps1 = insertPatchSet(c);
    String rev1 = ps1.getRevision().get();
    incrementPatchSet(c);
    PatchSet ps2 = insertPatchSet(c);
    testRepo.branch(c.getDest().get()).update(parseCommit(ps1));

    FixInput fix = new FixInput();
    fix.expectMergedAs = rev1;
    List<ProblemInfo> problems = checker.check(c, fix).problems();
    assertThat(problems).hasSize(1);
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo(
        "Expected merged commit " + rev1 + " corresponds to patch set "
        + ps1.getId() + ", which is not the current patch set " + ps2.getId());
  }

  @Test
  public void expectedMergedCommitWithMismatchedChangeId() throws Exception {
    Change c = insertChange();
    c.setStatus(Change.Status.MERGED);
    RevCommit parent =
        testRepo.branch(c.getDest().get()).commit().message("parent").create();
    PatchSet ps = insertPatchSet(c);
    RevCommit commit = parseCommit(ps);

    String badId = "I0000000000000000000000000000000000000000";
    RevCommit mergedAs = testRepo.commit().parent(parent)
        .message(commit.getShortMessage() + "\n"
            + "\n"
            + "Change-Id: " + badId + "\n")
        .create();
    testRepo.getRevWalk().parseBody(mergedAs);
    testRepo.update(c.getDest().get(), mergedAs);

    FixInput fix = new FixInput();
    fix.expectMergedAs = mergedAs.name();
    List<ProblemInfo> problems = checker.check(c, fix).problems();
    assertThat(problems).hasSize(1);
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo(
        "Expected merged commit " + mergedAs.name() + " has Change-Id: "
        + badId + ", but expected " + c.getKey().get());
  }

  @Test
  public void expectedMergedCommitMatchesMultiplePatchSets()
      throws Exception {
    Change c1 = insertChange();
    c1.setStatus(Change.Status.MERGED);
    insertPatchSet(c1);

    RevCommit commit = testRepo.branch(c1.getDest().get()).commit().create();
    Change c2 = insertChange();
    PatchSet ps2 = newPatchSet(c2.currentPatchSetId(), commit, adminId);
    updatePatchSetRef(ps2);
    db.patchSets().insert(singleton(ps2));

    Change c3 = insertChange();
    PatchSet ps3 = newPatchSet(c3.currentPatchSetId(), commit, adminId);
    updatePatchSetRef(ps3);
    db.patchSets().insert(singleton(ps3));

    FixInput fix = new FixInput();
    fix.expectMergedAs = commit.name();
    List<ProblemInfo> problems = checker.check(c1, fix).problems();
    assertThat(problems).hasSize(1);
    ProblemInfo p = problems.get(0);
    assertThat(p.message).isEqualTo(
        "Multiple patch sets for expected merged commit " + commit.name()
        + ": [" + ps2 + ", " + ps3 + "]");
  }

  private Change insertChange() throws Exception {
    Change c = newChange(project, adminId);
    db.changes().insert(singleton(c));
    return c;
  }

  private void incrementPatchSet(Change c) throws Exception {
    TestChanges.incrementPatchSet(c);
    db.changes().upsert(singleton(c));
  }

  private PatchSet insertPatchSet(Change c) throws Exception {
    db.changes().upsert(singleton(c));
    RevCommit commit = testRepo.branch(c.currentPatchSetId().toRefName()).commit()
        .parent(tip).message("Change " + c.getId().get()).create();
    PatchSet ps = newPatchSet(c.currentPatchSetId(), commit, adminId);
    updatePatchSetRef(ps);
    db.patchSets().insert(singleton(ps));
    return ps;
  }

  private PatchSet insertMissingPatchSet(Change c, String id) throws Exception {
    PatchSet ps = newPatchSet(c.currentPatchSetId(),
        ObjectId.fromString(id), adminId);
    db.patchSets().insert(singleton(ps));
    return ps;
  }

  private void updatePatchSetRef(PatchSet ps) throws Exception {
    testRepo.update(ps.getId().toRefName(),
        ObjectId.fromString(ps.getRevision().get()));
  }

  private void deleteRef(String refName) throws Exception {
    RefUpdate ru = testRepo.getRepository().updateRef(refName, true);
    ru.setForceUpdate(true);
    assertThat(ru.delete()).isEqualTo(RefUpdate.Result.FORCED);
  }

  private RevCommit parseCommit(PatchSet ps) throws Exception {
    RevCommit commit = testRepo.getRevWalk()
        .parseCommit(ObjectId.fromString(ps.getRevision().get()));
    testRepo.getRevWalk().parseBody(commit);
    return commit;
  }

  private void assertProblems(Change c, String... expected) {
    assertThat(Lists.transform(checker.check(c).problems(),
          new Function<ProblemInfo, String>() {
            @Override
            public String apply(ProblemInfo in) {
              checkArgument(in.status == null,
                  "Status is not null: " + in.message);
              return in.message;
            }
          })).containsExactly((Object[]) expected);
  }
}
