All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.spartatech.testutils.logback.UnitTestAsserterLogback Maven / Gradle / Ivy

package com.github.spartatech.testutils.logback;

import java.util.Arrays;
import java.util.LinkedList;

import org.junit.ComparisonFailure;
import org.slf4j.LoggerFactory;

import com.github.spartatech.testutils.logback.constant.ExpectValue;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import junit.framework.AssertionFailedError;


/** 
 * 
 * Logback utility to spy logs calls
 * The way it works is:
 * - Instantiate a new {@link UnitTestAsserterLogback} giving the logger to be spied.
 * - Declare all your expectations using addExpectation
 * - call method to be tested
 * - call {@code UnitTestAsserterLogback.assertLogExpectations()}
 * 
 * @author Daniel Conde Diehl
 * 
 * History: 
 *    Dec 27, 2016 - Daniel Conde Diehl
 *  
 */
public class UnitTestAsserterLogback  {

    private LinkedList expectations = new LinkedList<>();
    private LinkedList events = new LinkedList<>();
    
    private UnitTestAsserterLogbackAppender appender;
    
    
    /**
     * Constructor receiving the logger as a String.
     * @param logger name as a String
     */
    public UnitTestAsserterLogback(String logger) {
        appender = new UnitTestAsserterLogbackAppender(logger, events);
        attachAppenderToLogback();
    }
    
    /**
     * Constructor receiving the logger as a class.
     * @param clazz Class that will be used as a logger name
     */
    public UnitTestAsserterLogback(Class clazz) {
        appender = new UnitTestAsserterLogbackAppender(clazz, events);
        attachAppenderToLogback();
    }
    
    /**
     * Adds a new expectation to the logger. 
     * 
     * @param level expected for the log entry
     * @param logMessage message expected for the log entry
     * @param params list of parameters for the log entry.
     */
    public void addExpectation(Level level, String logMessage, Object...params) {
        expectations.add(new LogEntryItem(level, logMessage, params));
    }
    
    
    
    /**
     * Replay expectations to check if all logs happened.
     * Analyzes in order and all logs supposed to be there 
     * 
     * @throws AssertionError Throws an assertion error when the asserts fail
     * @deprecated this method will be remove in future releases, please use {@code UnitTestAsserterLogback.assertLogExpectations(false)} instead
     */
    @Deprecated
    public void assertLogExpectations() throws AssertionError {
    	assertLogExpectations(false);
    }    
    
    /**
     * Replay expectations to check if all logs happened.
     * Analyzes in order and all logs supposed to be there 
     * 
     * @param ignoreExtraMessages false - if any message other than ones expected happens it fail, also check in order, 
     * 							  true - ensure that messages that were expected happens, allows extra messages and does not check 
     * @throws AssertionError Throws an assertion error when the asserts fail
     */
	public void assertLogExpectations(boolean ignoreExtraMessages) throws AssertionError {
    	if (!ignoreExtraMessages) {
            if (events.size() != expectations.size()) {
                throw new ComparisonFailure("Invalid number of messages", String.valueOf(expectations.size()), String.valueOf(events.size()));
            }
            
            for (ILoggingEvent event : events) {

                LogEntryItem entry = expectations.remove();

                if (!entry.getMessage().equals(event.getMessage())) {
                    throw new ComparisonFailure("Message mismatch", entry.getMessage(), event.getMessage());
                }
                
                compareEntries(event, entry);
            }
    	} else {
    		for (LogEntryItem entry : expectations) {
    			boolean foundMatch = false;
    			for(ILoggingEvent event : events) {
    				if (entry.getMessage().equals(event.getMessage())) {
    					try {
    						compareEntries(event, entry);
    						foundMatch = true;
    					} catch (ComparisonFailure e) {
    						//Error happened not a match
    					}
    				}
    			}
    			if (!foundMatch) {
    				throw new AssertionFailedError("Message ["+entry + "] not found");
    			}
            }
    	}
    }
    

    /**
     * Compares an expected entry with a logging event, checking if the level, and param match.
     * 
     * @param event Log event that happened
     * @param entry expected entry
     */
    private void compareEntries (ILoggingEvent event, LogEntryItem entry) {
        if (entry.getLevel() != event.getLevel()) {
            throw new ComparisonFailure("LogLevel mismatch", entry.getLevel().toString(), event.getLevel().toString());
        }
        
        int expectedSize = entry.getParams() == null ? 0 : entry.getParams().length;
        int actualSize = event.getArgumentArray() == null ? 0 : event.getArgumentArray().length;
        if (expectedSize != actualSize) {
            throw new ComparisonFailure("Incorrect number of params", 
                                        entry.getParams()== null ? "0" : String.valueOf(entry.getParams().length) , 
                                        event.getArgumentArray() == null ? "0" : String.valueOf(event.getArgumentArray().length));
        }

        for (int i = 0; i < entry.getParams().length; i++) {
            Object expectedParam = entry.getParams()[i];
            Object actualParam = event.getArgumentArray()[i];

            if (ExpectValue.ANY == expectedParam) {
                continue;
            }
            
            if (expectedParam == null && actualParam == null) {
                continue;
            } else if (expectedParam == null && actualParam != null) {
                throw new ComparisonFailure("Param [" + i + "] mismatch", "null", actualParam.toString());
            } else if (!expectedParam.equals(actualParam)) {
                throw new ComparisonFailure("Param [" + i + "] mismatch", expectedParam == null ? "NULL" : expectedParam.toString(), actualParam == null ? "NULL" : actualParam.toString());
            }
        }
    }
    
    /**
     * Attached the log to the logback. 
     */
    private void attachAppenderToLogback() {
        Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
        root.addAppender(appender);
    }
    
    /** 
     * 
     * Internal VO to carry log entries for asserting values.
     * 
     * @author Daniel Conde Diehl 
     * 
     * History: 
     *    Jan 15, 2017 - Daniel Conde Diehl
     *  
     */ 
    class LogEntryItem {
        private Level level;
        private String message;
        private Object[] params;
        
        /**
         * Constructor with all values.
         * 
         * @param level log loevel for the message
         * @param message text message
         * @param params params used in the log
         */
        public LogEntryItem(Level level, String message, Object[] params) {
            this.level = level;
            this.message = message;
            this.params = params;
        }
        
        /**
         * @return the level
         */
        public Level getLevel() {
            return level;
        }

        /**
         * @return the message
         */
        public String getMessage() {
            return message;
        }
        /**
         * @return the params
         */
        public Object[] getParams() {
            return params;
        }

		/* (non-Javadoc)
		 * @see java.lang.Object#toString()
		 */
		@Override
		public String toString() {
			StringBuilder builder = new StringBuilder();
			builder.append("[level=");
			builder.append(level);
			builder.append(", message=");
			builder.append(message);
			builder.append(", params=");
			builder.append(Arrays.toString(params));
			builder.append("]");
			return builder.toString();
		}
    }
};




© 2015 - 2025 Weber Informatics LLC | Privacy Policy