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 com.google.common.annotations.GwtCompatible; 020import com.google.errorprone.annotations.concurrent.GuardedBy; 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.List; 024import java.util.logging.Handler; 025import java.util.logging.LogRecord; 026import org.jspecify.annotations.NullMarked; 027import org.checkerframework.checker.nullness.qual.Nullable; 028 029/** 030 * Tests may use this to intercept messages that are logged by the code under test. Example: 031 * 032 * <pre> 033 * TestLogHandler handler; 034 * 035 * protected void setUp() throws Exception { 036 * super.setUp(); 037 * handler = new TestLogHandler(); 038 * SomeClass.logger.addHandler(handler); 039 * addTearDown(new TearDown() { 040 * public void tearDown() throws Exception { 041 * SomeClass.logger.removeHandler(handler); 042 * } 043 * }); 044 * } 045 * 046 * public void test() { 047 * SomeClass.foo(); 048 * LogRecord firstRecord = handler.getStoredLogRecords().get(0); 049 * assertEquals("some message", firstRecord.getMessage()); 050 * } 051 * </pre> 052 * 053 * @author Kevin Bourrillion 054 * @since 10.0 055 */ 056@GwtCompatible 057@NullMarked 058public class TestLogHandler extends Handler { 059 private final Object lock = new Object(); 060 061 /** We will keep a private list of all logged records */ 062 @GuardedBy("lock") 063 private final List<LogRecord> list = new ArrayList<>(); 064 065 /** Adds the most recently logged record to our list. */ 066 @Override 067 public void publish(@Nullable LogRecord record) { 068 synchronized (lock) { 069 if (record != null) { 070 list.add(record); 071 } 072 } 073 } 074 075 @Override 076 public void flush() {} 077 078 @Override 079 public void close() {} 080 081 public void clear() { 082 synchronized (lock) { 083 list.clear(); 084 } 085 } 086 087 /** Returns a snapshot of the logged records. */ 088 /* 089 * TODO(cpovirk): consider higher-level APIs here (say, assertNoRecordsLogged(), 090 * getOnlyRecordLogged(), getAndClearLogRecords()...) 091 * 092 * TODO(cpovirk): consider renaming this method to reflect that it takes a snapshot (and/or return 093 * an ImmutableList) 094 */ 095 public List<LogRecord> getStoredLogRecords() { 096 synchronized (lock) { 097 List<LogRecord> result = new ArrayList<>(list); 098 return Collections.unmodifiableList(result); 099 } 100 } 101}