package com.codeborne.selenide.logevents; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import static com.codeborne.selenide.logevents.LogEvent.EventStatus.FAIL; /** * Logs Selenide test steps and notifies all registered LogEventListener about it */ public class SelenideLogger { protected static ThreadLocal<Map<String, LogEventListener>> listeners = new ThreadLocal<>(); /** * Add a listener (to the current thread). * @param name unique name of this listener (per thread). * Can be used later to remove listener using method {@link #removeListener(String)} * @param listener event listener */ public static void addListener(String name, LogEventListener listener) { Map<String, LogEventListener> threadListeners = listeners.get(); if (threadListeners == null) { threadListeners = new HashMap<>(); } threadListeners.put(name, listener); listeners.set(threadListeners); } public static SelenideLog beginStep(String source, String methodName, Object... args) { return beginStep(source, readableMethodName(methodName) + "(" + readableArguments(args) + ")"); } static String readableMethodName(String methodName) { return methodName.replaceAll("([A-Z])", " $1").toLowerCase(); } static String readableArguments(Object... args) { return args == null ? "" : (args[0] instanceof Object[]) ? arrayToString((Object[]) args[0]) : arrayToString(args); } private static String arrayToString(Object[] args) { return args.length == 1 ? String.valueOf(args[0]) : Arrays.toString(args); } public static SelenideLog beginStep(String source, String subject) { return new SelenideLog(source, subject); } public static void commitStep(SelenideLog log, Throwable error) { log.setError(error); commitStep(log, FAIL); } public static void commitStep(SelenideLog log, LogEvent.EventStatus status) { log.setStatus(status); Collection<LogEventListener> listeners = getEventLoggerListeners(); for (LogEventListener listener : listeners) { listener.onEvent(log); } } private static Collection<LogEventListener> getEventLoggerListeners() { if (listeners.get() == null) { listeners.set(new HashMap<String, LogEventListener>()); } return listeners.get().values(); } /** * Remove listener (from the current thread). * @param name unique name of listener added by method {@link #addListener(String, LogEventListener)} * @param <T> class of listener to be returned * @return the listener being removed */ @SuppressWarnings("unchecked") public static <T extends LogEventListener> T removeListener(String name) { Map<String, LogEventListener> listeners = SelenideLogger.listeners.get(); return listeners == null ? null : (T) listeners.remove(name); } public static void removeAllListeners() { SelenideLogger.listeners.remove(); } /** * If listener with given name is bound (added) to the current thread. * * @param name unique name of listener added by method {@link #addListener(String, LogEventListener)} * @return true iff method {@link #addListener(String, LogEventListener)} with * corresponding name has been called in current thread. */ public static boolean hasListener(String name) { Map<String, LogEventListener> listeners = SelenideLogger.listeners.get(); return listeners != null && listeners.containsKey(name); } }