1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.adservices.shared.testing; 17 18 import com.android.adservices.shared.testing.Logger.LogLevel; 19 20 import com.google.common.truth.FailureMetadata; 21 22 import java.util.Objects; 23 24 /** 25 * Represents a call to a static method in a logging class {like @code android.util.Log or 26 * com.android.tradefed.log.LogUtil.CLog}. 27 */ 28 public final class LogEntry { 29 public final LogLevel level; 30 public final String tag; 31 public final String message; 32 public final @Nullable Throwable throwable; 33 LogEntry(LogLevel level, String tag, String message)34 public LogEntry(LogLevel level, String tag, String message) { 35 this(level, tag, message, /* throwable= */ null); 36 } 37 LogEntry(LogLevel level, String tag, String message, @Nullable Throwable throwable)38 public LogEntry(LogLevel level, String tag, String message, @Nullable Throwable throwable) { 39 this.level = Objects.requireNonNull(level, "level cannot be null"); 40 this.tag = Objects.requireNonNull(tag, "tag cannot be null"); 41 this.message = Objects.requireNonNull(message, "message cannot be null"); 42 this.throwable = throwable; 43 } 44 45 @Override hashCode()46 public int hashCode() { 47 return Objects.hash(level, message, tag, throwable); 48 } 49 50 @Override equals(Object obj)51 public boolean equals(Object obj) { 52 if (this == obj) return true; 53 if (obj == null) return false; 54 if (getClass() != obj.getClass()) return false; 55 LogEntry other = (LogEntry) obj; 56 return level == other.level 57 && Objects.equals(message, other.message) 58 && Objects.equals(tag, other.tag) 59 && Objects.equals(throwable, other.throwable); 60 } 61 62 @Override toString()63 public String toString() { 64 return "LogEntry [level=" 65 + level 66 + ", tag=" 67 + tag 68 + ", throwable=" 69 + throwable 70 + ", message=" 71 + message 72 + "]"; 73 } 74 75 /** 76 * Custom {@code Truth} subject for a {@link LogEntry}. 77 * 78 * <p>Typical usage: <code> 79 * import static com.android.adservices.shared.meta_testing.LogEntry.Subject.logEntry; 80 * 81 * LogEntry entry = ... 82 * expect.withMessage("logged message") 83 * .about(logEntry()) 84 * .that(entry)) 85 * .hasLevel(..) 86 * .hasTag(...) 87 * .hasXyz(...); 88 * </code> 89 */ 90 public static final class Subject extends com.google.common.truth.Subject { 91 92 /** Factory method. */ logEntry()93 public static Factory<Subject, LogEntry> logEntry() { 94 return Subject::new; 95 } 96 97 @Nullable private final LogEntry mActual; 98 Subject(FailureMetadata metadata, @Nullable Object actual)99 private Subject(FailureMetadata metadata, @Nullable Object actual) { 100 super(metadata, actual); 101 mActual = (LogEntry) actual; 102 } 103 104 /** Checks it has the expected level. */ hasLevel(LogLevel expected)105 public Subject hasLevel(LogLevel expected) { 106 check("level").that(mActual.level).isEqualTo(expected); 107 return this; 108 } 109 110 /** Checks it has the expected tag. */ hasTag(String expected)111 public Subject hasTag(String expected) { 112 check("tag").that(mActual.tag).isEqualTo(expected); 113 return this; 114 } 115 116 /** Checks it has the expected throwable. */ hasThrowable(Throwable expected)117 public Subject hasThrowable(Throwable expected) { 118 check("throwable").that(mActual.throwable).isSameInstanceAs(expected); 119 return this; 120 } 121 122 /** Checks it has the expected message. */ hasMessage(String expected)123 public Subject hasMessage(String expected) { 124 check("message").that(mActual.message).isEqualTo(expected); 125 return this; 126 } 127 } 128 } 129