/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2013, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ package ch.qos.logback.classic.android; import android.util.Log; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowLog; import java.util.List; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.classic.spi.ThrowableProxy; /** * Tests the {@link LogcatAppender} class * * @author Anthony Trinh */ @RunWith(RobolectricTestRunner.class) public class LogcatAppenderTest { static private final String LOGGER_NAME = "LOGCAT"; static private final int MAX_TAG_LENGTH = 23; // for android.util.Log.isLoggable() static private final String TAG = "123456789012345678901234567890"; static private final String TRUNCATED_TAG = TAG.substring(0, MAX_TAG_LENGTH - 1) + "*"; private LogcatAppender logcatAppender; private LoggerContext context = new LoggerContext(); private Logger root = context.getLogger(Logger.ROOT_LOGGER_NAME); @Before public void before() { context.reset(); root.detachAndStopAllAppenders(); configureLogcatAppender(); } @Test public void longTagAllowedIfNotCheckLoggable() { LoggingEvent event = new LoggingEvent(); event.setMessage(TAG); boolean checkLoggable = false; setTagPattern(TAG, checkLoggable); String actualTag = logcatAppender.getTag(event); assertThat(TRUNCATED_TAG, is(not(actualTag))); assertThat(TAG, is(actualTag)); } @Test public void longTagTruncatedIfCheckLoggable() { LoggingEvent event = new LoggingEvent(); event.setMessage(TAG); boolean checkLoggable = true; setTagPattern(TAG, checkLoggable); String actualTag = logcatAppender.getTag(event); assertThat(TRUNCATED_TAG, is(actualTag)); assertThat(TAG, is(not(actualTag))); } // Issue #34 @Test public void tagExcludesStackTraces() { // create logging event with throwable LoggingEvent event = new LoggingEvent(); Throwable throwable = new Throwable("throwable"); ThrowableProxy tp = new ThrowableProxy(throwable); event.setThrowableProxy(tp); event.setMessage(TAG); setTagPattern(TAG, true); // if the tags match, it does not include the stack trace String actualTag = logcatAppender.getTagEncoder().getLayout().doLayout(event); assertThat(TAG, is(actualTag)); } private void setTagPattern(String tag, boolean checkLoggable) { logcatAppender.stop(); logcatAppender.setCheckLoggable(checkLoggable); logcatAppender.getTagEncoder().setPattern(tag); logcatAppender.start(); } private void configureLogcatAppender() { logcatAppender = new LogcatAppender(); logcatAppender.setContext(context); logcatAppender.setName(LOGGER_NAME); PatternLayoutEncoder encoder = new PatternLayoutEncoder(); encoder.setContext(context); encoder.setPattern("%msg"); encoder.start(); PatternLayoutEncoder tagEncoder = new PatternLayoutEncoder(); tagEncoder.setContext(context); tagEncoder.setPattern(TAG); tagEncoder.start(); logcatAppender.setTagEncoder(tagEncoder); logcatAppender.setEncoder(encoder); logcatAppender.start(); } private boolean logcatContains(List<ShadowLog.LogItem> logs, int level, String errorMessage) { boolean found = false; for (ShadowLog.LogItem s : logs) { if (level == s.type) { if (s.msg.contains(errorMessage)) { found = true; break; } } } return found; } private void assertLogcatContains(int level, String errorMessage) { List<ShadowLog.LogItem> logs = ShadowLog.getLogsForTag(LOGGER_NAME); assertThat(logs, is(notNullValue())); assertThat(logcatContains(logs, level, errorMessage), is(true)); } private void addLogcatAppenderToRoot() { PatternLayoutEncoder encoder2 = new PatternLayoutEncoder(); encoder2.setContext(context); encoder2.setPattern("[%thread] %method\\(\\): %msg%n"); encoder2.start(); LogcatAppender logcatAppender = new LogcatAppender(); logcatAppender.setContext(context); logcatAppender.setName(LOGGER_NAME); logcatAppender.setEncoder(encoder2); logcatAppender.start(); root.addAppender(logcatAppender); } /** * Issue #102 */ @Test public void logsExceptionWhenMessageTrailsWithNewline() { addLogcatAppenderToRoot(); ShadowLog.reset(); context.getLogger(LOGGER_NAME).debug("msg\n", new NullPointerException()); assertLogcatContains(Log.DEBUG, NullPointerException.class.getName()); } /** * Issue #102 */ @Test public void logsExceptionWhenMessageHasNoTrailingNewline() { addLogcatAppenderToRoot(); ShadowLog.reset(); context.getLogger(LOGGER_NAME).debug("msg", new NullPointerException()); assertLogcatContains(Log.DEBUG, NullPointerException.class.getName()); } }