/AddParameterLogger.java Secret
Last active
January 19, 2017 01:07
Star
You must be signed in to star a gist
Refactoring the FyzLog for https://blog.quantityandconversion.com
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private static void println(final int level, final int logLevel, final String msgFormat, final Object... args) { | |
... | |
} | |
private static void log(final int level, final int logLevel, final String msgFormat, final Object... args) { | |
... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private String configureSystemTest(final String prefix, final int level) { | |
systemOutRule.clearLog(); | |
FyzLog.doPrint = true; | |
final String logLevel = prefix + "@" + getLevelTag(level) + "/ "; | |
final String tag = "FYZ:TheFyzLogTests "; | |
final String thread = "[main] "; | |
return logLevel + tag + thread; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.quantityandconversion.log; | |
import android.util.Log; | |
import java.util.Locale; | |
public class Logger { | |
private static final String TAG_PREFIX = "FYZ:"; | |
private static void println(final int level, final String msgFormat, final Object... args) { | |
if(msgFormat == null) throw new IllegalArgumentException("FyzLog message can not be null"); | |
final StackTraceElement frame = getCallingStackTraceElement(); | |
final String output = | |
getLevelTag(level) + "@" + getLevelTag(logLevel) + "/ " + | |
createTag(frame) + " " + | |
createMessage(frame, String.format(Locale.US, msgFormat, args)); | |
System.out.println(output); | |
} | |
private static String getLevelTag(final int level) { | |
switch (level) { | |
case Log.VERBOSE: | |
return "V"; | |
case Log.DEBUG: | |
return "D"; | |
case Log.INFO: | |
return "I"; | |
case Log.WARN: | |
return "W"; | |
case Log.ERROR: | |
return "E"; | |
case Log.ASSERT: | |
return "WTF"; | |
default: | |
return "?"; | |
} | |
} | |
private static String createTag(final StackTraceElement frame) { | |
final String fullClassName = frame.getClassName(); | |
final String className = fullClassName.substring(fullClassName.lastIndexOf('.') + 1); | |
return TAG_PREFIX + className; | |
} | |
private static String createMessage(final StackTraceElement frame, final String msg) { | |
return String.format(Locale.US, | |
"[%s] %s : %s", | |
Thread.currentThread().getName(), | |
frame.getMethodName(), | |
msg); | |
} | |
private static StackTraceElement getCallingStackTraceElement() { | |
boolean hitLogger = false; | |
for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) { | |
final boolean isLogger = ste.getClassName().startsWith(FyzLog.class.getName()); | |
hitLogger = hitLogger || isLogger; | |
if (hitLogger && !isLogger) { | |
return ste; | |
} | |
} | |
return new StackTraceElement(FyzLog.class.getName(), | |
"getCallingStackTraceElement", | |
null, | |
-1); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void wtf(final String msgFormat, final Object... args) { | |
if (doPrint) { | |
println(Log.ASSERT, msgFormat, args); | |
} else { | |
log(Log.ASSERT, msgFormat, args); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void wtf(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
new Logger().println(Log.ASSERT, logLevel, msgFormat, args); | |
} else { | |
log(Log.ASSERT, msgFormat, args); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Test | |
public void massiveTestOfAllPrintMessageCombinations() { | |
//Tracks how many tests we performed | |
int ctr = 0;//Looping over the available Log calls | |
for (final String s : new String[]{"V", "D", "I", "W", "E", "WTF"}) { | |
//Looping over each logLevel, with an extra setting on each side | |
for (int i = Log.VERBOSE - 1; i <= Log.ASSERT + 1; i++) { | |
//Arrange | |
final String prefix = configureSystemTest(s, i); | |
final String msg = message(); | |
final String method = Thread.currentThread().getStackTrace()[1].getMethodName() + " : "; | |
//Set the Log Level | |
FyzLog.logLevel = i; | |
//Prep the expected value | |
final String expected = prefix + method + msg; | |
//Act | |
switch (s) { | |
case "V": | |
FyzLog.v(msg); | |
break; | |
case "D": | |
FyzLog.d(msg); | |
break; | |
case "I": | |
FyzLog.i(msg); | |
break; | |
case "W": | |
FyzLog.w(msg); | |
break; | |
case "E": | |
FyzLog.e(msg); | |
break; | |
case "WTF": | |
FyzLog.wtf(msg); | |
break; | |
} | |
//Assert | |
final String target = systemOutRule.getLog(); | |
assertEquals("Failed at [s=" + s + "][i=" + i + "]", expected + "\n", target); | |
//A test ran, inc | |
ctr++; | |
} | |
} | |
//Confirm we ran the expected number of tests | |
assertThat(ctr).isEqualTo(6 * (6 + 2)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class LogLevel { | |
public final static LogLevel VERBOSE = new LogLevel(Log.VERBOSE, "V"); | |
public final static LogLevel DEBUG = new LogLevel(Log.DEBUG, "D"); | |
public final static LogLevel INFO = new LogLevel(Log.INFO, "I"); | |
public final static LogLevel WARN = new LogLevel(Log.WARN, "W"); | |
public final static LogLevel ERROR = new LogLevel(Log.ERROR, "E"); | |
public final static LogLevel ASSERT = new LogLevel(Log.ASSERT, "WTF"); | |
private final int level; | |
private final String tag; | |
public LogLevel(final int level, final String tag) { | |
this.level = level; | |
this.tag = tag; | |
} | |
public String tag() { | |
return tag; | |
} | |
public boolean logAt(final LogLevel other) { | |
return this.level >= other.level; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* package */ void println(final int level, final int logLevel, final String msgFormat, final Object... args) { | |
... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Test | |
public void massiveAndroidLogging() { | |
//Tracks how many tests we performed | |
int ctr = 0; | |
final LogLevel[] logLevels = new LogLevel[]{LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.ASSERT}; | |
//Looping over the available Log calls | |
for (final LogLevel currentLogLevel : logLevels) { | |
//Set the Log Level | |
FyzLog.logLevel = currentLogLevel; | |
//Looping over each logLevel | |
for (final LogLevel attemptingLogLevel : logLevels) { | |
//Get the tag | |
//Determine if logging will be attempted, which will result in an exception | |
final boolean shouldTryToLog = attemptingLogLevel.logAt(currentLogLevel); | |
//Show what's about to be performed. If this breaks, it's HUGELY useful. | |
System.out.println("[currentLogLevel=" + currentLogLevel.tag() + "][attemptingLogLevel=" + attemptingLogLevel.tag() + "][shouldTryToLog=" + shouldTryToLog + "]"); | |
//INVOKE | |
try { | |
if (attemptingLogLevel == LogLevel.VERBOSE) | |
FyzLog.v(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.DEBUG) | |
FyzLog.d(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.INFO) | |
FyzLog.i(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.WARN) | |
FyzLog.w(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.ERROR) | |
FyzLog.e(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.ASSERT) | |
FyzLog.wtf(messageFormat(), messageArgs()); | |
//If we got here, we did not expect an exception, prove it | |
assertFalse("[currentLogLevel=" + currentLogLevel.tag() + "][attemptingLogLevel=" + attemptingLogLevel.tag() + "]", shouldTryToLog); | |
} catch (final RuntimeException e) { | |
//If we got here, we expected to, prove it | |
assertThat(shouldTryToLog).isTrue(); | |
//Since this is kinda a catch all exception, make sure it's what we wanted | |
assertThat(e.getMessage()).isEqualTo("Method " + attemptingLogLevel.tag().toLowerCase() + " in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details."); | |
} | |
//A test ran, inc | |
ctr++; | |
} | |
} | |
//Confirm we ran the expected number of tests | |
assertThat(ctr).isEqualTo(6 * 6); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Test | |
public void massiveAndroidLogging() { | |
//Tracks how many tests we performed | |
int ctr = 0; | |
//Used to check if an exception should be thrown. | |
final int offset = Log.VERBOSE; | |
//The variation in the exception message | |
final String[] tags = new String[]{"v", "d", "i", "w", "e", "wtf"}; | |
//Looping over the available Log calls | |
for (int idx = 0; idx < tags.length; idx++) { | |
//Looping over each logLevel, with an extra setting on each side | |
for (int i = Log.VERBOSE - 1; i <= Log.ASSERT + 1; i++) { | |
//Set the Log Level | |
FyzLog.logLevel = i; | |
//Get the tag | |
final String tag = tags[idx]; | |
//Determine if logging will be attempted, which will result in an exception | |
final boolean shouldTryToLog = i <= idx + offset; | |
//Show what's about to be performed. If this breaks, it's HUGELY useful. | |
System.out.println("[idx=" + idx + ";" + tag + "][i=" + i + "][shouldTryToLog=" + shouldTryToLog + "]"); | |
//INVOKE | |
try { | |
switch (tag) { | |
case "v": | |
FyzLog.v(messageFormat(), messageArgs()); | |
break; | |
case "d": | |
FyzLog.d(messageFormat(), messageArgs()); | |
break; | |
case "i": | |
FyzLog.i(messageFormat(), messageArgs()); | |
break; | |
case "w": | |
FyzLog.w(messageFormat(), messageArgs()); | |
break; | |
case "e": | |
FyzLog.e(messageFormat(), messageArgs()); | |
break; | |
case "wtf": | |
FyzLog.wtf(messageFormat(), messageArgs()); | |
break; | |
} | |
//If we got here, we did not expect an exception, prove it | |
assertFalse("[idx=" + idx + ";" + tag + "][i=" + i + "]", shouldTryToLog); | |
} catch (final RuntimeException e) { | |
//If we got here, we expected to, prove it | |
assertThat(shouldTryToLog).isTrue(); | |
//Since this is kinda a catch all exception, make sure it's what we wanted | |
assertThat(e.getMessage()).isEqualTo("Method " + tag + " in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details."); | |
} | |
//A test ran, inc | |
ctr++; | |
} | |
} | |
//Confirm we ran the expected number of tests | |
assertThat(ctr).isEqualTo(6 * (6 + 2)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016 Fyzxs | |
* | |
* Licensed under The MIT License (MIT) | |
*/ | |
package com.quantityandconversion.log; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.VisibleForTesting; | |
import android.util.Log; | |
import java.util.Locale; | |
/** | |
* Fyzxs Log(ger) | |
* <p> | |
* This lightweight static class wraps the Android logger. | |
* It allows customization of the logging process. | |
* <p> | |
* Most importantly, it allows control of the logging for | |
* unit testing purposes. | |
*/ | |
public final class FyzLog { | |
//Understands handling a user request to log | |
/** | |
* This is the tag prefix that will be displayed in the tag component of the {@link Log#v(String, String) Android Log} methods | |
*/ | |
private static final String TAG_PREFIX = "FYZ:"; | |
/** | |
* Write Log Message to {@link System#out#println} | |
*/ | |
@VisibleForTesting | |
public static boolean doPrint = false; | |
/** | |
* Controls the level of logging. | |
* This can be configured during build to limit logging messages to {@link Log#ERROR} or other levels. | |
* Default value is {@link Log#VERBOSE the lowest setting} | |
*/ | |
@VisibleForTesting | |
public static int logLevel = Log.VERBOSE; | |
/** | |
* The {@link Log#VERBOSE} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void v(@NonNull final String msg) { | |
v(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#VERBOSE} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void v(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
println(Log.VERBOSE, msgFormat, args); | |
} else { | |
log(Log.VERBOSE, msgFormat, args); | |
} | |
} | |
/** | |
* The {@link Log#DEBUG} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void d(@NonNull final String msg) { | |
d(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#DEBUG} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void d(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
println(Log.DEBUG, msgFormat, args); | |
} else { | |
log(Log.DEBUG, msgFormat, args); | |
} | |
} | |
/** | |
* The {@link Log#INFO} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void i(@NonNull final String msg) { | |
i(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#INFO} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void i(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
println(Log.INFO, msgFormat, args); | |
} else { | |
log(Log.INFO, msgFormat, args); | |
} | |
} | |
/** | |
* The {@link Log#WARN} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void w(@NonNull final String msg) { | |
w(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#WARN} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void w(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
println(Log.WARN, msgFormat, args); | |
} else { | |
log(Log.WARN, msgFormat, args); | |
} | |
} | |
//endregion | |
//region error | |
/** | |
* The {@link Log#ERROR} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void e(@NonNull final String msg) { | |
e(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#ERROR} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void e(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
println(Log.ERROR, msgFormat, args); | |
} else { | |
log(Log.ERROR, msgFormat, args); | |
} | |
} | |
/** | |
* The {@link Log#ASSERT} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void wtf(@NonNull final String msg) { | |
wtf(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#ASSERT} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void wtf(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
println(Log.ASSERT, msgFormat, args); | |
} else { | |
log(Log.ASSERT, msgFormat, args); | |
} | |
} | |
/** | |
* Always writes the message to {@link System#out} if invoked | |
* | |
* @param level The Invoking Log Level | |
* @param msgFormat the message format string | |
* @param args the args to format in | |
*/ | |
private static void println(final int level, final String msgFormat, final Object... args) { | |
if(msgFormat == null) throw new IllegalArgumentException("FyzLog message can not be null"); | |
final StackTraceElement frame = getCallingStackTraceElement(); | |
final String output = | |
getLevelTag(level) + "@" + getLevelTag(logLevel) + "/ " + | |
createTag(frame) + " " + | |
createMessage(frame, String.format(Locale.US, msgFormat, args)); | |
System.out.println(output); | |
} | |
/** | |
* Helper method for the println | |
* | |
* @param level the invoking level of logging | |
* @return Letter Identifier | |
*/ | |
private static String getLevelTag(final int level) { | |
switch (level) { | |
case Log.VERBOSE: | |
return "V"; | |
case Log.DEBUG: | |
return "D"; | |
case Log.INFO: | |
return "I"; | |
case Log.WARN: | |
return "W"; | |
case Log.ERROR: | |
return "E"; | |
case Log.ASSERT: | |
return "WTF"; | |
default: | |
return "?"; | |
} | |
} | |
/** | |
* IFF the logLevel is high enough, logs to Android. | |
* <p> | |
* This will drop a null msg. | |
* | |
* @param level The invoking level of logging | |
* @param msgFormat the message format string | |
* @param args the args to format in | |
*/ | |
private static void log(final int level, final String msgFormat, final Object... args) { | |
if (level >= logLevel && msgFormat != null) { | |
final StackTraceElement frame = getCallingStackTraceElement(); | |
final String tag = createTag(frame); | |
final String msg = String.format(Locale.US, msgFormat, args); | |
final String message = createMessage(frame, msg); | |
switch (level) { | |
case Log.VERBOSE: | |
Log.v(tag, message); | |
break; | |
case Log.DEBUG: | |
Log.d(tag, message); | |
break; | |
case Log.INFO: | |
Log.i(tag, message); | |
break; | |
case Log.WARN: | |
Log.w(tag, message); | |
break; | |
case Log.ERROR: | |
Log.e(tag, message); | |
break; | |
case Log.ASSERT: | |
Log.wtf(tag, message); | |
break; | |
} | |
} | |
} | |
/** | |
* Creates the tag to be used | |
* | |
* @param frame {@link StackTraceElement} to build the tag from | |
* @return Tag to use for the logged message | |
*/ | |
private static String createTag(final StackTraceElement frame) { | |
final String fullClassName = frame.getClassName(); | |
final String className = fullClassName.substring(fullClassName.lastIndexOf('.') + 1); | |
return TAG_PREFIX + className; | |
} | |
/** | |
* Builds the final message to be logged. | |
* The format will be | |
* InvokingMethodName [currentThreadName] providedMessage | |
* | |
* @param frame The {@link StackTraceElement} to pull the method name from | |
* @param msg the message to prefix the method name to | |
* @return The final message string | |
*/ | |
private static String createMessage(final StackTraceElement frame, final String msg) { | |
return String.format(Locale.US, | |
"[%s] %s : %s", | |
Thread.currentThread().getName(), | |
frame.getMethodName(), | |
msg); | |
} | |
/** | |
* Gets the {@link StackTraceElement} for the method that invoked logging | |
* | |
* @return {@link StackTraceElement} for the caller into {@link FyzLog} | |
*/ | |
private static StackTraceElement getCallingStackTraceElement() { | |
boolean hitLogger = false; | |
for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) { | |
final boolean isLogger = ste.getClassName().startsWith(FyzLog.class.getName()); | |
hitLogger = hitLogger || isLogger; | |
if (hitLogger && !isLogger) { | |
return ste; | |
} | |
} | |
return new StackTraceElement(FyzLog.class.getName(), | |
"getCallingStackTraceElement", | |
null, | |
-1); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016 Fyzxs | |
* | |
* Licensed under The MIT License (MIT) | |
*/ | |
package com.quantityandconversion.log; | |
import android.util.Log; | |
import org.junit.Before; | |
import org.junit.Rule; | |
import org.junit.Test; | |
import org.junit.contrib.java.lang.system.SystemOutRule; | |
import org.junit.rules.ExpectedException; | |
import static org.assertj.core.api.Java6Assertions.assertThat; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertFalse; | |
import static org.junit.Assert.assertTrue; | |
import static org.junit.Assert.fail; | |
/** | |
* !!! DO NOT USE THIS TEST CLASS AS AN EXAMPLE !!! | |
* <p> | |
* Predominate issues with this test class | |
* <p> | |
* + Prefixed with 'The' | |
* A proper name for this class would be "FyzLogTests". | |
* Doing so triggers a condition internal, which shouldn't be re-written to bypass unit tests. | |
* <p> | |
* + Using System.out | |
* Don't do this. | |
*/ | |
@SuppressWarnings("ConstantConditions") | |
public class TheFyzLogTests { | |
@Rule | |
public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); | |
@Rule | |
public ExpectedException thrown = ExpectedException.none(); | |
/** | |
* This MUST reflect the {@link FyzLog#getLevelTag(int)} method | |
*/ | |
private static String getLevelTag(final int level) { | |
switch (level) { | |
case Log.VERBOSE: | |
return "V"; | |
case Log.DEBUG: | |
return "D"; | |
case Log.INFO: | |
return "I"; | |
case Log.WARN: | |
return "W"; | |
case Log.ERROR: | |
return "E"; | |
case Log.ASSERT: | |
return "WTF"; | |
default: | |
return "?"; | |
} | |
} | |
@Before | |
public void setup() { | |
FyzLog.logLevel = Log.VERBOSE; | |
FyzLog.doPrint = false; | |
systemOutRule.clearLog(); | |
} | |
private String configureSystemTest(final String prefix, final int level) { | |
systemOutRule.clearLog(); | |
FyzLog.doPrint = true; | |
final String logLevel = prefix + "@" + getLevelTag(level) + "/ "; | |
final String tag = "FYZ:TheFyzLogTests "; | |
final String thread = "[main] "; | |
return logLevel + tag + thread; | |
} | |
private String message() { | |
return "the message"; | |
} | |
private String messageFormat() { | |
return "%s %d %b %s"; | |
} | |
private Object[] messageArgs() { | |
return new Object[]{"it", 2357, true, "is"}; | |
} | |
@Test | |
public void massiveTestOfAllPrintMessageCombinations() { | |
//Tracks how many tests we performed | |
int ctr = 0;//Looping over the available Log calls | |
for (final String s : new String[]{"V", "D", "I", "W", "E", "WTF"}) { | |
//Looping over each logLevel, with an extra setting on each side | |
for (int i = Log.VERBOSE - 1; i <= Log.ASSERT + 1; i++) { | |
//Arrange | |
final String prefix = configureSystemTest(s, i); | |
final String msg = message(); | |
final String method = Thread.currentThread().getStackTrace()[1].getMethodName() + " : "; | |
//Set the Log Level | |
FyzLog.logLevel = i; | |
//Prep the expected value | |
final String expected = prefix + method + msg; | |
//Act | |
switch (s) { | |
case "V": | |
FyzLog.v(msg); | |
break; | |
case "D": | |
FyzLog.d(msg); | |
break; | |
case "I": | |
FyzLog.i(msg); | |
break; | |
case "W": | |
FyzLog.w(msg); | |
break; | |
case "E": | |
FyzLog.e(msg); | |
break; | |
case "WTF": | |
FyzLog.wtf(msg); | |
break; | |
} | |
//Assert | |
final String target = systemOutRule.getLog(); | |
assertEquals("Failed at [s=" + s + "][i=" + i + "]", expected + "\n", target); | |
//A test ran, inc | |
ctr++; | |
} | |
} | |
//Confirm we ran the expected number of tests | |
assertThat(ctr).isEqualTo(6 * (6 + 2)); | |
} | |
@Test | |
public void printMessageThrowsNullPointerExceptionGivenNull() { | |
//Tracks how many tests we performed | |
int ctr = 0; | |
//We're printing | |
FyzLog.doPrint = true; | |
//Looping over each logLevel | |
for (int i = Log.VERBOSE; i <= Log.ASSERT; i++) { | |
try { | |
switch (i) { | |
case Log.VERBOSE: | |
FyzLog.v(null); | |
break; | |
case Log.DEBUG: | |
FyzLog.d(null); | |
break; | |
case Log.INFO: | |
FyzLog.i(null); | |
break; | |
case Log.WARN: | |
FyzLog.w(null); | |
break; | |
case Log.ERROR: | |
FyzLog.e(null); | |
break; | |
case Log.ASSERT: | |
FyzLog.wtf(null); | |
break; | |
} | |
//We're expecting exceptions, make sure we don't get here | |
fail("Should Have Thrown"); | |
} catch (final IllegalArgumentException e) { | |
//Make sure it's the exception we wanted | |
assertThat(e.getMessage()).isEqualTo("FyzLog message can not be null"); | |
} | |
//inc the test performed count | |
ctr++; | |
} | |
//Verify we performed the expected tests | |
assertThat(ctr).isEqualTo(6); | |
} | |
@Test | |
public void massiveTestOfAllPrintMessageFormatCombinations() { | |
//Tracks how many tests we performed | |
int ctr = 0; | |
//Looping over the available Log calls | |
for (final String s : new String[]{"V", "D", "I", "W", "E", "WTF"}) { | |
//Looping over each logLevel, with an extra setting on each side | |
for (int i = Log.VERBOSE - 1; i <= Log.ASSERT + 1; i++) { | |
//Arrange | |
final String prefix = configureSystemTest(s, i); | |
final String msg = messageFormat(); | |
final String method = Thread.currentThread().getStackTrace()[1].getMethodName() + " : "; | |
//Set the Log Level | |
FyzLog.logLevel = i; | |
//Prep the expected value | |
final String expected = prefix + method + msg; | |
//Act | |
switch (s) { | |
case "V": | |
FyzLog.v(messageFormat(), messageArgs()); | |
break; | |
case "D": | |
FyzLog.d(messageFormat(), messageArgs()); | |
break; | |
case "I": | |
FyzLog.i(messageFormat(), messageArgs()); | |
break; | |
case "W": | |
FyzLog.w(messageFormat(), messageArgs()); | |
break; | |
case "E": | |
FyzLog.e(messageFormat(), messageArgs()); | |
break; | |
case "WTF": | |
FyzLog.wtf(messageFormat(), messageArgs()); | |
break; | |
} | |
//Assert | |
final String target = systemOutRule.getLog(); | |
assertEquals("Failed at [s=" + s + "][i=" + i + "]", | |
target, | |
String.format(expected, messageArgs()) + "\n"); | |
//A test ran, inc | |
ctr++; | |
} | |
} | |
//Confirm we ran the expected number of tests | |
assertThat(ctr).isEqualTo(6 * (6 + 2)); | |
} | |
/** | |
* Can't (easily) assert that it formats, so this just tests logging or not functionality of the | |
* log level setting. | |
*/ | |
@Test | |
public void massiveAndroidLogging() { | |
//Tracks how many tests we performed | |
int ctr = 0; | |
//Used to check if an exception should be thrown. | |
final int offset = Log.VERBOSE; | |
//The variation in the exception message | |
final String[] tags = new String[]{"v", "d", "i", "w", "e", "wtf"}; | |
//Looping over the available Log calls | |
for (int idx = 0; idx < tags.length; idx++) { | |
//Looping over each logLevel, with an extra setting on each side | |
for (int i = Log.VERBOSE - 1; i <= Log.ASSERT + 1; i++) { | |
//Set the Log Level | |
FyzLog.logLevel = i; | |
//Get the tag | |
final String tag = tags[idx]; | |
//Determine if logging will be attempted, which will result in an exception | |
final boolean shouldTryToLog = i <= idx + offset; | |
//Show what's about to be performed. If this breaks, it's HUGELY useful. | |
System.out.println("[idx=" + idx + ";" + tag + "][i=" + i + "][shouldTryToLog=" + shouldTryToLog + "]"); | |
//INVOKE | |
try { | |
switch (tag) { | |
case "v": | |
FyzLog.v(messageFormat(), messageArgs()); | |
break; | |
case "d": | |
FyzLog.d(messageFormat(), messageArgs()); | |
break; | |
case "i": | |
FyzLog.i(messageFormat(), messageArgs()); | |
break; | |
case "w": | |
FyzLog.w(messageFormat(), messageArgs()); | |
break; | |
case "e": | |
FyzLog.e(messageFormat(), messageArgs()); | |
break; | |
case "wtf": | |
FyzLog.wtf(messageFormat(), messageArgs()); | |
break; | |
} | |
//If we got here, we did not expect an exception, prove it | |
assertFalse("[idx=" + idx + ";" + tag + "][i=" + i + "]", shouldTryToLog); | |
} catch (final RuntimeException e) { | |
//If we got here, we expected to, prove it | |
assertThat(shouldTryToLog).isTrue(); | |
//Since this is kinda a catch all exception, make sure it's what we wanted | |
assertThat(e.getMessage()).isEqualTo("Method " + tag + " in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details."); | |
} | |
//A test ran, inc | |
ctr++; | |
} | |
} | |
//Confirm we ran the expected number of tests | |
assertThat(ctr).isEqualTo(6 * (6 + 2)); | |
} | |
@Test | |
public void androidLogDoesNothingGivenNull() { | |
FyzLog.doPrint = false; | |
systemOutRule.clearLog(); | |
FyzLog.logLevel = Log.VERBOSE - 1; | |
//All calls should bail w/o doing anything | |
FyzLog.v(null); | |
FyzLog.d(null); | |
FyzLog.i(null); | |
FyzLog.w(null); | |
FyzLog.e(null); | |
FyzLog.wtf(null); | |
//Also should not have logged via printing | |
assertThat(systemOutRule.getLog()).isNullOrEmpty(); | |
assertTrue("It should have gotten here", true); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016 Fyzxs | |
* | |
* Licensed under The MIT License (MIT) | |
*/ | |
package com.quantityandconversion.log; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.VisibleForTesting; | |
import android.util.Log; | |
import java.util.Locale; | |
/** | |
* Fyzxs Log(ger) | |
* <p> | |
* This lightweight static class wraps the Android logger. | |
* It allows customization of the logging process. | |
* <p> | |
* Most importantly, it allows control of the logging for | |
* unit testing purposes. | |
*/ | |
public final class FyzLog { | |
//Understands handling a user request to log | |
/** | |
* This is the tag prefix that will be displayed in the tag component of the {@link Log#v(String, String) Android Log} methods | |
*/ | |
private static final String TAG_PREFIX = "FYZ:"; | |
/** | |
* Write Log Message to {@link System#out#println} | |
*/ | |
@VisibleForTesting | |
public static boolean doPrint = false; | |
/** | |
* Controls the level of logging. | |
* This can be configured during build to limit logging messages to {@link Log#ERROR} or other levels. | |
* Default value is {@link Log#VERBOSE the lowest setting} | |
*/ | |
@VisibleForTesting | |
public static int logLevel = Log.VERBOSE; | |
/** | |
* The {@link Log#VERBOSE} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void v(@NonNull final String msg) { | |
v(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#VERBOSE} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void v(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
Logger.SystemOut.println(Log.VERBOSE, logLevel, msgFormat, args); | |
} else { | |
log(Log.VERBOSE, msgFormat, args); | |
} | |
} | |
/** | |
* The {@link Log#DEBUG} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void d(@NonNull final String msg) { | |
d(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#DEBUG} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void d(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
Logger.SystemOut.println(Log.DEBUG, logLevel, msgFormat, args); | |
} else { | |
log(Log.DEBUG, msgFormat, args); | |
} | |
} | |
/** | |
* The {@link Log#INFO} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void i(@NonNull final String msg) { | |
i(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#INFO} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void i(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
Logger.SystemOut.println(Log.INFO, logLevel, msgFormat, args); | |
} else { | |
log(Log.INFO, msgFormat, args); | |
} | |
} | |
/** | |
* The {@link Log#WARN} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void w(@NonNull final String msg) { | |
w(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#WARN} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void w(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
Logger.SystemOut.println(Log.WARN, logLevel, msgFormat, args); | |
} else { | |
log(Log.WARN, msgFormat, args); | |
} | |
} | |
//endregion | |
//region error | |
/** | |
* The {@link Log#ERROR} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void e(@NonNull final String msg) { | |
e(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#ERROR} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void e(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
Logger.SystemOut.println(Log.ERROR, logLevel, msgFormat, args); | |
} else { | |
log(Log.ERROR, msgFormat, args); | |
} | |
} | |
/** | |
* The {@link Log#ASSERT} level logging | |
* | |
* @param msg The message to log | |
*/ | |
public static void wtf(@NonNull final String msg) { | |
wtf(msg, (Object[]) null); | |
} | |
/** | |
* The {@link Log#ASSERT} level logging with string formatting | |
* | |
* @param msgFormat the format string | |
* @param args the args to format in | |
*/ | |
public static void wtf(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
Logger.SystemOut.println(Log.ASSERT, logLevel, msgFormat, args); | |
} else { | |
log(Log.ASSERT, msgFormat, args); | |
} | |
} | |
/** | |
* IFF the logLevel is high enough, logs to Android. | |
* <p> | |
* This will drop a null msg. | |
* | |
* @param level The invoking level of logging | |
* @param msgFormat the message format string | |
* @param args the args to format in | |
*/ | |
private static void log(final int level, final String msgFormat, final Object... args) { | |
if (level >= logLevel && msgFormat != null) { | |
final StackTraceElement frame = getCallingStackTraceElement(); | |
final String tag = createTag(frame); | |
final String msg = String.format(Locale.US, msgFormat, args); | |
final String message = createMessage(frame, msg); | |
switch (level) { | |
case Log.VERBOSE: | |
Log.v(tag, message); | |
break; | |
case Log.DEBUG: | |
Log.d(tag, message); | |
break; | |
case Log.INFO: | |
Log.i(tag, message); | |
break; | |
case Log.WARN: | |
Log.w(tag, message); | |
break; | |
case Log.ERROR: | |
Log.e(tag, message); | |
break; | |
case Log.ASSERT: | |
Log.wtf(tag, message); | |
break; | |
} | |
} | |
} | |
/** | |
* Creates the tag to be used | |
* | |
* @param frame {@link StackTraceElement} to build the tag from | |
* @return Tag to use for the logged message | |
*/ | |
private static String createTag(final StackTraceElement frame) { | |
final String fullClassName = frame.getClassName(); | |
final String className = fullClassName.substring(fullClassName.lastIndexOf('.') + 1); | |
return TAG_PREFIX + className; | |
} | |
/** | |
* Builds the final message to be logged. | |
* The format will be | |
* InvokingMethodName [currentThreadName] providedMessage | |
* | |
* @param frame The {@link StackTraceElement} to pull the method name from | |
* @param msg the message to prefix the method name to | |
* @return The final message string | |
*/ | |
private static String createMessage(final StackTraceElement frame, final String msg) { | |
return String.format(Locale.US, | |
"[%s] %s : %s", | |
Thread.currentThread().getName(), | |
frame.getMethodName(), | |
msg); | |
} | |
/** | |
* Gets the {@link StackTraceElement} for the method that invoked logging | |
* | |
* @return {@link StackTraceElement} for the caller into {@link FyzLog} | |
*/ | |
private static StackTraceElement getCallingStackTraceElement() { | |
boolean hitLogger = false; | |
for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) { | |
final boolean isLogger = ste.getClassName().startsWith(FyzLog.class.getName()); | |
hitLogger = hitLogger || isLogger; | |
if (hitLogger && !isLogger) { | |
return ste; | |
} | |
} | |
return new StackTraceElement(FyzLog.class.getName(), | |
"getCallingStackTraceElement", | |
null, | |
-1); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void wtf(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
Logger.println(LogLevel.ASSERT, logLevel, msgFormat, args); | |
} else { | |
log(Log.ASSERT, msgFormat, args); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void wtf(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
Logger.SystemOut.println(Log.ASSERT, logLevel, msgFormat, args); | |
} else { | |
log(Log.ASSERT, msgFormat, args); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* package */ class Logger { | |
/* package */ static final Logger SystemOut = new Logger(); | |
private Logger(){} | |
... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016 Fyzxs | |
* | |
* Licensed under The MIT License (MIT) | |
*/ | |
package com.quantityandconversion.log; | |
import org.junit.Before; | |
import org.junit.Rule; | |
import org.junit.Test; | |
import org.junit.contrib.java.lang.system.SystemOutRule; | |
import org.junit.rules.ExpectedException; | |
import static org.assertj.core.api.Java6Assertions.assertThat; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertFalse; | |
import static org.junit.Assert.assertTrue; | |
import static org.junit.Assert.fail; | |
/** | |
* !!! DO NOT USE THIS TEST CLASS AS AN EXAMPLE !!! | |
* <p> | |
* Predominate issues with this test class | |
* <p> | |
* + Prefixed with 'The' | |
* A proper name for this class would be "FyzLogTests". | |
* Doing so triggers a condition internal, which shouldn't be re-written to bypass unit tests. | |
* <p> | |
* + Using System.out | |
* Don't do this. | |
*/ | |
@SuppressWarnings("ConstantConditions") | |
public class TheFyzLogTests { | |
@Rule | |
public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); | |
@Rule | |
public ExpectedException thrown = ExpectedException.none(); | |
@Before | |
public void setup() { | |
FyzLog.logLevel = LogLevel.VERBOSE; | |
FyzLog.doPrint = false; | |
systemOutRule.clearLog(); | |
} | |
private String configureSystemTest(final LogLevel currentLogLevel, final LogLevel attemptingLogLevel) { | |
systemOutRule.clearLog(); | |
FyzLog.doPrint = true; | |
final String logLevel = attemptingLogLevel.tag() + "@" + currentLogLevel.tag() + "/ "; | |
final String tag = "FYZ:TheFyzLogTests "; | |
final String thread = "[main] "; | |
return logLevel + tag + thread; | |
} | |
private String message() { | |
return "the message"; | |
} | |
private String messageFormat() { | |
return "%s %d %b %s"; | |
} | |
private Object[] messageArgs() { | |
return new Object[]{"it", 2357, true, "is"}; | |
} | |
@Test | |
public void massiveTestOfAllPrintMessageCombinations() { | |
//Tracks how many tests we performed | |
int ctr = 0; | |
final LogLevel[] logLevels = new LogLevel[]{LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.ASSERT}; | |
for (final LogLevel currentLogLevel : logLevels) { | |
//Set the Log Level | |
FyzLog.logLevel = currentLogLevel; | |
//Looping over each logLevel | |
for (final LogLevel attemptingLogLevel : logLevels) { | |
//Arrange | |
final String prefix = configureSystemTest(currentLogLevel, attemptingLogLevel); | |
final String msg = message(); | |
final String method = Thread.currentThread().getStackTrace()[1].getMethodName() + " : "; | |
//Prep the expected value | |
final String expected = prefix + method + msg; | |
//Act | |
if (attemptingLogLevel == LogLevel.VERBOSE) FyzLog.v(msg); | |
else if (attemptingLogLevel == LogLevel.DEBUG) FyzLog.d(msg); | |
else if (attemptingLogLevel == LogLevel.INFO) FyzLog.i(msg); | |
else if (attemptingLogLevel == LogLevel.WARN) FyzLog.w(msg); | |
else if (attemptingLogLevel == LogLevel.ERROR) FyzLog.e(msg); | |
else if (attemptingLogLevel == LogLevel.ASSERT) FyzLog.wtf(msg); | |
//Assert | |
final String target = systemOutRule.getLog(); | |
assertEquals("Failed at [currentLogLevel=" + currentLogLevel.tag() + "][attemptingLogLevel=" + attemptingLogLevel.tag() + "]", expected + "\n", target); | |
//A test ran, inc | |
ctr++; | |
} | |
} | |
//Confirm we ran the expected number of tests | |
assertThat(ctr).isEqualTo(6 * 6); | |
} | |
@Test | |
public void printMessageThrowsNullPointerExceptionGivenNull() { | |
//Tracks how many tests we performed | |
int ctr = 0; | |
//We're printing | |
FyzLog.doPrint = true; | |
//Looping over each logLevel | |
for (final LogLevel logLevel : new LogLevel[]{LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.ASSERT}) { | |
try { | |
if (logLevel == LogLevel.VERBOSE) FyzLog.v(null); | |
else if (logLevel == LogLevel.DEBUG) FyzLog.d(null); | |
else if (logLevel == LogLevel.INFO) FyzLog.i(null); | |
else if (logLevel == LogLevel.WARN) FyzLog.w(null); | |
else if (logLevel == LogLevel.ERROR) FyzLog.e(null); | |
else if (logLevel == LogLevel.ASSERT) FyzLog.wtf(null); | |
//We're expecting exceptions, make sure we don't get here | |
fail("Should Have Thrown"); | |
} catch (final IllegalArgumentException e) { | |
//Make sure it's the exception we wanted | |
assertThat(e.getMessage()).isEqualTo("FyzLog message can not be null"); | |
} | |
//inc the test performed count | |
ctr++; | |
} | |
//Verify we performed the expected tests | |
assertThat(ctr).isEqualTo(6); | |
} | |
@Test | |
public void massiveTestOfAllPrintMessageFormatCombinations() { | |
//Tracks how many tests we performed | |
int ctr = 0; | |
//Looping over the available Log calls | |
final LogLevel[] logLevels = new LogLevel[]{LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.ASSERT}; | |
for (final LogLevel currentLogLevel : logLevels) { | |
//Set the Log Level | |
FyzLog.logLevel = currentLogLevel; | |
//Looping over each logLevel | |
for (final LogLevel attemptingLogLevel : logLevels) { | |
//Arrange | |
final String prefix = configureSystemTest(currentLogLevel, attemptingLogLevel); | |
final String msg = messageFormat(); | |
final String method = Thread.currentThread().getStackTrace()[1].getMethodName() + " : "; | |
//Prep the expected value | |
final String expected = prefix + method + msg; | |
//Act | |
if (attemptingLogLevel == LogLevel.VERBOSE) | |
FyzLog.v(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.DEBUG) | |
FyzLog.d(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.INFO) | |
FyzLog.i(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.WARN) | |
FyzLog.w(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.ERROR) | |
FyzLog.e(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.ASSERT) | |
FyzLog.wtf(messageFormat(), messageArgs()); | |
//Assert | |
final String target = systemOutRule.getLog(); | |
assertEquals("Failed at [currentLogLevel=" + currentLogLevel.tag() + "][attemptingLogLevel=" + attemptingLogLevel.tag() + "]", | |
target, | |
String.format(expected, messageArgs()) + "\n"); | |
//A test ran, inc | |
ctr++; | |
} | |
} | |
//Confirm we ran the expected number of tests | |
assertThat(ctr).isEqualTo(6 * 6); | |
} | |
/** | |
* Can't (easily) assert that it formats, so this just tests logging or not functionality of the | |
* log level setting. | |
*/ | |
@Test | |
public void massiveAndroidLogging() { | |
//Tracks how many tests we performed | |
int ctr = 0; | |
final LogLevel[] logLevels = new LogLevel[]{LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.ASSERT}; | |
//Looping over the available Log calls | |
for (final LogLevel currentLogLevel : logLevels) { | |
//Set the Log Level | |
FyzLog.logLevel = currentLogLevel; | |
//Looping over each logLevel | |
for (final LogLevel attemptingLogLevel : logLevels) { | |
//Determine if logging will be attempted, which will result in an exception | |
final boolean shouldTryToLog = attemptingLogLevel.logAt(currentLogLevel); | |
//Show what's about to be performed. If this breaks, it's HUGELY useful. | |
System.out.println("[currentLogLevel=" + currentLogLevel.tag() + "][attemptingLogLevel=" + attemptingLogLevel.tag() + "][shouldTryToLog=" + shouldTryToLog + "]"); | |
//INVOKE | |
try { | |
if (attemptingLogLevel == LogLevel.VERBOSE) | |
FyzLog.v(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.DEBUG) | |
FyzLog.d(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.INFO) | |
FyzLog.i(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.WARN) | |
FyzLog.w(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.ERROR) | |
FyzLog.e(messageFormat(), messageArgs()); | |
else if (attemptingLogLevel == LogLevel.ASSERT) | |
FyzLog.wtf(messageFormat(), messageArgs()); | |
//If we got here, we did not expect an exception, prove it | |
assertFalse("[currentLogLevel=" + currentLogLevel.tag() + "][attemptingLogLevel=" + attemptingLogLevel.tag() + "]", shouldTryToLog); | |
} catch (final RuntimeException e) { | |
//If we got here, we expected to, prove it | |
assertThat(shouldTryToLog).isTrue(); | |
//Since this is kinda a catch all exception, make sure it's what we wanted | |
assertThat(e.getMessage()).isEqualTo("Method " + attemptingLogLevel.tag().toLowerCase() + " in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details."); | |
} | |
//A test ran, inc | |
ctr++; | |
} | |
} | |
//Confirm we ran the expected number of tests | |
assertThat(ctr).isEqualTo(6 * 6); | |
} | |
@Test | |
public void androidLogDoesNothingGivenNull() { | |
FyzLog.doPrint = false; | |
systemOutRule.clearLog(); | |
FyzLog.logLevel = LogLevel.VERBOSE; | |
//All calls should bail w/o doing anything | |
FyzLog.v(null); | |
FyzLog.d(null); | |
FyzLog.i(null); | |
FyzLog.w(null); | |
FyzLog.e(null); | |
FyzLog.wtf(null); | |
//Also should not have logged via printing | |
assertThat(systemOutRule.getLog()).isNullOrEmpty(); | |
assertTrue("It should have gotten here", true); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* package */ class Logger { ... } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* package */ static void println(final int level, final int logLevel, final String msgFormat, final Object... args){ | |
... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void wtf(@NonNull final String msgFormat, final Object... args) { | |
if (doPrint) { | |
Logger.println(Log.ASSERT, logLevel, msgFormat, args); | |
} else { | |
log(Log.ASSERT, msgFormat, args); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment