// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.testing;

import static com.google.common.truth.Truth.assertAbout;

import com.google.common.testing.TestLogHandler;
import com.google.common.truth.AbstractVerb.DelegatedVerb;
import com.google.common.truth.FailureStrategy;
import com.google.common.truth.Subject;
import google.registry.testing.TruthChainer.And;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;

/** Utility methods for asserting things about logging {@link Handler} instances. */
public class LogsSubject extends Subject<LogsSubject, TestLogHandler> {

  /** A factory for instances of this subject. */
  private static class SubjectFactory
      extends ReflectiveSubjectFactory<TestLogHandler, LogsSubject> {}

  public LogsSubject(FailureStrategy strategy, TestLogHandler subject) {
    super(strategy, subject);
  }

  public And<LogsSubject> hasNoLogsAtLevel(Level level) {
    for (LogRecord log : actual().getStoredLogRecords()) {
      if (log.getLevel().equals(level)) {
        failWithRawMessage(
            "Not true that there are no logs at level %s. Found <%s>.", level, log.getMessage());
      }
    }
    return new And<>(this);
  }

  public And<LogsSubject> hasLogAtLevelWithMessage(Level level, String message) {
    boolean found = false;
    for (LogRecord log : actual().getStoredLogRecords()) {
      if (log.getLevel().equals(level) && log.getMessage().contains(message)) {
        found = true;
        break;
      }
    }
    if (!found) {
      failWithRawMessage("Found no logs at level %s with message %s.", level, message);
    }
    return new And<>(this);
  }

  public static DelegatedVerb<LogsSubject, TestLogHandler> assertAboutLogs() {
    return assertAbout(new SubjectFactory());
  }
}

@@ -704,16 +704,64 @@
 About;%0A%0A
+import com.google.common.collect.ImmutableList;%0A
 import c
@@ -860,16 +860,63 @@
 edVerb;%0A
+import com.google.common.truth.Correspondence;%0A
 import c
@@ -995,16 +995,17 @@
 ubject;%0A
+%0A
 import g
@@ -1044,16 +1044,40 @@
 ner.And;
+%0A%0Aimport java.util.List;
 %0Aimport 
@@ -1605,62 +1605,503 @@
 %0A  p
-ublic And%3CLogsSubject%3E hasNoLogsAtLevel(Level level) %7B
+rivate static final Correspondence%3CString, String%3E CONTAINS_CORRESPONDENCE =%0A      new Correspondence%3CString, String%3E() %7B%0A        @Override%0A        public boolean compare(String actual, String expected) %7B%0A          return actual.contains(expected);%0A        %7D%0A%0A        @Override%0A        public String toString() %7B%0A          return %22contains%22;%0A        %7D%0A      %7D;%0A%0A  private List%3CString%3E getMessagesAtLevel(Level level) %7B%0A    ImmutableList.Builder%3CString%3E builder = ImmutableList.%3CString%3Ebuilder();
 %0A   
@@ -2206,35 +2206,43 @@
         
-failWithRaw
+builder.add(log.get
 Message(
 %0A       
@@ -2237,120 +2237,244 @@
 age(
+));
 %0A      
+%7D%0A
     
-  %22Not true that there are no logs at level %25s. Found %3C%25s%3E.%22, level, log.getMessage(
+%7D%0A    return builder.build();%0A  %7D%0A%0A  public And%3CLogsSubject%3E hasNoLogsAtLevel(Level level) %7B%0A    check()%0A        .withFailureMessage(%22Logs at level %25s%22, level)%0A        .that(getMessagesAtLevel(level
 ))
-;
 %0A      
-%7D%0A    %7D
+  .isEmpty();
 %0A   
@@ -2593,317 +2593,187 @@
     
-boolean found = false;%0A    for (LogRecord log : actual().getStoredLogRecords()) %7B%0A      if (log.getLevel().equals(level) && log.getMessage().contains(message)) %7B%0A        found = true;%0A        break;%0A      %7D%0A    %7D%0A    if (!found) %7B%0A      failWithRawMessage(%22Found no logs at level %25s with message %25s.%22, level, 
+check()%0A        .withFailureMessage(%22Logs at level %25s%22, level)%0A        .that(getMessagesAtLevel(level))%0A        .comparingElementsUsing(CONTAINS_CORRESPONDENCE)%0A        .contains(
 mess
@@ -2778,22 +2778,16 @@
 ssage);%0A
-    %7D%0A
     retu

Improve error messages for LogsSubject