001/* 002 * Copyright (C) 2008 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.testing; 018 019import static java.util.Collections.unmodifiableList; 020 021import com.google.common.annotations.GwtCompatible; 022import com.google.errorprone.annotations.concurrent.GuardedBy; 023import java.util.ArrayList; 024import java.util.List; 025import java.util.logging.Handler; 026import java.util.logging.LogRecord; 027import org.jspecify.annotations.NullMarked; 028import org.jspecify.annotations.Nullable; 029 030/** 031 * Tests may use this to intercept messages that are logged by the code under test. Example: 032 * 033 * <pre> 034 * TestLogHandler handler; 035 * 036 * protected void setUp() throws Exception { 037 * super.setUp(); 038 * handler = new TestLogHandler(); 039 * SomeClass.logger.addHandler(handler); 040 * addTearDown(new TearDown() { 041 * public void tearDown() throws Exception { 042 * SomeClass.logger.removeHandler(handler); 043 * } 044 * }); 045 * } 046 * 047 * public void test() { 048 * SomeClass.foo(); 049 * LogRecord firstRecord = handler.getStoredLogRecords().get(0); 050 * assertEquals("some message", firstRecord.getMessage()); 051 * } 052 * </pre> 053 * 054 * @author Kevin Bourrillion 055 * @since 10.0 056 */ 057@GwtCompatible 058@NullMarked 059public class TestLogHandler extends Handler { 060 private final Object lock = new Object(); 061 062 /** We will keep a private list of all logged records */ 063 @GuardedBy("lock") 064 private final List<LogRecord> list = new ArrayList<>(); 065 066 /** Adds the most recently logged record to our list. */ 067 @Override 068 public void publish(@Nullable LogRecord record) { 069 synchronized (lock) { 070 if (record != null) { 071 list.add(record); 072 } 073 } 074 } 075 076 @Override 077 public void flush() {} 078 079 @Override 080 public void close() {} 081 082 /** Clears all stored log records. */ 083 public void clear() { 084 synchronized (lock) { 085 list.clear(); 086 } 087 } 088 089 /** Returns a snapshot of the logged records. */ 090 /* 091 * TODO(cpovirk): consider higher-level APIs here (say, assertNoRecordsLogged(), 092 * getOnlyRecordLogged(), getAndClearLogRecords()...) 093 * 094 * TODO(cpovirk): consider renaming this method to reflect that it takes a snapshot (and/or return 095 * an ImmutableList) 096 */ 097 public List<LogRecord> getStoredLogRecords() { 098 synchronized (lock) { 099 List<LogRecord> result = new ArrayList<>(list); 100 return unmodifiableList(result); 101 } 102 } 103}