--- /dev/null 2015-11-20 17:44:38.000000000 +0100 +++ new/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java 2015-11-20 17:44:38.000000000 +0100 @@ -0,0 +1,2316 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8140364 + * @author danielfuchs + * @summary JDK implementation specific unit test for JDK internal artifacts. + * This test tests all the public API methods defined in the {@link + * java.lang.System.Logger} interface, as well as all the JDK + * internal methods defined in the + * {@link sun.util.logging.PlatformLogger.Bridge} + * interface, with loggers returned by {@link + * java.lang.System.LoggerFinder#getLogger(java.lang.String, java.lang.Class)} + * and {@link java.lang.System.LoggerFinder#getLocalizedLogger(java.lang.String, + * java.util.ResourceBundle, java.lang.Class)} + * (using both a null resource bundle and a non null resource bundle). + * It calls both the {@link java.lang.System} factory methods and + * {@link jdk.internal.logger.LazyLoggers} to obtains those loggers, + * and configure them with all possible known levels. + * @modules java.base/sun.util.logging + * java.base/jdk.internal.logger + * java.logging/sun.util.logging.internal + * @build LoggerFinderBackendTest SystemClassLoader + * @run main/othervm -Djava.system.class.loader=SystemClassLoader -Dtest.logger.hidesProvider=true LoggerFinderBackendTest + * @run main/othervm -Djava.system.class.loader=SystemClassLoader -Dtest.logger.hidesProvider=false LoggerFinderBackendTest + */ + + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.ResourceBundle; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiFunction; +import java.util.function.BooleanSupplier; +import java.util.function.Function; +import java.util.function.Supplier; +import java.lang.System.LoggerFinder; +import java.util.logging.ConsoleHandler; +import java.util.logging.Handler; +import sun.util.logging.PlatformLogger.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import sun.util.logging.internal.LoggingProviderImpl; + +/** + * @author danielfuchs + */ +public class LoggerFinderBackendTest { + + // whether the implementation of Logger try to do a best + // effort for logp... If the provider is not hidden, then + // the logp() implementation comes from LoggerWrapper - which does a + // best effort. Otherwise, it comes from the default provider + // which does support logp. + static final boolean BEST_EFFORT_FOR_LOGP = + !Boolean.getBoolean("test.logger.hidesProvider"); + static final boolean VERBOSE = false; + + static final Class spiLoggerClass = + java.lang.System.Logger.class; + static final Class jdkLoggerClass = + java.lang.System.Logger.class; + static final Class bridgeLoggerClass = + sun.util.logging.PlatformLogger.Bridge.class; + + /** Use to retrieve the log records that were produced by the JUL backend */ + static class LoggerTesterHandler extends Handler { + public final List records = + Collections.synchronizedList(new ArrayList<>()); + + @Override + public void publish(LogRecord record) { + record.getSourceClassName(); record.getSourceMethodName(); + records.add(record); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + records.clear(); + } + + public void reset() { + records.clear(); + } + } + + /** The {@link LoggerTesterHandler} handler is added to the root logger. */ + static final LoggerTesterHandler handler = new LoggerTesterHandler(); + static { + for (Handler h : Logger.getLogger("").getHandlers()) { + if (h instanceof ConsoleHandler) { + Logger.getLogger("").removeHandler(h); + } + } + Logger.getLogger("").addHandler(handler); + } + + /** + * A resource handler parameter that will be used when calling out the + * logrb-like methods - as well as when calling the level-specific + * methods that take a ResourceBundle parameter. + */ + public static class ResourceBundeParam extends ResourceBundle { + Map map = Collections.synchronizedMap(new LinkedHashMap<>()); + @Override + protected Object handleGetObject(String key) { + map.putIfAbsent(key, "${"+key+"}"); + return map.get(key); + } + + @Override + public Enumeration getKeys() { + return Collections.enumeration(new LinkedHashSet<>(map.keySet())); + } + + } + + final static ResourceBundle bundleParam = + ResourceBundle.getBundle(ResourceBundeParam.class.getName()); + + /** + * A resource handler parameter that will be used when creating localized + * loggers by calling {@link + * LoggerFinder#getLocalizedLogger(java.lang.String, java.util.ResourceBundle, java.lang.Class)}. + */ + public static class ResourceBundeLocalized extends ResourceBundle { + Map map = Collections.synchronizedMap(new LinkedHashMap<>()); + @Override + protected Object handleGetObject(String key) { + map.putIfAbsent(key, "Localized:${"+key+"}"); + return map.get(key); + } + + @Override + public Enumeration getKeys() { + return Collections.enumeration(new LinkedHashSet<>(map.keySet())); + } + + } + + /** + * The Levels enum is used to call all the level-specific methods on + * a logger instance. To minimize the amount of code it uses reflection + * to do so. + */ + static Lookup lookup = MethodHandles.lookup(); + public enum Levels { + /** Used to call all forms of Logger.log?(SEVERE, ...) */ + SEVERE("severe", bridgeLoggerClass, Level.SEVERE, null, "error", false), + /** Used to call all forms of Logger.log?(WARNING,...) */ + WARNING("warning", bridgeLoggerClass, Level.WARNING, "warning", "warning", false), + /** Used to call all forms of Logger.log?(INFO,...) */ + INFO("info", bridgeLoggerClass, Level.INFO, "info", "info", false), + /** Used to call all forms of Logger.log?(CONFIG,...) */ + CONFIG("config", bridgeLoggerClass, Level.CONFIG, null, "debug", false), + /** Used to call all forms of Logger.log?(FINE,...) */ + FINE("fine", bridgeLoggerClass, Level.FINE, null, "debug", false), + /** Used to call all forms of Logger.log?(FINER,...) */ + FINER("finer", bridgeLoggerClass, Level.FINER, null, "trace", false), + /** Used to call all forms of Logger.log?(FINEST,...) */ + FINEST("finest", bridgeLoggerClass, Level.FINEST, null, "trace", false), + ; + public final String method; // The name of the level-specific method to call + public final Class definingClass; // which interface j.u.logger.Logger or j.u.logging.spi.Logger defines it + public final Level platformLevel; // The platform Level it will be mapped to in Jul when Jul is the backend + public final String jdkExtensionToJUL; // The name of the method called on the JUL logger when JUL is the backend + public final String julToJdkExtension; // The name of the method called in the jdk extension by the default impl in jdk.internal.logging.Logger + public final String enableMethod; // The name of the isXxxxEnabled method + public final boolean hasSpecificIsEnabled; + Levels(String method, Class definingClass, Level defaultMapping, + String jdkExtensionToJUL, String julToJdkExtension, + boolean hasSpecificIsEnabled) { + this.method = method; + this.definingClass = definingClass; + this.platformLevel = defaultMapping; + this.jdkExtensionToJUL = jdkExtensionToJUL; + this.julToJdkExtension = julToJdkExtension; + this.hasSpecificIsEnabled = hasSpecificIsEnabled; + if (hasSpecificIsEnabled) { + this.enableMethod = "is" + method.substring(0,1).toUpperCase() + + method.substring(1) + "Enabled"; + } else { + this.enableMethod = "isLoggable"; + } + } + + /* + * calls this level specific method - e.g. if this==INFO: logger.info(msg); + */ + public void level(Object logger, String msg) { + MethodType mt = MethodType.methodType(void.class, Level.class, String.class); + invoke("log", logger, mt, platformLevel, msg); + } + + /* + * calls this level specific method - e.g. if this==INFO: logger.info(msgSupplier); + */ + public void level(Object logger, Supplier msgSupplier) { + MethodType mt = MethodType.methodType(void.class, Level.class, Supplier.class); + invoke("log", logger, mt, platformLevel, msgSupplier); + } + + /* + * calls this level specific method - e.g. if this==INFO: logger.info(msg, params); + */ + public void level(Object logger, String msg, Object... params) { + MethodType mt = MethodType.methodType(void.class, Level.class, String.class, + Object[].class); + invoke("log", logger, mt, platformLevel, msg, params); + } + + /* + * calls this level specific method - e.g. if this==INFO: logger.info(msg, thrown); + */ + public void level(Object logger, String msg, Throwable thrown) { + MethodType mt = MethodType.methodType(void.class, Level.class, String.class, + Throwable.class); + invoke("log", logger, mt, platformLevel, msg, thrown); + } + + /* + * calls this level specific method - e.g. if this==INFO: logger.info(msgSupplier, thrown); + */ + public void level(Object logger, Supplier msgSupplier, Throwable thrown) { + MethodType mt = MethodType.methodType(void.class, Level.class, + Throwable.class, Supplier.class); + invoke("log", logger, mt, platformLevel, thrown, msgSupplier); + } + + /* + * calls this level specific method - e.g. if this==INFO: logger.info(bundle, msg); + */ + public void level(Object logger, String msg, ResourceBundle bundle) { + MethodType mt = MethodType.methodType(void.class, Level.class, + ResourceBundle.class, String.class, Object[].class); + invoke("logrb", logger, mt, platformLevel, bundle, msg, null); + } + + public void level(Object logger, String msg, ResourceBundle bundle, + Object... params) { + MethodType mt = MethodType.methodType(void.class, Level.class, + ResourceBundle.class, String.class, Object[].class); + invoke("logrb", logger, mt, platformLevel, bundle, msg, params); + } + + public void level(Object logger, String msg, ResourceBundle bundle, + Throwable thrown) { + MethodType mt = MethodType.methodType(void.class, Level.class, + ResourceBundle.class, String.class, Throwable.class); + invoke("logrb", logger, mt, platformLevel, bundle, msg, thrown); + } + + public boolean isEnabled(Object logger) { + try { + if (hasSpecificIsEnabled) { + MethodType mt = MethodType.methodType(boolean.class); + final MethodHandle handle = lookup.findVirtual(definingClass, + enableMethod, mt).bindTo(logger); + return Boolean.class.cast(handle.invoke()); + } else { + MethodType mt = MethodType.methodType(boolean.class, + Level.class); + final MethodHandle handle = lookup.findVirtual(definingClass, + enableMethod, mt).bindTo(logger); + return Boolean.class.cast(handle.invoke(platformLevel)); + } + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + private void invoke(String method, Object logger, MethodType mt, Object... args) { + try { + final int last = mt.parameterCount()-1; + boolean isVarargs = mt.parameterType(last).isArray(); + final MethodHandle handle = lookup.findVirtual(definingClass, + method, mt).bindTo(logger); + + final StringBuilder builder = new StringBuilder(); + builder.append(logger.getClass().getSimpleName()).append('.') + .append(method).append('('); + String sep = ""; + int offset = 0; + Object[] params = args; + for (int i=0; (i-offset) < params.length; i++) { + if (isVarargs && i == last) { + offset = last; + params = (Object[])args[i]; + if (params == null) break; + } + Object p = params[i - offset]; + String quote = (p instanceof String) ? "\"" : ""; + builder.append(sep).append(quote).append(p).append(quote); + sep = ", "; + } + builder.append(')'); + if (verbose) { + System.out.println(builder); + } + handle.invokeWithArguments(args); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + }; + + static interface Checker extends BiFunction {} + static interface JdkLogTester + extends BiFunction {} + static interface SpiLogTester + extends BiFunction {} + + static interface MethodInvoker { + public void logX(LOGGER logger, LEVEL level, Object... args); + } + + public enum JdkLogMethodInvoker + implements MethodInvoker { + /** + * Tests {@link + * jdk.internal.logging.Logger#log(Level, String, Object...)}; + **/ + LOG_STRING_PARAMS("log", MethodType.methodType(void.class, + Level.class, String.class, Object[].class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#log(Level, String, Throwable)}; + **/ + LOG_STRING_THROWN("log", MethodType.methodType(void.class, + Level.class, String.class, Throwable.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#log(Level, Supplier)}; + **/ + LOG_SUPPLIER("log", MethodType.methodType(void.class, + Level.class, Supplier.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#log(Level, Throwable, Supplier)}; + **/ + LOG_SUPPLIER_THROWN("log", MethodType.methodType(void.class, + Level.class, Throwable.class, Supplier.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logp(Level, String, String, String)}; + **/ + LOGP_STRING("logp", MethodType.methodType(void.class, + Level.class, String.class, String.class, String.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logp(Level, String, String, String, Object...)}; + **/ + LOGP_STRING_PARAMS("logp", MethodType.methodType(void.class, + Level.class, String.class, String.class, String.class, Object[].class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logp(Level, String, String, String, Throwable)}; + **/ + LOGP_STRING_THROWN("logp", MethodType.methodType(void.class, + Level.class, String.class, String.class, String.class, Throwable.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logp(Level, String, String, Supplier)}; + **/ + LOGP_SUPPLIER("logp", MethodType.methodType(void.class, + Level.class, String.class, String.class, Supplier.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logp(Level, String, String, Throwable, Supplier)}; + **/ + LOGP_SUPPLIER_THROWN("logp", MethodType.methodType(void.class, + Level.class, String.class, String.class, + Throwable.class, Supplier.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Object...)}; + **/ + LOGRB_STRING_PARAMS("logrb", MethodType.methodType(void.class, + Level.class, ResourceBundle.class, String.class, Object[].class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Throwable)}; + **/ + LOGRB_STRING_THROWN("logrb", MethodType.methodType(void.class, + Level.class, ResourceBundle.class, String.class, Throwable.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logrb(Level, String, String, ResourceBundle, String, Object...)}; + **/ + LOGRBP_STRING_PARAMS("logrb", MethodType.methodType(void.class, + Level.class, String.class, String.class, ResourceBundle.class, + String.class, Object[].class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logrb(Level, String, String, ResourceBundle, String, Throwable)}; + **/ + LOGRBP_STRING_THROWN("logrb", MethodType.methodType(void.class, + Level.class, String.class, String.class, ResourceBundle.class, + String.class, Throwable.class)), + ; + final MethodType mt; + final String method; + JdkLogMethodInvoker(String method, MethodType mt) { + this.mt = mt; + this.method = method; + } + Object[] makeArgs(Level level, Object... rest) { + List list = new ArrayList<>(rest == null ? 1 : rest.length + 1); + list.add(level); + if (rest != null) { + list.addAll(Arrays.asList(rest)); + } + return list.toArray(new Object[list.size()]); + } + + @Override + public void logX(sun.util.logging.PlatformLogger.Bridge logger, Level level, Object... args) { + try { + MethodHandle handle = lookup.findVirtual(bridgeLoggerClass, + method, mt).bindTo(logger); + final int last = mt.parameterCount()-1; + boolean isVarargs = mt.parameterType(last).isArray(); + + args = makeArgs(level, args); + + final StringBuilder builder = new StringBuilder(); + builder.append(logger.getClass().getSimpleName()).append('.') + .append(this.method).append('('); + String sep = ""; + int offset = 0; + Object[] params = args; + for (int i=0; (i-offset) < params.length; i++) { + if (isVarargs && i == last) { + offset = last; + params = (Object[])args[i]; + if (params == null) break; + } + Object p = params[i - offset]; + String quote = (p instanceof String) ? "\"" : ""; + p = p instanceof Level ? "Level."+p : p; + builder.append(sep).append(quote).append(p).append(quote); + sep = ", "; + } + builder.append(')'); + if (verbose) System.out.println(builder); + handle.invokeWithArguments(args); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + } + + + public enum SpiLogMethodInvoker implements MethodInvoker { + /** + * Tests {@link + * jdk.internal.logging.Logger#log(Level, String, Object...)}; + **/ + LOG_STRING_PARAMS("log", MethodType.methodType(void.class, + java.lang.System.Logger.Level.class, String.class, Object[].class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#log(Level, String, Throwable)}; + **/ + LOG_STRING_THROWN("log", MethodType.methodType(void.class, + java.lang.System.Logger.Level.class, String.class, Throwable.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#log(Level, Supplier)}; + **/ + LOG_SUPPLIER("log", MethodType.methodType(void.class, + java.lang.System.Logger.Level.class, Supplier.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#log(Level, Throwable, Supplier)}; + **/ + LOG_SUPPLIER_THROWN("log", MethodType.methodType(void.class, + java.lang.System.Logger.Level.class, Supplier.class, Throwable.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#log(Level, Supplier)}; + **/ + LOG_OBJECT("log", MethodType.methodType(void.class, + java.lang.System.Logger.Level.class, Object.class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Object...)}; + **/ + LOGRB_STRING_PARAMS("log", MethodType.methodType(void.class, + java.lang.System.Logger.Level.class, ResourceBundle.class, + String.class, Object[].class)), + /** + * Tests {@link + * jdk.internal.logging.Logger#logrb(Level, ResourceBundle, String, Throwable)}; + **/ + LOGRB_STRING_THROWN("log", MethodType.methodType(void.class, + java.lang.System.Logger.Level.class, ResourceBundle.class, + String.class, Throwable.class)), + ; + final MethodType mt; + final String method; + SpiLogMethodInvoker(String method, MethodType mt) { + this.mt = mt; + this.method = method; + } + Object[] makeArgs(java.lang.System.Logger.Level level, Object... rest) { + List list = new ArrayList<>(rest == null ? 1 : rest.length + 1); + list.add(level); + if (rest != null) { + list.addAll(Arrays.asList(rest)); + } + return list.toArray(new Object[list.size()]); + } + + @Override + public void logX(java.lang.System.Logger logger, + java.lang.System.Logger.Level level, Object... args) { + try { + MethodHandle handle = lookup.findVirtual(spiLoggerClass, + method, mt).bindTo(logger); + final int last = mt.parameterCount()-1; + boolean isVarargs = mt.parameterType(last).isArray(); + + args = makeArgs(level, args); + + final StringBuilder builder = new StringBuilder(); + builder.append(logger.getClass().getSimpleName()).append('.') + .append(this.method).append('('); + String sep = ""; + int offset = 0; + Object[] params = args; + for (int i=0; (i-offset) < params.length; i++) { + if (isVarargs && i == last) { + offset = last; + params = (Object[])args[i]; + if (params == null) break; + } + Object p = params[i - offset]; + String quote = (p instanceof String) ? "\"" : ""; + p = p instanceof Level ? "Level."+p : p; + builder.append(sep).append(quote).append(p).append(quote); + sep = ", "; + } + builder.append(')'); + if (verbose) System.out.println(builder); + handle.invokeWithArguments(args); + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + } + + + public abstract static class BackendTester { + static final Level[] levelMap = {Level.ALL, Level.FINER, Level.FINE, + Level.INFO, Level.WARNING, Level.SEVERE, Level.OFF}; + + abstract class BackendAdaptor { + public abstract String getLoggerName(BackendRecord res); + public abstract Object getLevel(BackendRecord res); + public abstract String getMessage(BackendRecord res); + public abstract String getSourceClassName(BackendRecord res); + public abstract String getSourceMethodName(BackendRecord res); + public abstract Throwable getThrown(BackendRecord res); + public abstract ResourceBundle getResourceBundle(BackendRecord res); + public abstract void setLevel(java.lang.System.Logger logger, + Level level); + public abstract void setLevel(java.lang.System.Logger logger, + java.lang.System.Logger.Level level); + public abstract List getBackendRecords(); + public abstract void resetBackendRecords(); + public boolean shouldBeLoggable(Levels level, Level loggerLevel) { + final Level logLevel = level.platformLevel; + return shouldBeLoggable(logLevel, loggerLevel); + } + public boolean shouldBeLoggable(Level logLevel, Level loggerLevel) { + return loggerLevel.intValue() != Level.OFF.intValue() + && logLevel.intValue() >= loggerLevel.intValue(); + } + public boolean shouldBeLoggable(java.lang.System.Logger.Level logLevel, + java.lang.System.Logger.Level loggerLevel) { + return loggerLevel != java.lang.System.Logger.Level.OFF + && logLevel.ordinal() >= loggerLevel.ordinal(); + } + public boolean isLoggable(java.lang.System.Logger logger, Level l) { + return bridgeLoggerClass.cast(logger).isLoggable(l); + } + public String getCallerClassName(Levels level, String clazz) { + return clazz != null ? clazz : Levels.class.getName(); + } + public String getCallerClassName(MethodInvoker logMethod, + String clazz) { + return clazz != null ? clazz : logMethod.getClass().getName(); + } + public String getCallerMethodName(Levels level, String method) { + return method != null ? method : "invoke"; + } + public String getCallerMethodName(MethodInvoker logMethod, + String method) { + return method != null ? method : "logX"; + } + public Object getMappedLevel(Object level) { + return level; + } + + public Level toJUL(java.lang.System.Logger.Level level) { + return levelMap[level.ordinal()]; + } + } + + public final boolean isSystem; + public final Class restrictedTo; + public final ResourceBundle localized; + public BackendTester(boolean isSystem) { + this(isSystem,null,null); + } + public BackendTester(boolean isSystem, ResourceBundle localized) { + this(isSystem,null,localized); + } + public BackendTester(boolean isSystem, + Class restrictedTo) { + this(isSystem, restrictedTo, null); + } + public BackendTester(boolean isSystem, + Class restrictedTo, + ResourceBundle localized) { + this.isSystem = isSystem; + this.restrictedTo = restrictedTo; + this.localized = localized; + } + + public java.lang.System.Logger convert(java.lang.System.Logger logger) { + return logger; + } + + public static Level[] LEVELS = { + Level.OFF, + Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG, + Level.FINE, Level.FINER, Level.FINEST, + Level.ALL + }; + + abstract BackendAdaptor adaptor(); + + protected void checkRecord(Levels test, BackendRecord res, String loggerName, + Level level, String msg, String className, String methodName, + Throwable thrown, ResourceBundle bundle, Object... params) { + checkRecord(test, res, loggerName, level, ()->msg, className, + methodName, thrown, bundle, params); + + } + protected void checkRecord(Levels test, BackendRecord res, String loggerName, + Level level, Supplier msg, String className, String methodName, + Throwable thrown, ResourceBundle bundle, Object... params) { + checkRecord(test.method, res, loggerName, level, msg, + className, methodName, thrown, bundle, params); + } + protected void checkRecord(String logMethod, BackendRecord res, String loggerName, + L level, Supplier msg, String className, String methodName, + Throwable thrown, ResourceBundle bundle, Object... params) { + final BackendAdaptor analyzer = adaptor(); + if (! Objects.equals(analyzer.getLoggerName(res), loggerName)) { + throw new RuntimeException(logMethod+": expected logger name " + + loggerName + " got " + analyzer.getLoggerName(res)); + } + if (!Objects.equals(analyzer.getLevel(res), analyzer.getMappedLevel(level))) { + throw new RuntimeException(logMethod+": expected level " + + analyzer.getMappedLevel(level) + " got " + analyzer.getLevel(res)); + } + if (!Objects.equals(analyzer.getMessage(res), msg.get())) { + throw new RuntimeException(logMethod+": expected message \"" + + msg.get() + "\" got \"" + analyzer.getMessage(res) +"\""); + } + if (!Objects.equals(analyzer.getSourceClassName(res), className)) { + throw new RuntimeException(logMethod + + ": expected class name \"" + className + + "\" got \"" + analyzer.getSourceClassName(res) +"\""); + } + if (!Objects.equals(analyzer.getSourceMethodName(res), methodName)) { + throw new RuntimeException(logMethod + + ": expected method name \"" + methodName + + "\" got \"" + analyzer.getSourceMethodName(res) +"\""); + } + final Throwable thrownRes = analyzer.getThrown(res); + if (!Objects.equals(thrownRes, thrown)) { + throw new RuntimeException(logMethod + + ": expected throwable \"" + thrown + + "\" got \"" + thrownRes + "\""); + } + if (!Objects.equals(analyzer.getResourceBundle(res), bundle)) { + throw new RuntimeException(logMethod + + ": expected bundle \"" + bundle + + "\" got \"" + analyzer.getResourceBundle(res) +"\""); + } + } + + public void testLevel(Levels level, java.lang.System.Logger logger, + String msg) { + Runnable test = () -> level.level(logger, msg); + Checker check = (res, l) -> { + checkRecord(level, res, logger.getName(), l, msg, + adaptor().getCallerClassName(level, Levels.class.getName()), + adaptor().getCallerMethodName(level, "invoke"), + null, localized); + return null; + }; + test("msg", level, logger, test, check); + } + + public void testLevel(Levels level, java.lang.System.Logger logger, + String msg, Object... params) { + Runnable test = () -> level.level(logger, msg, (Object[])params); + Checker check = (res, l) -> { + checkRecord(level, res, logger.getName(), l, msg, + adaptor().getCallerClassName(level, Levels.class.getName()), + adaptor().getCallerMethodName(level, "invoke"), + null, localized, (Object[])params); + return null; + }; + test("msg, params", level, logger, test, check); + } + + public void testLevel(Levels level, java.lang.System.Logger logger, + String msg, Throwable thrown) { + Runnable test = () -> level.level(logger, msg, thrown); + Checker check = (res, l) -> { + checkRecord(level, res, logger.getName(), l, msg, + adaptor().getCallerClassName(level, Levels.class.getName()), + adaptor().getCallerMethodName(level, "invoke"), + thrown, localized); + return null; + }; + test("msg, thrown", level, logger, test, check); + } + + public void testLevel(Levels level, java.lang.System.Logger logger, + Supplier msg) { + Runnable test = () -> level.level(logger, msg); + Checker check = (res, l) -> { + checkRecord(level, res, logger.getName(), l, msg, + adaptor().getCallerClassName(level, Levels.class.getName()), + adaptor().getCallerMethodName(level, "invoke"), + null, null); + return null; + }; + test("msgSupplier", level, logger, test, check); + } + + public void testLevel(Levels level, java.lang.System.Logger logger, + Supplier msg, Throwable thrown) { + Runnable test = () -> level.level(logger, msg, thrown); + Checker check = (res, l) -> { + checkRecord(level, res, logger.getName(), l, msg, + adaptor().getCallerClassName(level, Levels.class.getName()), + adaptor().getCallerMethodName(level, "invoke"), + thrown, null); + return null; + }; + test("throw, msgSupplier", level, logger, test, check); + } + + public void testLevel(Levels level, java.lang.System.Logger logger, + String msg, ResourceBundle bundle) { + Runnable test = () -> level.level(logger, msg, bundle); + Checker check = (res, l) -> { + checkRecord(level, res, logger.getName(), l, msg, + adaptor().getCallerClassName(level, Levels.class.getName()), + adaptor().getCallerMethodName(level, "invoke"), + null, bundle); + return null; + }; + test("bundle, msg", level, logger, test, check); + } + + public void testLevel(Levels level, java.lang.System.Logger logger, + String msg, ResourceBundle bundle, Object... params) { + Runnable test = () -> level.level(logger, msg, bundle, (Object[])params); + Checker check = (res, l) -> { + checkRecord(level, res, logger.getName(), l, msg, + adaptor().getCallerClassName(level, Levels.class.getName()), + adaptor().getCallerMethodName(level, "invoke"), + null, bundle, (Object[])params); + return null; + }; + test("bundle, msg, params", level, logger, test, check); + } + + public void testLevel(Levels level, java.lang.System.Logger logger, + String msg, ResourceBundle bundle, Throwable thrown) { + Runnable test = () -> level.level(logger, msg, bundle, thrown); + Checker check = (res, l) -> { + checkRecord(level, res, logger.getName(), l, msg, + adaptor().getCallerClassName(level, Levels.class.getName()), + adaptor().getCallerMethodName(level, "invoke"), + thrown, bundle); + return null; + }; + test("bundle, msg, throwable", level, logger, test, check); + } + + // System.Logger + public void testSpiLog(java.lang.System.Logger logger, String msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + SpiLogMethodInvoker.LOG_STRING_PARAMS, + SpiLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + SpiLogMethodInvoker.LOG_STRING_PARAMS, + "logX"), null, localized); + return null; + }; + SpiLogTester tester = (x, level) -> { + SpiLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, (Object[])null); + return null; + }; + Function nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\")"; + testSpiLog(logger, tester, check, nameProducer); + } + + public void testSpiLog(java.lang.System.Logger logger, + ResourceBundle bundle, String msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + SpiLogMethodInvoker.LOGRB_STRING_PARAMS, + SpiLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + SpiLogMethodInvoker.LOGRB_STRING_PARAMS, + "logX"), null, bundle); + return null; + }; + SpiLogTester tester = (x, level) -> { + SpiLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, (Object[])null); + return null; + }; + Function nameProducer = (l) -> "log(Level." + l + + ", bundle, \"" + msg + "\")"; + testSpiLog(logger, tester, check, nameProducer); + } + + public void testSpiLog(java.lang.System.Logger logger, String msg, Object... params) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + SpiLogMethodInvoker.LOG_STRING_PARAMS, + SpiLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + SpiLogMethodInvoker.LOG_STRING_PARAMS, + "logX"), null, localized, params); + return null; + }; + SpiLogTester tester = (x, level) -> { + SpiLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, params); + return null; + }; + Function nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\", params...)"; + testSpiLog(logger, tester, check, nameProducer); + } + + public void testSpiLog(java.lang.System.Logger logger, + ResourceBundle bundle, String msg, Object... params) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + SpiLogMethodInvoker.LOGRB_STRING_PARAMS, + SpiLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + SpiLogMethodInvoker.LOGRB_STRING_PARAMS, + "logX"), null, bundle, params); + return null; + }; + SpiLogTester tester = (x, level) -> { + SpiLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, params); + return null; + }; + Function nameProducer = (l) -> "log(Level." + l + + ", bundle, \"" + msg + "\", params...)"; + testSpiLog(logger, tester, check, nameProducer); + } + + public void testSpiLog(java.lang.System.Logger logger, String msg, Throwable thrown) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + SpiLogMethodInvoker.LOG_STRING_THROWN, + SpiLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + SpiLogMethodInvoker.LOG_STRING_THROWN, + "logX"), thrown, localized); + return null; + }; + SpiLogTester tester = (x, level) -> { + SpiLogMethodInvoker.LOG_STRING_THROWN.logX(x, level, msg, thrown); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", \"" + msg + "\", thrown)"; + testSpiLog(logger, tester, check, nameProducer); + } + + public void testSpiLog(java.lang.System.Logger logger, + ResourceBundle bundle, String msg, Throwable thrown) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + SpiLogMethodInvoker.LOGRB_STRING_THROWN, + SpiLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + SpiLogMethodInvoker.LOGRB_STRING_THROWN, + "logX"), thrown, bundle); + return null; + }; + SpiLogTester tester = (x, level) -> { + SpiLogMethodInvoker.LOGRB_STRING_THROWN.logX(x, level, bundle, msg, thrown); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", bundle, \"" + msg + "\", thrown)"; + testSpiLog(logger, tester, check, nameProducer); + } + + public void testSpiLog(java.lang.System.Logger logger, Supplier msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, msg, + adaptor().getCallerClassName( + SpiLogMethodInvoker.LOG_SUPPLIER, + SpiLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + SpiLogMethodInvoker.LOG_SUPPLIER, + "logX"), null, null); + return null; + }; + SpiLogTester tester = (x, level) -> { + SpiLogMethodInvoker.LOG_SUPPLIER.logX(x, level, msg); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", () -> \"" + msg.get() + "\")"; + testSpiLog(logger, tester, check, nameProducer); + } + + public void testSpiLog(java.lang.System.Logger logger, Object obj) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> obj.toString(), + adaptor().getCallerClassName( + SpiLogMethodInvoker.LOG_OBJECT, + SpiLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + SpiLogMethodInvoker.LOG_OBJECT, + "logX"), null, null); + return null; + }; + SpiLogTester tester = (x, level) -> { + SpiLogMethodInvoker.LOG_OBJECT.logX(x, level, obj); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", new "+obj.getClass().getSimpleName()+"(\"" + + obj.toString() + "\"))"; + testSpiLog(logger, tester, check, nameProducer); + } + + public void testSpiLog(java.lang.System.Logger logger, Throwable thrown, Supplier msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, msg, + adaptor().getCallerClassName( + SpiLogMethodInvoker.LOG_SUPPLIER_THROWN, + SpiLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + SpiLogMethodInvoker.LOG_SUPPLIER_THROWN, + "logX"), thrown, null); + return null; + }; + SpiLogTester tester = (x, level) -> { + SpiLogMethodInvoker.LOG_SUPPLIER_THROWN.logX(x, level, msg, thrown); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", () -> \"" + msg.get() + "\", thrown)"; + testSpiLog(logger, tester, check, nameProducer); + } + + + // JDK + + public void testLog(java.lang.System.Logger logger, String msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOG_STRING_PARAMS, + JdkLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + JdkLogMethodInvoker.LOG_STRING_PARAMS, + "logX"), null, localized); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, (Object[])null); + return null; + }; + Function nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\")"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLogrb(java.lang.System.Logger logger, + ResourceBundle bundle, String msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGRB_STRING_PARAMS, + JdkLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + JdkLogMethodInvoker.LOGRB_STRING_PARAMS, + "logX"), null, bundle); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, (Object[])null); + return null; + }; + Function nameProducer = (l) -> "logrb(Level." + l + + ", bundle, \"" + msg + "\")"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLog(java.lang.System.Logger logger, String msg, Object... params) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOG_STRING_PARAMS, + JdkLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + JdkLogMethodInvoker.LOG_STRING_PARAMS, + "logX"), null, localized, params); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOG_STRING_PARAMS.logX(x, level, msg, params); + return null; + }; + Function nameProducer = (l) -> "log(Level." + l + ", \"" + msg + "\", params...)"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLogrb(java.lang.System.Logger logger, + ResourceBundle bundle, String msg, Object... params) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGRB_STRING_PARAMS, + JdkLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + JdkLogMethodInvoker.LOGRB_STRING_PARAMS, + "logX"), null, bundle, params); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGRB_STRING_PARAMS.logX(x, level, bundle, msg, params); + return null; + }; + Function nameProducer = (l) -> "log(Level." + l + + ", bundle, \"" + msg + "\", params...)"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLog(java.lang.System.Logger logger, String msg, Throwable thrown) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOG_STRING_THROWN, + JdkLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + JdkLogMethodInvoker.LOG_STRING_THROWN, + "logX"), thrown, localized); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOG_STRING_THROWN.logX(x, level, msg, thrown); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", \"" + msg + "\", thrown)"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLogrb(java.lang.System.Logger logger, + ResourceBundle bundle, String msg, Throwable thrown) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGRB_STRING_THROWN, + JdkLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + JdkLogMethodInvoker.LOGRB_STRING_THROWN, + "logX"), thrown, bundle); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGRB_STRING_THROWN.logX(x, level, bundle, msg, thrown); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", bundle, \"" + msg + "\", thrown)"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLog(java.lang.System.Logger logger, Supplier msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOG_SUPPLIER, + JdkLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + JdkLogMethodInvoker.LOG_SUPPLIER, + "logX"), null, null); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOG_SUPPLIER.logX(x, level, msg); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", () -> \"" + msg.get() + "\")"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLog(java.lang.System.Logger logger, Throwable thrown, Supplier msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOG_SUPPLIER_THROWN, + JdkLogMethodInvoker.class.getName()), + adaptor().getCallerMethodName( + JdkLogMethodInvoker.LOG_SUPPLIER_THROWN, + "logX"), thrown, null); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOG_SUPPLIER_THROWN.logX(x, level, thrown, msg); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", () -> \"" + msg.get() + "\", thrown)"; + testJdkLog(logger, tester, check, nameProducer); + } + + static Supplier logpMessage(ResourceBundle bundle, + String className, String methodName, Supplier msg) { + if (BEST_EFFORT_FOR_LOGP && bundle == null + && (className != null || methodName != null)) { + final String cName = className == null ? "" : className; + final String mName = methodName == null ? "" : methodName; + return () -> { + String m = msg.get(); + return String.format("[%s %s] %s", cName, mName, m == null ? "" : m); + }; + } else { + return msg; + } + } + + public void testLogp(java.lang.System.Logger logger, String className, + String methodName, String msg) { + Checker check = (res, l) -> { + checkRecord("logp", res, logger.getName(), l, + logpMessage(localized, className, methodName, () -> msg), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_STRING, className), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_STRING, methodName), + null, localized); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGP_STRING.logX(x, level, + className, methodName, msg); + return null; + }; + Function nameProducer = (l) -> + "logp(Level." + l + ", class, method, \"" + msg + "\")"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLogrb(java.lang.System.Logger logger, String className, + String methodName, ResourceBundle bundle, String msg) { + Checker check = (res, l) -> { + checkRecord("logp", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, className), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, methodName), + null, bundle); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGRBP_STRING_PARAMS.logX(x, level, + className, methodName, bundle, msg, (Object[])null); + return null; + }; + Function nameProducer = (l) -> + "logp(Level." + l + ", class, method, bundle, \"" + msg + "\")"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLogp(java.lang.System.Logger logger, String className, + String methodName, String msg, Object... params) { + Checker check = (res, l) -> { + checkRecord("logp", res, logger.getName(), l, + logpMessage(localized, className, methodName, () -> msg), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_STRING_PARAMS, className), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_STRING_PARAMS, methodName), + null, localized, params); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGP_STRING_PARAMS.logX(x, level, + className, methodName, msg, params); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", class, method, \"" + msg + "\", params...)"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLogrb(java.lang.System.Logger logger, String className, + String methodName, ResourceBundle bundle, String msg, + Object... params) { + Checker check = (res, l) -> { + checkRecord("logp", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, className), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGRBP_STRING_PARAMS, methodName), + null, bundle, params); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGRBP_STRING_PARAMS.logX(x, level, + className, methodName, bundle, msg, params); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", class, method, bundle, \"" + + msg + "\", params...)"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLogp(java.lang.System.Logger logger, String className, + String methodName, String msg, Throwable thrown) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, + logpMessage(localized, className, methodName, () -> msg), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_STRING_THROWN, className), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_STRING_THROWN, methodName), + thrown, localized); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGP_STRING_THROWN.logX(x, level, + className, methodName, msg, thrown); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", class, method, \"" + msg + "\", thrown)"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLogrb(java.lang.System.Logger logger, String className, + String methodName, ResourceBundle bundle, + String msg, Throwable thrown) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, () -> msg, + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGRBP_STRING_THROWN, className), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGRBP_STRING_THROWN, methodName), + thrown, bundle); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGRBP_STRING_THROWN.logX(x, level, + className, methodName, bundle, msg, thrown); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", class, method, bundle, \"" + msg + "\", thrown)"; + testJdkLog(logger, tester, check, nameProducer); + + } + + public void testLogp(java.lang.System.Logger logger, String className, + String methodName, Supplier msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, + logpMessage(null, className, methodName, msg), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_SUPPLIER, className), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_SUPPLIER, methodName), + null, null); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGP_SUPPLIER.logX(x, level, + className, methodName, msg); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", class, method, () -> \"" + msg.get() + "\")"; + testJdkLog(logger, tester, check, nameProducer); + } + + public void testLogp(java.lang.System.Logger logger, String className, + String methodName, Throwable thrown, Supplier msg) { + Checker check = (res, l) -> { + checkRecord("log", res, logger.getName(), l, + logpMessage(null, className, methodName, msg), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_SUPPLIER_THROWN, className), + adaptor().getCallerClassName( + JdkLogMethodInvoker.LOGP_SUPPLIER_THROWN, methodName), + thrown, null); + return null; + }; + JdkLogTester tester = (x, level) -> { + JdkLogMethodInvoker.LOGP_SUPPLIER_THROWN.logX(x, level, + className, methodName, thrown, msg); + return null; + }; + Function nameProducer = (l) -> + "log(Level." + l + ", class, method, () -> \"" + msg.get() + "\", thrown)"; + testJdkLog(logger, tester, check, nameProducer); + } + + private void testJdkLog(java.lang.System.Logger logger, + JdkLogTester log, Checker check, + Function nameProducer) { + if (restrictedTo != null) { + if (!bridgeLoggerClass.isAssignableFrom(restrictedTo)) { + if (VERBOSE) { + System.out.println("Skipping method from " + + bridgeLoggerClass); + } + return; + } + } + System.out.println("Testing Logger." + nameProducer.apply("*") + + " on " + logger); + final BackendAdaptor adaptor = adaptor(); + for (Level loggerLevel : LEVELS) { + adaptor.setLevel(logger, loggerLevel); + for (Level l : LEVELS) { + check(logger, () -> log.apply(bridgeLoggerClass.cast(logger), l), + check, () -> adaptor.isLoggable(logger, l), + () -> adaptor.shouldBeLoggable(l, loggerLevel), + l, loggerLevel, nameProducer.apply(l.toString())); + } + } + } + + private void testSpiLog(java.lang.System.Logger logger, + SpiLogTester log, Checker check, + Function nameProducer) { + System.out.println("Testing System.Logger." + nameProducer.apply("*") + + " on " + logger); + final BackendAdaptor adaptor = adaptor(); + for (java.lang.System.Logger.Level loggerLevel : java.lang.System.Logger.Level.values()) { + + adaptor.setLevel(logger, loggerLevel); + for (java.lang.System.Logger.Level l : java.lang.System.Logger.Level.values()) { + check(logger, () -> log.apply(logger, l), + check, () -> logger.isLoggable(l), + () -> adaptor.shouldBeLoggable(l, loggerLevel), + l, loggerLevel, nameProducer.apply(l.toString())); + } + } + } + + private void test(String args, Levels level, java.lang.System.Logger logger, + Runnable test, Checker check) { + if (restrictedTo != null) { + if (!level.definingClass.isAssignableFrom(restrictedTo)) { + if (VERBOSE) { + System.out.println("Skipping method from " + + level.definingClass); + } + return; + } + } + String method = args.contains("bundle") ? "logrb" : "log"; + System.out.println("Testing Logger." + + method + "(Level." + level.platformLevel + + ", "+ args + ")" + " on " + logger); + final BackendAdaptor adaptor = adaptor(); + for (Level loggerLevel : LEVELS) { + adaptor.setLevel(logger, loggerLevel); + check(logger, test, check, + () -> level.isEnabled(logger), + () -> adaptor.shouldBeLoggable(level, loggerLevel), + level.platformLevel, loggerLevel, level.method); + } + } + + private void check(java.lang.System.Logger logger, + Runnable test, Checker check, + BooleanSupplier checkLevelEnabled, + BooleanSupplier shouldBeLoggable, + L logLevel, L loggerLevel, String logMethod) { + final BackendAdaptor adaptor = adaptor(); + adaptor.resetBackendRecords(); + test.run(); + final List records = adaptor.getBackendRecords(); + if (shouldBeLoggable.getAsBoolean()) { + if (!checkLevelEnabled.getAsBoolean()) { + throw new RuntimeException("Logger is not enabled for " + + logMethod + + " although logger level is " + loggerLevel); + } + if (records.size() != 1) { + throw new RuntimeException(loggerLevel + " [" + + logLevel + "] : Unexpected record sizes: " + + records.toString()); + } + BackendRecord res = records.get(0); + check.apply(res, logLevel); + } else { + if (checkLevelEnabled.getAsBoolean()) { + throw new RuntimeException("Logger is enabled for " + + logMethod + + " although logger level is " + loggerLevel); + } + if (!records.isEmpty()) { + throw new RuntimeException(loggerLevel + " [" + + logLevel + "] : Unexpected record sizes: " + + records.toString()); + } + } + } + } + + public static class JULBackendTester extends BackendTester{ + + public JULBackendTester(boolean isSystem) { + this(isSystem,null,null); + } + public JULBackendTester(boolean isSystem, ResourceBundle localized) { + this(isSystem,null,localized); + } + public JULBackendTester(boolean isSystem, + Class restrictedTo) { + this(isSystem, restrictedTo, null); + } + public JULBackendTester(boolean isSystem, + Class restrictedTo, + ResourceBundle localized) { + super(isSystem, restrictedTo, localized); + } + + Logger getBackendLogger(String name) { + if (isSystem) { + return LoggingProviderImpl.getLogManagerAccess().demandLoggerFor( + LogManager.getLogManager(), name, Thread.class); + } else { + return Logger.getLogger(name); + } + } + + class JULBackendAdaptor extends BackendAdaptor { + @Override + public String getLoggerName(LogRecord res) { + return res.getLoggerName(); + } + @Override + public Level getLevel(LogRecord res) { + return Level.valueOf(res.getLevel().getName()); + } + @Override + public String getMessage(LogRecord res) { + return res.getMessage(); + } + @Override + public String getSourceClassName(LogRecord res) { + return res.getSourceClassName(); + } + @Override + public String getSourceMethodName(LogRecord res) { + return res.getSourceMethodName(); + } + @Override + public Throwable getThrown(LogRecord res) { + return res.getThrown(); + } + @Override + public ResourceBundle getResourceBundle(LogRecord res) { + return res.getResourceBundle(); + } + @Override + public void setLevel(java.lang.System.Logger logger, Level level) { + Logger backend = getBackendLogger(logger.getName()); + backend.setLevel(java.util.logging.Level.parse(level.name())); + } + @Override + public void setLevel(java.lang.System.Logger logger, java.lang.System.Logger.Level level) { + setLevel(logger, toJUL(level)); + } + @Override + public List getBackendRecords() { + return handler.records; + } + @Override + public void resetBackendRecords() { + handler.reset(); + } + @Override + public Level getMappedLevel(Object level) { + if (level instanceof java.lang.System.Logger.Level) { + return toJUL((java.lang.System.Logger.Level)level); + } + return (Level)level; + } + } + + final JULBackendAdaptor julAdaptor = new JULBackendAdaptor(); + + @Override + BackendAdaptor adaptor() { + return julAdaptor; + } + + } + + public abstract static class BackendTesterFactory { + public abstract BackendTester createBackendTester(boolean isSystem); + public abstract BackendTester createBackendTester(boolean isSystem, + Class restrictedTo); + public abstract BackendTester createBackendTester(boolean isSystem, + Class restrictedTo, + ResourceBundle bundle); + public abstract BackendTester createBackendTester(boolean isSystem, + ResourceBundle bundle); + } + + public static class JULBackendTesterFactory extends BackendTesterFactory { + + @Override + public BackendTester createBackendTester(boolean isSystem) { + return new JULBackendTester(isSystem); + } + + @Override + public BackendTester createBackendTester(boolean isSystem, + Class restrictedTo) { + return new JULBackendTester(isSystem, restrictedTo); + } + + @Override + public BackendTester createBackendTester(boolean isSystem, + Class restrictedTo, + ResourceBundle bundle) { + return new JULBackendTester(isSystem, restrictedTo, bundle); + } + + @Override + public BackendTester createBackendTester(boolean isSystem, + ResourceBundle bundle) { + return new JULBackendTester(isSystem, bundle); + } + } + + public static class CustomLoggerFinder extends LoggerFinder { + + static enum CustomLevel { OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL }; + static CustomLevel[] customLevelMap = { CustomLevel.ALL, + CustomLevel.TRACE, CustomLevel.DEBUG, CustomLevel.INFO, + CustomLevel.WARN, CustomLevel.ERROR, CustomLevel.OFF + }; + static class CustomLogRecord { + public final CustomLevel logLevel; + public final java.lang.System.Logger logger; + public final String msg; + public final Object[] params; + public final Throwable thrown; + public final ResourceBundle bundle; + + CustomLogRecord(java.lang.System.Logger producer, + CustomLevel level, String msg) { + this(producer, level, msg, (ResourceBundle)null, (Throwable)null, (Object[])null); + } + + CustomLogRecord(java.lang.System.Logger producer, + CustomLevel level, String msg, ResourceBundle bundle, + Throwable thrown, Object... params) { + this.logger = producer; + this.logLevel = level; + this.msg = msg; + this.params = params; + this.thrown = thrown; + this.bundle = bundle; + } + } + + static final List records = + Collections.synchronizedList(new ArrayList<>()); + + static class CustomLogger implements java.lang.System.Logger { + + final String name; + volatile CustomLevel level; + CustomLogger(String name) { + this.name = name; + this.level = CustomLevel.INFO; + } + + @Override + public String getName() { + return name; + } + + public void setLevel(CustomLevel level) { + this.level = level; + } + + + @Override + public boolean isLoggable(java.lang.System.Logger.Level level) { + + return this.level != CustomLevel.OFF && this.level.ordinal() + >= customLevelMap[level.ordinal()].ordinal(); + } + + @Override + public void log(java.lang.System.Logger.Level level, ResourceBundle bundle, String key, Throwable thrown) { + if (isLoggable(level)) { + records.add(new CustomLogRecord(this, customLevelMap[level.ordinal()], + key, bundle, thrown)); + } + } + + @Override + public void log(java.lang.System.Logger.Level level, ResourceBundle bundle, String format, Object... params) { + if (isLoggable(level)) { + records.add(new CustomLogRecord(this, customLevelMap[level.ordinal()], + format, bundle, null, params)); + } + } + + } + + final Map applicationLoggers = + Collections.synchronizedMap(new HashMap<>()); + final Map systemLoggers = + Collections.synchronizedMap(new HashMap<>()); + + @Override + public java.lang.System.Logger getLogger(String name, Class caller) { + ClassLoader callerLoader = caller.getClassLoader(); + if (callerLoader == null) { + systemLoggers.putIfAbsent(name, new CustomLogger(name)); + return systemLoggers.get(name); + } else { + applicationLoggers.putIfAbsent(name, new CustomLogger(name)); + return applicationLoggers.get(name); + } + } + + CustomLevel fromJul(Level level) { + if (level.intValue() == Level.OFF.intValue()) { + return CustomLevel.OFF; + } else if (level.intValue() > Level.SEVERE.intValue()) { + return CustomLevel.ERROR; + } else if (level.intValue() > Level.WARNING.intValue()) { + return CustomLevel.ERROR; + } else if (level.intValue() > Level.INFO.intValue()) { + return CustomLevel.WARN; + } else if (level.intValue() > Level.CONFIG.intValue()) { + return CustomLevel.INFO; + } else if (level.intValue() > Level.FINER.intValue()) { + return CustomLevel.DEBUG; + } else if (level.intValue() > Level.FINEST.intValue()) { + return CustomLevel.TRACE; + } else if (level.intValue() == Level.ALL.intValue()) { + return CustomLevel.ALL; + } else { + return CustomLevel.TRACE; + } + } + + Level toJul(CustomLevel level) { + switch(level) { + case OFF: return Level.OFF; + case FATAL: return Level.SEVERE; + case ERROR: return Level.SEVERE; + case WARN: return Level.WARNING; + case INFO: return Level.INFO; + case DEBUG: return Level.FINE; + case TRACE: return Level.FINER; + case ALL: return Level.ALL; + default: throw new InternalError("No such level: "+level); + } + } + + } + + public static class CustomBackendTester extends + BackendTester { + + public final CustomLoggerFinder provider; + + public CustomBackendTester(boolean isSystem) { + this(isSystem, null, null); + } + + public CustomBackendTester(boolean isSystem, + Class restrictedTo) { + this(isSystem, restrictedTo, null); + } + + public CustomBackendTester(boolean isSystem, + ResourceBundle localized) { + this(isSystem, null, localized); + } + + public CustomBackendTester(boolean isSystem, + Class restrictedTo, + ResourceBundle localized) { + super(isSystem, restrictedTo, localized); + provider = (CustomLoggerFinder)java.lang.System.LoggerFinder.getLoggerFinder(); + } + + @Override + public java.lang.System.Logger convert(java.lang.System.Logger logger) { + if (restrictedTo != null && restrictedTo.isInstance(logger)) { + return logger; + } else if (restrictedTo == jdkLoggerClass) { + return logger; + } else { + return java.lang.System.Logger.class.cast( + sun.util.logging.PlatformLogger.Bridge.convert(logger)); + } + } + + class CustomBackendAdaptor extends BackendAdaptor { + + @Override + public String getLoggerName(CustomLoggerFinder.CustomLogRecord res) { + return res.logger.getName(); + } + + @Override + public CustomLoggerFinder.CustomLevel getLevel(CustomLoggerFinder.CustomLogRecord res) { + return res.logLevel; + } + + @Override + public String getMessage(CustomLoggerFinder.CustomLogRecord res) { + return res.msg; + } + + @Override // we don't support source class name in our custom provider implementation + public String getSourceClassName(CustomLoggerFinder.CustomLogRecord res) { + return null; + } + + @Override // we don't support source method name in our custom provider implementation + public String getSourceMethodName(CustomLoggerFinder.CustomLogRecord res) { + return null; + } + + @Override + public Throwable getThrown(CustomLoggerFinder.CustomLogRecord res) { + return res.thrown; + } + + @Override + public ResourceBundle getResourceBundle(CustomLoggerFinder.CustomLogRecord res) { + return res.bundle; + } + + @Override + public void setLevel(java.lang.System.Logger logger, Level level) { + final CustomLoggerFinder.CustomLogger l = + (CustomLoggerFinder.CustomLogger) + (isSystem ? provider.getLogger(logger.getName(), Thread.class) : + provider.getLogger(logger.getName(), LoggerFinderBackendTest.class)); + l.setLevel(provider.fromJul(level)); + } + @Override + public void setLevel(java.lang.System.Logger logger, + java.lang.System.Logger.Level level) { + setLevel(logger, toJUL(level)); + } + + CustomLoggerFinder.CustomLevel getLevel(java.lang.System.Logger logger) { + final CustomLoggerFinder.CustomLogger l = + (CustomLoggerFinder.CustomLogger) + (isSystem ? provider.getLogger(logger.getName(), Thread.class) : + provider.getLogger(logger.getName(), LoggerFinderBackendTest.class)); + return l.level; + } + + @Override + public List getBackendRecords() { + return CustomLoggerFinder.records; + } + + @Override + public void resetBackendRecords() { + CustomLoggerFinder.records.clear(); + } + + @Override + public boolean shouldBeLoggable(Levels level, Level loggerLevel) { + return loggerLevel != Level.OFF && + fromLevels(level).ordinal() <= provider.fromJul(loggerLevel).ordinal(); + } + + @Override + public boolean isLoggable(java.lang.System.Logger logger, Level l) { + return super.isLoggable(logger, l); + } + + @Override + public boolean shouldBeLoggable(Level logLevel, Level loggerLevel) { + return loggerLevel != Level.OFF && + provider.fromJul(logLevel).ordinal() <= provider.fromJul(loggerLevel).ordinal(); + } + + @Override // we don't support source class name in our custom provider implementation + public String getCallerClassName(Levels level, String clazz) { + return null; + } + + @Override // we don't support source method name in our custom provider implementation + public String getCallerMethodName(Levels level, String method) { + return null; + } + + @Override // we don't support source class name in our custom provider implementation + public String getCallerClassName(MethodInvoker logMethod, String clazz) { + return null; + } + + @Override // we don't support source method name in our custom provider implementation + public String getCallerMethodName(MethodInvoker logMethod, String method) { + return null; + } + + @Override + public CustomLoggerFinder.CustomLevel getMappedLevel(Object level) { + if (level instanceof java.lang.System.Logger.Level) { + final int index = ((java.lang.System.Logger.Level)level).ordinal(); + return CustomLoggerFinder.customLevelMap[index]; + } else if (level instanceof Level) { + return provider.fromJul((Level)level); + } + return (CustomLoggerFinder.CustomLevel) level; + } + + CustomLoggerFinder.CustomLevel fromLevels(Levels level) { + switch(level) { + case SEVERE: + return CustomLoggerFinder.CustomLevel.ERROR; + case WARNING: + return CustomLoggerFinder.CustomLevel.WARN; + case INFO: + return CustomLoggerFinder.CustomLevel.INFO; + case CONFIG: case FINE: + return CustomLoggerFinder.CustomLevel.DEBUG; + case FINER: case FINEST: + return CustomLoggerFinder.CustomLevel.TRACE; + } + throw new InternalError("No such level "+level); + } + + } + + @Override + BackendAdaptor adaptor() { + return new CustomBackendAdaptor(); + } + + } + + public static class CustomBackendTesterFactory extends BackendTesterFactory { + + @Override + public BackendTester createBackendTester(boolean isSystem) { + return new CustomBackendTester(isSystem); + } + + @Override + public BackendTester createBackendTester(boolean isSystem, + Class restrictedTo) { + return new CustomBackendTester(isSystem, restrictedTo); + } + + @Override + public BackendTester createBackendTester(boolean isSystem, + Class restrictedTo, + ResourceBundle bundle) { + return new CustomBackendTester(isSystem, restrictedTo, bundle); + } + + @Override + public BackendTester createBackendTester(boolean isSystem, + ResourceBundle bundle) { + return new CustomBackendTester(isSystem, bundle); + } + } + + static final Method getLazyLogger; + static final Method accessLoggerFinder; + static { + // jdk.internal.logger.LazyLoggers.getLazyLogger(name, caller); + try { + Class lazyLoggers = jdk.internal.logger.LazyLoggers.class; + getLazyLogger = lazyLoggers.getMethod("getLazyLogger", + String.class, Class.class); + getLazyLogger.setAccessible(true); + Class loggerFinderLoader = + Class.forName("java.lang.System$LoggerFinder"); + accessLoggerFinder = loggerFinderLoader.getDeclaredMethod("accessProvider"); + accessLoggerFinder.setAccessible(true); + } catch (Throwable ex) { + throw new ExceptionInInitializerError(ex); + } + } + + static java.lang.System.Logger getSystemLogger(String name, Class caller) throws Exception { + try { + return java.lang.System.Logger.class.cast(getLazyLogger.invoke(null, name, caller)); + } catch (InvocationTargetException x) { + Throwable t = x.getTargetException(); + if (t instanceof Exception) { + throw (Exception)t; + } else { + throw (Error)t; + } + } + } + static java.lang.System.Logger getSystemLogger(String name, + ResourceBundle bundle, Class caller) throws Exception { + try { + LoggerFinder provider = LoggerFinder.class.cast(accessLoggerFinder.invoke(null)); + return provider.getLocalizedLogger(name, bundle, caller); + } catch (InvocationTargetException x) { + Throwable t = x.getTargetException(); + if (t instanceof Exception) { + throw (Exception)t; + } else { + throw (Error)t; + } + } + } + + // Change this to 'true' to get more traces... + public static boolean verbose = false; + + public static void main(String[] argv) throws Exception { + + final AtomicInteger nb = new AtomicInteger(0); + final boolean hidesProvider = Boolean.getBoolean("test.logger.hidesProvider"); + System.out.println(ClassLoader.getSystemClassLoader()); + final BackendTesterFactory factory; + if (java.lang.System.LoggerFinder.getLoggerFinder() instanceof CustomLoggerFinder) { + if (hidesProvider) { + System.err.println("Custom backend " + + java.lang.System.LoggerFinder.getLoggerFinder() + + " should have been hidden!"); + throw new RuntimeException( + "Custom backend should have been hidden: " + + "check value of java.system.class.loader property"); + } + System.out.println("Using custom backend"); + factory = new CustomBackendTesterFactory(); + } else { + if (!hidesProvider) { + System.err.println("Default JUL backend " + + java.lang.System.LoggerFinder.getLoggerFinder() + + " should have been hidden!"); + throw new RuntimeException( + "Default JUL backend should have been hidden: " + + "check value of java.system.class.loader property"); + } + System.out.println("Using JUL backend"); + factory = new JULBackendTesterFactory(); + } + + testBackend(nb, factory); + } + + public static void testBackend(AtomicInteger nb, BackendTesterFactory factory) throws Exception { + + // Tests all level specifics methods with loggers configured with + // all possible levels and loggers obtained with all possible + // entry points from LoggerFactory and JdkLoggerFactory, with + // JUL as backend. + + // Test a simple application logger with JUL backend + final BackendTester tester = factory.createBackendTester(false); + final java.lang.System.Logger logger = + java.lang.System.LoggerFinder.getLoggerFinder() + .getLogger("foo", LoggerFinderBackendTest.class); + + testLogger(tester, logger, nb); + + // Test a simple system logger with JUL backend + final java.lang.System.Logger system = + java.lang.System.LoggerFinder.getLoggerFinder() + .getLogger("bar", Thread.class); + final BackendTester systemTester = factory.createBackendTester(true); + testLogger(systemTester, system, nb); + + // Test a localized application logger with null resource bundle and + // JUL backend + final java.lang.System.Logger noBundleLogger = + java.lang.System.LoggerFinder.getLoggerFinder() + .getLocalizedLogger("baz", null, LoggerFinderBackendTest.class); + final BackendTester noBundleTester = + factory.createBackendTester(false, spiLoggerClass); + testLogger(noBundleTester, noBundleLogger, nb); + + // Test a localized system logger with null resource bundle and JUL + // backend + final java.lang.System.Logger noBundleSysLogger = + java.lang.System.LoggerFinder.getLoggerFinder() + .getLocalizedLogger("oof", null, Thread.class); + final BackendTester noBundleSysTester = + factory.createBackendTester(true, spiLoggerClass); + testLogger(noBundleSysTester, noBundleSysLogger, nb); + + // Test a localized application logger with null resource bundle and + // JUL backend + try { + System.getLogger("baz", null); + throw new RuntimeException("Expected NullPointerException not thrown"); + } catch (NullPointerException x) { + System.out.println("System.Loggers.getLogger(\"baz\", null): got expected " + x); + } + final java.lang.System.Logger noBundleExtensionLogger = + getSystemLogger("baz", null, LoggerFinderBackendTest.class); + final BackendTester noBundleExtensionTester = + factory.createBackendTester(false, jdkLoggerClass); + testLogger(noBundleExtensionTester, noBundleExtensionLogger, nb); + + // Test a simple system logger with JUL backend + final java.lang.System.Logger sysExtensionLogger = + getSystemLogger("oof", Thread.class); + final BackendTester sysExtensionTester = + factory.createBackendTester(true, jdkLoggerClass); + testLogger(sysExtensionTester, sysExtensionLogger, nb); + + // Test a localized system logger with null resource bundle and JUL + // backend + final java.lang.System.Logger noBundleSysExtensionLogger = + getSystemLogger("oof", null, Thread.class); + final BackendTester noBundleSysExtensionTester = + factory.createBackendTester(true, jdkLoggerClass); + testLogger(noBundleSysExtensionTester, noBundleSysExtensionLogger, nb); + + // Test a localized application logger converted to JDK with null + // resource bundle and JUL backend + final java.lang.System.Logger noBundleConvertedLogger = + (java.lang.System.Logger) + sun.util.logging.PlatformLogger.Bridge.convert(noBundleLogger); + final BackendTester noBundleJdkTester = factory.createBackendTester(false); + testLogger(noBundleJdkTester, noBundleConvertedLogger, nb); + + // Test a localized system logger converted to JDK with null resource + // bundle and JUL backend + final java.lang.System.Logger noBundleConvertedSysLogger = + (java.lang.System.Logger) + sun.util.logging.PlatformLogger.Bridge.convert(noBundleSysLogger); + final BackendTester noBundleJdkSysTester = factory.createBackendTester(true); + testLogger(noBundleJdkSysTester, noBundleConvertedSysLogger, nb); + + // Test a localized application logger with resource bundle and JUL + // backend + final ResourceBundle bundle = + ResourceBundle.getBundle(ResourceBundeLocalized.class.getName()); + final java.lang.System.Logger bundleLogger = + java.lang.System.LoggerFinder.getLoggerFinder() + .getLocalizedLogger("toto", bundle, LoggerFinderBackendTest.class); + final BackendTester bundleTester = + factory.createBackendTester(false, spiLoggerClass, bundle); + testLogger(bundleTester, bundleLogger, nb); + + // Test a localized system logger with resource bundle and JUL backend + final java.lang.System.Logger bundleSysLogger = + java.lang.System.LoggerFinder.getLoggerFinder() + .getLocalizedLogger("titi", bundle, Thread.class); + final BackendTester bundleSysTester = + factory.createBackendTester(true, spiLoggerClass, bundle); + testLogger(bundleSysTester, bundleSysLogger, nb); + + // Test a localized Jdk application logger with resource bundle and JUL + // backend + final java.lang.System.Logger bundleExtensionLogger = + System.getLogger("tita", bundle); + final BackendTester bundleExtensionTester = + factory.createBackendTester(false, jdkLoggerClass, bundle); + testLogger(bundleExtensionTester, bundleExtensionLogger, nb); + + // Test a localized Jdk system logger with resource bundle and JUL + // backend + final java.lang.System.Logger bundleExtensionSysLogger = + getSystemLogger("titu", bundle, Thread.class); + final BackendTester bundleExtensionSysTester = + factory.createBackendTester(true, jdkLoggerClass, bundle); + testLogger(bundleExtensionSysTester, bundleExtensionSysLogger, nb); + + // Test a localized application logger converted to JDK with resource + // bundle and JUL backend + final BackendTester bundleJdkTester = + factory.createBackendTester(false, bundle); + final java.lang.System.Logger bundleConvertedLogger = + (java.lang.System.Logger) + sun.util.logging.PlatformLogger.Bridge.convert(bundleLogger); + testLogger(bundleJdkTester, bundleConvertedLogger, nb); + + // Test a localized Jdk system logger converted to JDK with resource + // bundle and JUL backend + final BackendTester bundleJdkSysTester = + factory.createBackendTester(true, bundle); + final java.lang.System.Logger bundleConvertedSysLogger = + (java.lang.System.Logger) + sun.util.logging.PlatformLogger.Bridge.convert(bundleSysLogger); + testLogger(bundleJdkSysTester, bundleConvertedSysLogger, nb); + + // Now need to add tests for all the log/logp/logrb methods... + + } + + private static class FooObj { + final String s; + FooObj(String s) { + this.s = s; + } + + @Override + public String toString() { + return super.toString() +": "+s; + } + + } + + public static void testLogger(BackendTester tester, + java.lang.System.Logger spiLogger, AtomicInteger nb) { + + // Test all level-specific method forms: + // fatal(...) error(...) severe(...) etc... + java.lang.System.Logger jdkLogger = tester.convert(spiLogger); + for (Levels l : Levels.values()) { + java.lang.System.Logger logger = + l.definingClass.equals(spiLoggerClass) ? spiLogger : jdkLogger; + tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-" + + nb.incrementAndGet()); + tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-" + + nb.incrementAndGet(), + bundleParam); + final int nbb = nb.incrementAndGet(); + tester.testLevel(l, logger, () -> l.method + "[" + logger.getName() + + "]-" + nbb); + } + for (Levels l : Levels.values()) { + java.lang.System.Logger logger = + l.definingClass.equals(spiLoggerClass) ? spiLogger : jdkLogger; + tester.testLevel(l, logger, + l.method + "[" + logger.getName()+ "]({0},{1})-" + + nb.incrementAndGet(), + "One", "Two"); + tester.testLevel(l, logger, + l.method + "[" + logger.getName()+ "]({0},{1})-" + + nb.incrementAndGet(), + bundleParam, "One", "Two"); + } + final Throwable thrown = new RuntimeException("Test"); + for (Levels l : Levels.values()) { + java.lang.System.Logger logger = + l.definingClass.equals(spiLoggerClass) ? spiLogger : jdkLogger; + tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-" + + nb.incrementAndGet(), + thrown); + tester.testLevel(l, logger, l.method + "[" + logger.getName()+ "]-" + + nb.incrementAndGet(), + bundleParam, thrown); + final int nbb = nb.incrementAndGet(); + tester.testLevel(l, logger, ()->l.method + "[" + logger.getName()+ "]-" + + nbb, thrown); + } + + java.lang.System.Logger logger = jdkLogger; + + // test System.Logger methods + tester.testSpiLog(logger, "[" + logger.getName()+ "]-" + + nb.incrementAndGet()); + tester.testSpiLog(logger, bundleParam, "[" + logger.getName()+ "]-" + + nb.incrementAndGet()); + tester.testSpiLog(logger, "[" + logger.getName()+ "]-({0},{1})" + + nb.incrementAndGet(), "One", "Two"); + tester.testSpiLog(logger, bundleParam, "[" + logger.getName()+ "]-({0},{1})" + + nb.incrementAndGet(), "One", "Two"); + tester.testSpiLog(logger, "[" + logger.getName()+ "]-" + + nb.incrementAndGet(), thrown); + tester.testSpiLog(logger, bundleParam, "[" + logger.getName()+ "]-" + + nb.incrementAndGet(), thrown); + final int nbb01 = nb.incrementAndGet(); + tester.testSpiLog(logger, () -> "[" + logger.getName()+ "]-" + nbb01); + final int nbb02 = nb.incrementAndGet(); + tester.testSpiLog(logger, thrown, () -> "[" + logger.getName()+ "]-" + nbb02); + final int nbb03 = nb.incrementAndGet(); + tester.testSpiLog(logger, new FooObj("[" + logger.getName()+ "]-" + nbb03)); + + // Test all log method forms: + // jdk.internal.logging.Logger.log(...) + tester.testLog(logger, "[" + logger.getName()+ "]-" + + nb.incrementAndGet()); + tester.testLogrb(logger, bundleParam, "[" + logger.getName()+ "]-" + + nb.incrementAndGet()); + tester.testLog(logger, "[" + logger.getName()+ "]-({0},{1})" + + nb.incrementAndGet(), "One", "Two"); + tester.testLogrb(logger, bundleParam, "[" + logger.getName()+ "]-({0},{1})" + + nb.incrementAndGet(), "One", "Two"); + tester.testLog(logger, "[" + logger.getName()+ "]-" + + nb.incrementAndGet(), thrown); + tester.testLogrb(logger, bundleParam, "[" + logger.getName()+ "]-" + + nb.incrementAndGet(), thrown); + final int nbb1 = nb.incrementAndGet(); + tester.testLog(logger, () -> "[" + logger.getName()+ "]-" + nbb1); + final int nbb2 = nb.incrementAndGet(); + tester.testLog(logger, thrown, () -> "[" + logger.getName()+ "]-" + nbb2); + + // Test all logp method forms + // jdk.internal.logging.Logger.logp(...) + tester.testLogp(logger, "clazz" + nb.incrementAndGet(), + "method" + nb.incrementAndGet(), + "[" + logger.getName()+ "]-" + + nb.incrementAndGet()); + tester.testLogrb(logger, "clazz" + nb.incrementAndGet(), + "method" + nb.incrementAndGet(), bundleParam, + "[" + logger.getName()+ "]-" + + nb.incrementAndGet()); + tester.testLogp(logger, "clazz" + nb.incrementAndGet(), + "method" + nb.incrementAndGet(), + "[" + logger.getName()+ "]-({0},{1})" + + nb.incrementAndGet(), "One", "Two"); + tester.testLogrb(logger, "clazz" + nb.incrementAndGet(), + "method" + nb.incrementAndGet(), bundleParam, + "[" + logger.getName()+ "]-({0},{1})" + + nb.incrementAndGet(), "One", "Two"); + tester.testLogp(logger, "clazz" + nb.incrementAndGet(), + "method" + nb.incrementAndGet(), + "[" + logger.getName()+ "]-" + + nb.incrementAndGet(), thrown); + tester.testLogrb(logger, "clazz" + nb.incrementAndGet(), + "method" + nb.incrementAndGet(), bundleParam, + "[" + logger.getName()+ "]-" + + nb.incrementAndGet(), thrown); + final int nbb3 = nb.incrementAndGet(); + tester.testLogp(logger, "clazz" + nb.incrementAndGet(), + "method" + nb.incrementAndGet(), + () -> "[" + logger.getName()+ "]-" + nbb3); + final int nbb4 = nb.incrementAndGet(); + tester.testLogp(logger, "clazz" + nb.incrementAndGet(), + "method" + nb.incrementAndGet(), + thrown, () -> "[" + logger.getName()+ "]-" + nbb4); + } + +}