// Copyright (C) 2016 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.testutil;

import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.reviewdb.server.ReviewDbUtil;
import com.google.gerrit.server.PatchLineCommentsUtil;
import com.google.gerrit.server.notedb.ChangeBundle;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeRebuilder;
import com.google.gerrit.server.schema.DisabledChangesReviewDbWrapper;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Singleton
public class NoteDbChecker {
  private final Provider<ReviewDb> dbProvider;
  private final TestNotesMigration notesMigration;
  private final ChangeNotes.Factory notesFactory;
  private final ChangeRebuilder changeRebuilder;
  private final PatchLineCommentsUtil plcUtil;

  @Inject
  NoteDbChecker(Provider<ReviewDb> dbProvider,
      TestNotesMigration notesMigration,
      ChangeNotes.Factory notesFactory,
      ChangeRebuilder changeRebuilder,
      PatchLineCommentsUtil plcUtil) {
    this.dbProvider = dbProvider;
    this.notesMigration = notesMigration;
    this.notesFactory = notesFactory;
    this.changeRebuilder = changeRebuilder;
    this.plcUtil = plcUtil;
  }

  public void checkAllChanges() throws Exception {
    checkChanges(
        Iterables.transform(
            unwrapDb().changes().all(),
            ReviewDbUtil.changeIdFunction()));
  }

  public void checkChanges(Change.Id... changeIds) throws Exception {
    checkChanges(Arrays.asList(changeIds));
  }

  public void checkChanges(Iterable<Change.Id> changeIds) throws Exception {
    ReviewDb db = unwrapDb();

    notesMigration.setReadChanges(false);
    List<Change.Id> sortedIds =
        ReviewDbUtil.intKeyOrdering().sortedCopy(changeIds);
    List<ChangeBundle> allExpected = new ArrayList<>(sortedIds.size());
    for (Change.Id id : sortedIds) {
      allExpected.add(ChangeBundle.fromReviewDb(db, id));
    }

    notesMigration.setWriteChanges(true);
    notesMigration.setReadChanges(true);
    for (ChangeBundle expected : allExpected) {
      Change c = expected.getChange();
      changeRebuilder.rebuild(db, c.getId());
      ChangeBundle actual = ChangeBundle.fromNotes(
          plcUtil, notesFactory.create(db, c.getProject(), c.getId()));
      List<String> diff = expected.differencesFrom(actual);
      if (!diff.isEmpty()) {
        throw new AssertionError(
            "Differences between ReviewDb and NoteDb for " + c + ":\n"
            + Joiner.on('\n').join(diff));
      } else {
        System.err.println(
            "NoteDb conversion of change " + c.getId() + " successful");
      }
    }
  }

  private ReviewDb unwrapDb() {
    ReviewDb db = dbProvider.get();
    if (db instanceof DisabledChangesReviewDbWrapper) {
      db = ((DisabledChangesReviewDbWrapper) db).unsafeGetDelegate();
    }
    return db;
  }
}

@@ -2842,24 +2842,66 @@
 nges(true);%0A
+    List%3CString%3E all = new ArrayList%3C%3E();%0A
     for (Cha
@@ -2932,24 +2932,24 @@
 Expected) %7B%0A
-
       Change
@@ -3246,46 +3246,16 @@
     
-throw new AssertionError(%0A            
+all.add(
 %22Dif
@@ -3309,23 +3309,20 @@
 + %22:
-%5Cn%22%0A   
+%22);%0A
         
  + J
@@ -3321,37 +3321,44 @@
     
- + Joiner.on('%5Cn').join(diff)
+all.addAll(diff);%0A        all.add(%22%22
 );%0A 
@@ -3468,24 +3468,24 @@
 ccessful%22);%0A
-
       %7D%0A    
@@ -3486,16 +3486,107 @@
 %7D%0A    %7D%0A
+    if (!all.isEmpty()) %7B%0A      throw new AssertionError(Joiner.on('%5Cn').join(all));%0A    %7D%0A
   %7D%0A%0A  p

Throw an error with diffs for all changes