Browse Source

#37 javadoc: junit

Ranides Atterwim 4 years ago
parent
commit
6b9263e920

+ 14 - 0
assira.junit/src/main/java/net/ranides/assira/junit/JCategories.java

@@ -1,13 +1,27 @@
 package net.ranides.assira.junit;
 
 /**
+ * Annotations used to mark some unit test.
+ * Useful if we want to disable some tests in maven or if we want to search for some categories.
+ *
  * @author msieron
  */
 public class JCategories {
 
+    /**
+     * This test is slow, should not be executed in ordinary build.
+     * Please note, we should not write benchmarks as slow unit tests, strategy for benchmarks should
+     */
     public static final class Slow { }
 
+    /**
+     * This test required internet connection (most probably it connects to some mock on *.ranides.net)
+     */
     public static final class Online { }
 
+    /**
+     * This test is unpredictable. Most of the time works, but sometimes fails,
+     * most probably due to threading errors and race conditions
+     */
     public static final class UnstableTest { }
 }

+ 23 - 3
assira.junit/src/main/java/net/ranides/assira/junit/LogMessage.java

@@ -7,6 +7,10 @@
 package net.ranides.assira.junit;
 
 /**
+ * Entry used by {@link LogObserver} to store all observed messages.
+ * Please note that storing all log messages in memory is extremally inefficent both for performance and memory usage.
+ * We should use it inside unit tests, when we expect some log message and there is no other way to detect that expected
+ * action happened.
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
@@ -23,15 +27,31 @@ public class LogMessage {
         this.text = (error==null) ? text : text + " @ " + error;
         this.error = error;
     }
-    
+
+    /**
+     * Text of message
+     * @return string
+     */
     public String text() {
         return text;
     }
-  
+
+    /**
+     * Level of messsage.
+     * Levels are defined inside {@link org.slf4j.spi.LocationAwareLogger}
+     *
+     * @return int
+     */
     public int level() {
         return level;
     }
-    
+
+    /**
+     * Exception connected with the message.
+     * slf4j optionally allows to assign to specific message correlated exception.
+     *
+     * @return exception or null
+     */
     public Throwable error() {
         return error;
     }

+ 98 - 14
assira.junit/src/main/java/net/ranides/assira/junit/LogObserver.java

@@ -16,11 +16,31 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
+ * LogObserver is working only inside unit tests.
+ * It is collection all log messages emmitted by slf4j.
+ * It works because assira.junit provides its own slf4j logger implementation: {@link org.slf4j.impl.ObserveLogger}
+ *
+ * To use LogObserver be sure, that there is no other slf4j logger implementations in classpath
+ *
+ * You can enable log collection by setting system properties:
+ *  "assira.junit.debug"            - messages are printed to console
+ *  "assira.junit.logger.observe"   - messages are collected
+ *  "assira.junit.log"              - set minimum level of collected messages ("debug" by default)
+ *                                    allowed values: trace, debug, info, warn, warning, error
+ *
+ * You can change "debug" and "observe" states at runtime, by calling static methods: "debug" and "reset".
+ *
+ * It is impossible to change "level" of messages accepted by logger.
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
 public final class LogObserver {
-    
+
+    /**
+     * We use ConcurrentLinkedQueue because we want to avoid blocking on log operations.
+     * If we decided to use collection synchronized by locks, then all multithreading operations in unit test
+     * would be degenerated to serial list of steps one after one, by every log operation.
+     */
     private static final Queue<LogMessage> TARGET = new ConcurrentLinkedQueue<>();
     
     private static final boolean DEBUG = "true".equals(System.getProperty("assira.junit.debug"));
@@ -34,7 +54,17 @@ public final class LogObserver {
     private LogObserver() {
         /* utility class */
     }
-    
+
+    /**
+     * Adds new message to collected list, if observer is enabled. Prints message, if debug is enabled.
+     * It does nothing in other cases.
+     *
+     * Method is not supposed to be called directly. It is used by internal {@link org.slf4j.impl.ObserveLogger}.
+     *
+     * @param level level
+     * @param message message
+     * @param error error
+     */
     @SuppressWarnings("PMD.SystemPrintln")
     public static void append(int level, String message, Throwable error) {
         if(enabled) {
@@ -47,43 +77,97 @@ public final class LogObserver {
             }
         }
     }
-    
+
+    /**
+     * Turns on/off printing messages to console.
+     *
+     * @param value value
+     */
     public static void debug(boolean value) {
         debug = value;
     }
-    
+
+    /**
+     * Turns on/off collecting of messages emmited by slf4j.
+     *
+     * This method always clears already collected list of messages!
+     *
+     * @param enabled enabled
+     */
     public static void reset(boolean enabled) {
         TARGET.clear();
         LogObserver.enabled = enabled;
     }
-    
+
+    /**
+     * Returns snaphshot of collected messages.
+     * It is copy of internal buffer.
+     *
+     * @return list
+     */
     public static List<LogMessage> list() {
         return new ArrayList<>(TARGET);
     }
-    
+
+    /**
+     * Returns stream with collected messages.
+     *
+     * @return stream
+     */
     public static Stream<LogMessage> stream() {
         return TARGET.stream();
     }
-    
+
+    /**
+     * Checks if there is a message matching specified criteria.
+     * Equivalent to stream().anyMatch(filter)
+     *
+     * @param filter filter
+     * @return bool
+     */
     public static boolean match(Predicate<LogMessage> filter) {
         return stream().anyMatch(filter);
     }
-    
+
+    /**
+     * Returns stream with messages with text matching specified criteria.
+     *
+     * @param filter filter
+     * @return stream
+     */
     public static Stream<LogMessage> forText(Predicate<CharSequence> filter) {
         return stream().filter(m -> filter.test(m.text()));
     }
-    
+
+    /**
+     * Returns stream with messages with specified text.
+     * It uses simple comparison, not regular expression match.
+     *
+     * @param text text
+     * @return stream
+     */
     public static Stream<LogMessage> forText(CharSequence text) {
-        String str = String.valueOf(text);
-        return stream().filter(m -> str.equals(m.text()));
+        return forText(String.valueOf(text)::equals);
     }
-    
+
+    /**
+     * Returns stream with messages with level matching specified criteria
+     *
+     * @param filter
+     * @return
+     */
     public static Stream<LogMessage> forLevel(IntPredicate filter) {
         return stream().filter(m -> filter.test(m.level()));
     }
-    
+
+    /**
+     * Returns stream with messages with level greater or equal to provided
+     *
+     * @param level level
+     * @return stream
+     */
     public static Stream<LogMessage> forLevel(int level) {
-        return stream().filter(m -> m.level() >= level);
+        return forLevel(m -> m >= level);
     }
     
 }

+ 238 - 37
assira.junit/src/main/java/net/ranides/assira/junit/NewAssert.java

@@ -7,6 +7,8 @@
 package net.ranides.assira.junit;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.junit.Assert;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -35,13 +37,21 @@ import java.util.stream.Collectors;
 
 
 /**
+ * Additional static methods supplementing those from junit Assert.
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
 public final class NewAssert extends org.junit.Assert {
     
     private NewAssert() { }
-    
+
+    /**
+     * Methods expecting exception of specified type thrown from action.
+     * JUnit provided the same method in version 4.13
+     *
+     * @param error expected error
+     * @param action action
+     */
     public static void assertThrows(Class<? extends Throwable> error, Action action) {
         try {
             action.run();
@@ -54,6 +64,13 @@ public final class NewAssert extends org.junit.Assert {
         fail(error + " expected");
     }
 
+    /**
+     * Methods expecting specified exception with cause thrown from action.
+     *
+     * @param error type of exception
+     * @param cause type of cause
+     * @param action action
+     */
     public static void assertThrows(Class<? extends Throwable> error, Class<? extends Throwable> cause, Action action) {
         try {
             action.run();
@@ -69,7 +86,17 @@ public final class NewAssert extends org.junit.Assert {
         }
         fail(error + " expected");
     }
-    
+
+    /**
+     * Methods expecting specified exception with message thrown from action.
+     *
+     * Warning: Junit has similar method, but with different behaviour!
+     * It uses "message" argument to print information about failed assertion, not to examine exception.
+     *
+     * @param error expected exception
+     * @param message expected message
+     * @param action action
+     */
     public static void assertThrows(Class<? extends Throwable> error, String message, Action action) {
         try {
             action.run();
@@ -84,7 +111,14 @@ public final class NewAssert extends org.junit.Assert {
         }
         fail(error + " expected");
     }
-    
+
+    /**
+     * Methods expecting specified exception thrown from action.
+     * Provided "handler" is used to check if exception satisfies condition.
+     *
+     * @param handler predicate
+     * @param action action
+     */
     public static void assertThrows(Predicate<Throwable> handler, Action action) {
         try {
             action.run();
@@ -96,7 +130,12 @@ public final class NewAssert extends org.junit.Assert {
         }
         fail("Exception expected");
     }
-    
+
+    /**
+     * Checks if object can be correctly serialized and deserialized to the same state (checks equality).
+     *
+     * @param value value
+     */
     public static void assertSerializable(Object value) {
         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
         try (ObjectOutputStream ostream = new ObjectOutputStream(buffer)) {
@@ -112,17 +151,23 @@ public final class NewAssert extends org.junit.Assert {
     }
     
     /**
-     * Requirements (object : hash / pseudo-value)
+     * Check if provided objects has correctly implemented equality contract.
+     * First 2 objects should be equal.
+     * First 3 objects should have the same hashCode,
+     * Last object should have different hash & can't be equal to former objects.
+     *
+     * Requirements:
      * <pre>
-     *  A : 1 / 1
-     *  B : 1 / 1
-     *  C : 1 / 2
-     *  D : 2 / 3
+     *  A returns hash1 / has value1
+     *  B returns hash1 / has value1
+     *  C returns hash1 / has value2
+     *  D returns hash2 / has value3
      * </pre>
-     * @param a
-     * @param b
-     * @param c
-     * @param d
+     *
+     * @param a 1st object
+     * @param b 2nd object, equals to "a"
+     * @param c 3rd object, the same hash as "a" and "b"
+     * @param d 4th object, different hash and not equal to "a", "b", "c"
      */
     @SuppressFBWarnings("SA_LOCAL_SELF_COMPARISON")
     public static void assertEquality(Object a, Object b, Object c, Object d) {
@@ -155,15 +200,20 @@ public final class NewAssert extends org.junit.Assert {
     }
     
     /**
-     * Requirements (object : hash / pseudo-value)
+     * Check if provided objects has correctly implemented equality contract.
+     * First 2 objects should be equal.
+     * Last object should have different hash & can't be equal to former objects.
+     *
+     * Requirements:
      * <pre>
-     *  A : 1 / 1
-     *  B : 1 / 1
-     *  D : 2 / 2
+     *  A returns hash1 / has value1
+     *  B returns hash1 / has value1
+     *  D returns hash2 / has value3
      * </pre>
-     * @param a
-     * @param b
-     * @param d
+     *
+     * @param a 1st object
+     * @param b 2nd object, equals to "a"
+     * @param d 3th object, different hash and not equal to "a", "b", "c"
      */
     @SuppressFBWarnings("SA_LOCAL_SELF_COMPARISON")
     public static void assertEquality(Object a, Object b, Object d) {
@@ -187,33 +237,89 @@ public final class NewAssert extends org.junit.Assert {
         assertFalse("b != object", b.equals(new Object()));
         assertFalse("d != object", d.equals(new Object()));
     }
-	
+
+    /**
+     * Checks symmetrical equality of objects and their hashcodes.
+     * It means, it checks if a.equals(b) and b.equals(a).
+     *
+     * @param value1 value1
+     * @param value2 value2
+     */
 	public static void assertSymEquals(Object value1, Object value2) {
         assertEquals(Objects.hashCode(value1), Objects.hashCode(value2));
 		assertEquals(value1, value2);
         assertEquals(value2, value1);
 	}
-    
+
+    /**
+     * Checks symmetrical equality of objects and their hashcodes.
+     * It means, it checks if a.equals(b) and b.equals(a).
+     *
+     * Displays provided message on error.
+     *
+     * @param message message
+     * @param value1 value1
+     * @param value2 value2
+     */
     public static void assertSymEquals(String message, Object value1, Object value2) {
         assertEquals(message, Objects.hashCode(value1), Objects.hashCode(value2));
         assertEquals(message, value1, value2);
         assertEquals(message, value2, value1);
     }
-    
+
+    /**
+     * Checks symmetrical non-equality of objects and their hashcodes.
+     * It means, it checks if !a.equals(b) and !b.equals(a).
+     *
+     * @param value1 value1
+     * @param value2 value2
+     */
     public static void assertSymNotEquals(Object value1, Object value2) {
         assertNotEquals(value1, value2);
         assertNotEquals(value2, value1);
     }
-    
+
+    /**
+     * Checks symmetrical non-equality of objects and their hashcodes.
+     * It means, it checks if !a.equals(b) and !b.equals(a).
+     *
+     * Displays provided message on error.
+     *
+     * @param message message
+     * @param value1 value1
+     * @param value2 value2
+     */
     public static void assertSymNotEquals(String message, Object value1, Object value2) {
         assertNotEquals(message, value1, value2);
         assertNotEquals(message, value2, value1);
     }
-    
+
+    /**
+     * Checks if lists have the same size and if corresponding elements are equal.
+     * Equality is checked by provided "predicate".
+     *
+     * @param expected expected
+     * @param values values
+     * @param predicate predicate
+     * @param <A> type
+     * @param <B> type
+     */
     public static <A,B> void assertMatch(Collection<A> expected, Collection<B> values, BiPredicate<A,B> predicate) {
         assertMatch("", expected, values, predicate);
     }
-    
+
+    /**
+     * Checks if lists have the same size and if corresponding elements are equal.
+     * Equality is checked by provided "predicate".
+     * Displays provided message on error.
+     *
+     * @param message message
+     * @param expected expected
+     * @param values values
+     * @param predicate predicate
+     * @param <A> type
+     * @param <B> type
+     */
     public static <A,B> void assertMatch(String message, Collection<A> expected, Collection<B> values, BiPredicate<A,B> predicate) {
         assertEquals(message + ": different size", expected.size(), values.size());
         Iterator<A> ia = expected.iterator();
@@ -226,8 +332,21 @@ public final class NewAssert extends org.junit.Assert {
             }
 		}
     }
-    
-    @SuppressWarnings("unchecked")    
+
+    /**
+     * Checks enum invariants. Most specifically it checks:
+     *  - if there at least one enum constant
+     *  - if valueOf returns correct type
+     *  - if valueOf returns correct value for every enum name
+     *  - if valueOf throws exception on invalid name
+     *
+     * Idea of this method came because many corporate codebases contained enum classes with very strange "valueOf"
+     *
+     * @param enumtype type
+     * @param <E> type
+     * @throws Exception on internal error
+     */
+    @SuppressWarnings("unchecked")
     public static <E extends Enum<E>> void assertEnumInvariants(Class<E> enumtype) throws Exception {
         Method mValues = enumtype.getMethod("values");
         Method mValueOf = enumtype.getMethod("valueOf", String.class);
@@ -251,51 +370,126 @@ public final class NewAssert extends org.junit.Assert {
         assertNotSame(mValues.invoke(null), mValues.invoke(null));
         assertArrayEquals((E[])mValues.invoke(null), (E[])mValues.invoke(null));
     }
-    
+
+    /**
+     * Checks if provided maps have the same content, ignores order of elements.
+     *
+     * @param a a
+     * @param b a
+     * @param <K> K
+     * @param <V> V
+     */
     public static <K,V> void assertEquivalent(Map<K,V> a, Map<K,V> b) {
         assertEquivalent(a.entrySet(), b.entrySet());
     }
-    
+
+    /**
+     * Checks if provided collections have the same content, ignores order of elements.
+     *
+     * @param a a
+     * @param b b
+     * @param <T> T
+     */
     public static <T> void assertEquivalent(Collection<T> a, Collection<T> b) {
         String message = a + " not equivalent to " + b;
         assertTrue(message, a.size()==b.size());
         assertTrue(message, a.containsAll(b));
         assertTrue(message, b.containsAll(a));
 	}
-    
+
+    /**
+     * Checks equality of two Instant values with specified precision.
+     *
+     * @param a a
+     * @param b b
+     * @param dt precision
+     */
     public static void assertEquals(Instant a, Instant b, Duration dt) {
         assertTrue(a + " and " + b + " are not equal", Duration.between(a, b).abs().compareTo(dt.abs()) <= 0);
     }
-    
+
+    /**
+     * Checks equality of two Date values with specified precision.
+     *
+     * @param a a
+     * @param b b
+     * @param dt precision
+     */
     public static void assertEquals(Date a, Date b, Duration dt) {
         assertTrue(a + " and " + b + " are not equal", Math.abs(a.getTime() - b.getTime()) <= dt.toMillis());
     }
-    
+
+    /**
+     * Checks equality of two Date values with specified precision (in milliseconds).
+     *
+     * @param a a
+     * @param b b
+     * @param dt precision
+     */
     public static void assertEquals(Date a, Date b, long dt) {
         assertTrue(a + " and " + b + " are not equal", Math.abs(a.getTime() - b.getTime()) <= dt);
     }
-    
+
+    /**
+     * Checks if optional is empty
+     *
+     * @param value value
+     */
     public static void assertEmpty(Optional<?> value) {
         assertFalse("Optional should be empty", value.isPresent());
     }
-    
+
+    /**
+     * Checks if collection is empty
+     *
+     * @param value value
+     */
     public static void assertEmpty(Collection<?> value) {
         assertTrue("Collection should be empty", value.isEmpty());
     }
-    
+
+    /**
+     * Checks if map is empty
+     *
+     * @param value value
+     */
     public static void assertEmpty(Map<?,?> value) {
         assertTrue("Map should be empty", value.isEmpty());
     }
 
+    /**
+     * Checks if provided lines are identical to those in expected file.
+     * Please note that it does not care about linux/windows line endings.
+     * It uses UTF8 encoding.
+     *
+     * @param file expected content
+     * @param content content
+     */
     public static void assertLineEquals(File file, List<?> content) {
         String text = content.stream().map(Object::toString).collect(Collectors.joining("\n"));
         assertLineEquals(file, text);
     }
 
+    /**
+     * Checks if provided text contains identical lines like those in expected file.
+     * Please note that it does not care about linux/windows line endings.
+     * It uses UTF8 encoding.
+     *
+     * @param file expected content
+     * @param content content
+     */
     public static void assertLineEquals(File file, String content) {
         assertLineEquals(file, StandardCharsets.UTF_8, content);
     }
 
+    /**
+     * Checks if provided text contains identical lines like those in expected file.
+     * Please note that it does not care about linux/windows line endings
+     *
+     * @param file file
+     * @param charset charset
+     * @param content content
+     */
     public static void assertLineEquals(File file, Charset charset, String content) {
         try {
             String expected = Files.lines(file.toPath(), charset).collect(Collectors.joining("\n"));
@@ -306,8 +500,15 @@ public final class NewAssert extends org.junit.Assert {
         }
     }
 
+    /**
+     * Functional interface for {@link #assertThrows} methods.
+     */
     public interface Action {
-        
+
+        /**
+         * Action which should throw exception
+         * @throws Throwable exception
+         */
         void run() throws Throwable;
         
     }

+ 33 - 0
assira.junit/src/main/java/net/ranides/assira/junit/TestContract.java

@@ -12,6 +12,39 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
+ * Annotation used to mark methods as usable by {@link TestContractRunner}.
+ * Object which contains one or more annotated methods is called tester.
+ *
+ * Tester can declare methods for tests and fields for injection.
+ * To read about injection, lets look at {@link TestResource}.
+ *
+ * Annotated method must be non-static, public, and has one compatible argument.
+ * Type of argument is critical, because runner checks if currently tested object
+ * is sublcass of this argument and executes method only if it is designed for this type.
+ *
+ * Tester methods can take 3 types of arguments:
+ * 1) just an object of type T:
+ *    runner will create it using supplier and send this object in default state to the tester
+ *
+ * 2) supplier of object of type Supplier<T>:
+ *    runner will pass supplier, tester can call supplier to create many objects with default state
+ *
+ * 3) function<X,T>:
+ *    runner will pass function; tester can call this function with different "X" arguments
+ *    to create objects in different state. there is no exact definition of "different state":
+ *    only guaranteed effect is, they won't be equal.
+ *
+ *    Some functions takes int[] and use convention, that first int defines hashcode, and second defines equality.
+ *    Some functions takes int[] and use convention, to create collection filled by "some objects" created from int[] elements.
+ *
+ * You have to correctly configure runner to be able to pass those arguments to testers.
+ * For example: runner which does not have function<int[],T> won't be able to execute tests which expect this function.
+ *
+ * Every tester method must take argument, even if it does not use it,
+ * because we want to match tested type and decide if method should be executed.
+ *
+ * Some contract testers do not use passed arguments too much, but use injected factories.
+ * To use them, you must configure TestContractRunner, using {@link TestContractRunner#param}.
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */

+ 139 - 12
assira.junit/src/main/java/net/ranides/assira/junit/TestContractRunner.java

@@ -33,6 +33,11 @@ import org.junit.Ignore;
  * register testers annotated as compatible with {@code Map} & {@code SortedMap}, 
  * then method {@code run} will invoke both of them for {@code TreeMap}, but only
  * the first one for {@codee HashMap}.
+ *
+ * For details lets read:
+ *      @see #append(Object)
+ *      @see TestContract
+ *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
 public final class TestContractRunner {
@@ -54,12 +59,27 @@ public final class TestContractRunner {
 	private Function<Object, Object> function;
 	
 	private Supplier<Object> supplier;
-	
 
+
+    /**
+     * Creates new runner which prints results into specified stream
+     * @param output
+     */
     public TestContractRunner(PrintStream output) {
         this.output = output;
     }
-    
+
+    /**
+     * Creates new runner which inherits all testers and ignore patterns.
+     * Please note, that all testers are deeply copied.
+     *
+     * Every change in parent runner won't be visible in descendant runners.
+     *
+     * It is usefull if first configuration has high cost, for example
+     * it uses package scanner to find and append all testers.
+     *
+     * @param runner parent runner
+     */
     public TestContractRunner(TestContractRunner runner) {
         this(runner.output);
 		for(TesterWrapper w : runner.testers) {
@@ -70,26 +90,63 @@ public final class TestContractRunner {
 		this.supplier = null;
 		this.function = null;
     }
-    
+
+    /**
+     * Turns on/off debug mode.
+     * Runner in debug mode prints a bit more diagnostic messages: list every executed or ignored method.
+     *
+     * @param value value
+     * @return this
+     */
 	public TestContractRunner debug(boolean value) {
         this.debug = value;
 		return this;
 	}
-    
+
+    /**
+     * Returns current debug mode
+     * @return bool
+     */
     public boolean debug() {
         return this.debug;
 	}
-	
+
+    /**
+     * Ignores every method detected by runner inside any tests, if it matches to provided pattern.
+     * Pattern is standard regular expression.
+     *
+     * @param method method pattern
+     * @return this
+     */
     public TestContractRunner ignore(String method) {
         this.ignored.add(method);
         return this;
     }
-	
+
+    /**
+     * Ignores every method, if it matches to provided pattern.
+     *
+     * @param method method pattern
+     * @return this
+     */
 	public TestContractRunner ignore(Pattern method) {
         this.ignored.add(method);
         return this;
     }
-    
+
+    /**
+     * Appends to runner tester.
+     * All testers appended to runner are examined when {@link #run} is called.
+     * Runner uses provided suppliers and functions to create test objects and decides which tester is adequate to
+     * check object's behaviour.
+     *
+     * Any object can be tester as long as it has public methods annotated by {@link TestContract}.
+     *
+     * @param tester tester
+     * @return this
+     *
+     * @see TestContract
+     */
     public TestContractRunner append(Object tester) {
         appendWrapper(tester);
         return this;
@@ -118,35 +175,105 @@ public final class TestContractRunner {
         }
 		return wrapper;
 	}
-    
+
+    /**
+     * Inserts named object into runner.
+     * Contract testers can use those parameter by injection, annotating their fields by {@link TestResource}.
+     *
+     * Please note, that altough object
+     *
+     * @param name name
+     * @param value value
+     * @return
+     */
     public TestContractRunner param(String name, Object value) {
         testers.forEach(t -> t.param(name, value));
         return this;
     }
-    
+
+    /**
+     * Configures this runner, by applying provided configuration function.
+     * Configurator is simple method which calls whetever it wants on runner.
+     *
+     * @param configurator configurator
+     * @return this
+     */
     public TestContractRunner apply(Consumer<TestContractRunner> configurator) {
         configurator.accept(this);
         return this;
     }
-    
+
+    /**
+     * Configures "supplier" for this runner.
+     * Runner will use this supplier to produce testable objects (in default state).
+     * Some testers does not need much more than this functionality.
+     *
+     * @param supplier supplier
+     * @return
+     */
 	@SuppressWarnings("unchecked")
 	public TestContractRunner supplier(Supplier<?> supplier) {
 		this.supplier = (Supplier)supplier;
 		return this;
 	}
-	
+
+    /**
+     * Configures "function" for this runner.
+     * T can be any type, altough most testers expect int[].
+     * This function is simply used to map some standard type (string, int[]...) into R type, which will be tested.
+     *
+     * It is especially helpfull if you want to test some collections with different content.
+     *
+     * Please note, that configuring "function" won't configure default supplier!
+     *
+     * @param function function
+     * @param <T> standard input type, for example int[]
+     * @param <R> generated type to examine
+     * @return this
+     */
     @SuppressWarnings("unchecked")
 	public <T,R> TestContractRunner function(Function<T, R> function) {
 		this.function = (Function)function;
 		return this;
 	}
-	
+
+    /**
+     * Configures "function" for this runner.
+     * T can be any type, altough most testers expect int[].
+     * This function is simply used to map some standard type (string, int[]...) into R type, which will be tested.
+     *
+     * It is especially helpfull if you want to test some collections with different content.
+     *
+     * It uses "ident" input to configure default "supplier" too.
+     *
+     * @param ident argument for supplier
+     * @param function function
+     * @param <T> standard input type, for example int[]
+     * @param <R> generated type to examine
+     * @return this
+     */
 	public <T,R> TestContractRunner function(T ident, Function<T, R> function) {
 		function(function);
 		this.supplier = () -> this.function.apply(ident);
 		return this;
 	}
 
+    /**
+     * Iterates for all append testers,
+     * check every method if it is compatible with type provided by "supplier"
+     * and tries to execute it against created object.
+     *
+     * Compatibility means, if supplier returned type T, then we will try to execute all methods accepting:
+     *  1) type {@code T}
+     *  2) {@code Supplier<T>}
+     *  3) {@code Function<*,T>}
+     *
+     *  Method prints to console information about failed tests.
+     *
+     *  It does not stop on first error, but executes everything and prints summary at the very end.
+     *
+     * @return true if all tests succeded
+     */
     public boolean run() {
         for(TesterWrapper tester : testers) {
             tester.bind(this);

+ 13 - 0
assira.junit/src/main/java/net/ranides/assira/junit/TestResource.java

@@ -6,10 +6,23 @@ import java.lang.annotation.Target;
 import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
+/**
+ * This annotation is used by Tester to inject objects.
+ * TestContractRunner scans every tester for annotated fields and assigns to them value with specified name.
+ *
+ * You can configure named resources inside TestContractRunner by using {@code param} method.
+ *
+ * Please note, that you can inject currently executed TestContractRunner into tester,
+ * by simply annotating field of type TestContractRunner, without providing any name for TestResource annotation.
+ */
 @Retention(RUNTIME)
 @Target({FIELD})
 public @interface TestResource {
 
+    /**
+     * Name of resource to inject
+     * @return string
+     */
     String name() default "";
 
 }

+ 3 - 0
assira.junit/src/main/java/org/slf4j/impl/ObserveLoggerFactory.java

@@ -40,6 +40,9 @@ public class ObserveLoggerFactory implements ILoggerFactory {
 
     final ConcurrentMap<String, Logger> loggerMap;
 
+    /**
+     * Default constructor
+     */
     public ObserveLoggerFactory() {
         loggerMap = new ConcurrentHashMap<>();
     }

+ 6 - 2
assira.junit/src/main/java/org/slf4j/impl/StaticMDCBinder.java

@@ -44,13 +44,17 @@ public final class StaticMDCBinder {
     }
 
     /**
-     * Currently this method always returns an instance of 
-     * {@link StaticMDCBinder}.
+     * Currently this method always returns an instance of {@link StaticMDCBinder}.
+     * @return MDCAdapter
      */
     public MDCAdapter getMDCA() {
         return new NOPMDCAdapter();
     }
 
+    /**
+     * Currently this method always returns name of {@link StaticMDCBinder}.
+     * @return string
+     */
     public String getMDCAdapterClassStr() {
         return NOPMDCAdapter.class.getName();
     }