Pārlūkot izejas kodu

new: IOUtils#close(closeable) throws IOException
new: ClassUtils#isLoaded
new: LoggerLevel for slf4j

change: LoggerUtils - removed unnecessary methods (trace-logger)

test (82)

Ranides Atterwim 10 gadi atpakaļ
vecāks
revīzija
61c6555c4b

+ 5 - 6
assira/pom.xml

@@ -171,8 +171,11 @@
                                 
 								<exclude>net/ranides/assira/trace/ExceptionInspector$*</exclude>
 								<exclude>net/ranides/assira/trace/ExceptionInspector.class</exclude>
-								<!--<exclude>net/ranides/assira/trace/StackInspector$*</exclude>-->
-								<!--<exclude>net/ranides/assira/trace/StackInspector.class</exclude>-->
+                                <exclude>net/ranides/assira/trace/LoggerLevel$*</exclude>
+                                <exclude>net/ranides/assira/trace/LoggerLevel.class</exclude>
+                                <exclude>net/ranides/assira/trace/LoggerUtils.class</exclude>
+								<exclude>net/ranides/assira/trace/StackInspector$*</exclude>
+								<exclude>net/ranides/assira/trace/StackInspector.class</exclude>
 								<exclude>net/ranides/assira/trace/ThreadInspector$*</exclude>
 								<exclude>net/ranides/assira/trace/ThreadInspector.class</exclude>
                                 
@@ -224,10 +227,6 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-simple</artifactId>
-        </dependency>
         <dependency>
             <groupId>com.google.code.findbugs</groupId>
             <artifactId>annotations</artifactId>

+ 8 - 4
assira/src/main/java/net/ranides/assira/io/IOUtils.java

@@ -12,10 +12,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Arrays;
 import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.LongConsumer;
-import net.ranides.assira.events.Event;
-import net.ranides.assira.events.EventListener;
 import net.ranides.assira.trace.ExceptionInspector;
 import net.ranides.assira.trace.LoggerUtils;
 
@@ -41,6 +37,14 @@ public final class IOUtils {
         return ExceptionInspector.rethrow(wrap(cause));
     }
     
+    public static boolean close(Closeable object) throws IOException {
+        if(null != object) {
+            object.close();
+            return true;
+        }
+        return false;
+    }
+    
     public static boolean close(Object object) throws Exception {
         if(object instanceof Closeable) {
             ((Closeable)object).close();

+ 202 - 178
assira/src/main/java/net/ranides/assira/reflection/util/ClassUtils.java

@@ -1,178 +1,202 @@
-/*
- * @author Ranides Atterwim <ranides@gmail.com>
- * @copyright Ranides Atterwim
- * @license WTFPL
- * @url http://ranides.net/projects/assira
- */
-package net.ranides.assira.reflection.util;
-
-import java.lang.reflect.Modifier;
-
-/**
- *
- * @author Ranides Atterwim <ranides@gmail.com>
- */
-public final class ClassUtils {
-    
-    private ClassUtils() {
-        // utility class
-    }
-    
-    @SuppressWarnings("PMD")
-    public static Class<?> box(Class<?> clazz) {
-        if (byte.class.equals(clazz)) {
-            return Byte.class;
-        } else if (short.class.equals(clazz)) {
-            return Short.class;
-        } else if (int.class.equals(clazz)) {
-            return Integer.class;
-        } else if (long.class.equals(clazz)) {
-            return Long.class;
-        } else if (char.class.equals(clazz)) {
-            return Character.class;
-        } else if (float.class.equals(clazz)) {
-            return Float.class;
-        } else if (double.class.equals(clazz)) {
-            return Double.class;
-        } else if (boolean.class.equals(clazz)) {
-            return Boolean.class;
-        } else if (void.class.equals(clazz)) {
-            return Void.class;
-        } else {
-            return clazz;
-        }
-    }
-
-    @SuppressWarnings("PMD")
-    public static Class<?> unbox(Class<?> clazz) {
-        if (Byte.class.equals(clazz)) {
-            return byte.class;
-        } else if (Short.class.equals(clazz)) {
-            return short.class;
-        } else if (Integer.class.equals(clazz)) {
-            return int.class;
-        } else if (Long.class.equals(clazz)) {
-            return long.class;
-        } else if (Character.class.equals(clazz)) {
-            return char.class;
-        } else if (Float.class.equals(clazz)) {
-            return float.class;
-        } else if (Double.class.equals(clazz)) {
-            return double.class;
-        } else if (Boolean.class.equals(clazz)) {
-            return boolean.class;
-        } else if (Void.class.equals(clazz)) {
-            return void.class;
-        } else {
-            return clazz;
-        }
-    }
-
-    
-    public static boolean isStatic(Class<?> clazz) {
-        return Modifier.isStatic(clazz.getModifiers());
-    }
-
-    public static boolean isPublic(Class<?> clazz) {
-        return Modifier.isPublic(clazz.getModifiers());
-    }
-
-    public static boolean isProtected(Class<?> clazz) {
-        return Modifier.isProtected(clazz.getModifiers());
-    }
-
-    public static boolean isPrivate(Class<?> clazz) {
-        return Modifier.isPrivate(clazz.getModifiers());
-    }
-
-    public static boolean isInterface(Class<?> clazz) {
-        return Modifier.isInterface(clazz.getModifiers());
-    }
-
-    public static boolean isFinal(Class<?> clazz) {
-        return Modifier.isFinal(clazz.getModifiers());
-    }
-
-    public static boolean isAbstract(Class<?> clazz) {
-        return Modifier.isAbstract(clazz.getModifiers());
-    }
-    
-    /**
-     * Rozszerzenie standardowej metody {@code Class.isAssignableFrom}.
-     * Uwzględnia autoboxing argumentów.
-     * @param ssuper
-     * @param value
-     * @return
-     */
-    @SuppressWarnings("PMD.CyclomaticComplexity")
-    public static boolean isAssignableFrom(Class<?> ssuper, Class<?> value) {
-        if (ssuper.equals(boolean.class) || ssuper.equals(Boolean.class)) {
-            return value.equals(boolean.class) || value.equals(Boolean.class);
-        } else if (ssuper.equals(char.class) || ssuper.equals(Character.class)) {
-            return value.equals(char.class) || value.equals(Character.class);
-        } else if (ssuper.equals(byte.class) || ssuper.equals(Byte.class)) {
-            return value.equals(byte.class) || value.equals(Byte.class);
-        } else if (ssuper.equals(short.class) || ssuper.equals(Short.class)) {
-            return value.equals(short.class) || value.equals(Short.class);
-        } else if (ssuper.equals(int.class) || ssuper.equals(Integer.class)) {
-            return value.equals(int.class) || value.equals(Integer.class);
-        } else if (ssuper.equals(long.class) || ssuper.equals(Long.class)) {
-            return value.equals(long.class) || value.equals(Long.class);
-        } else if (ssuper.equals(float.class) || ssuper.equals(Float.class)) {
-            return value.equals(float.class) || value.equals(Float.class);
-        } else if (ssuper.equals(double.class) || ssuper.equals(Double.class)) {
-            return value.equals(double.class) || value.equals(Double.class);
-        } else {
-            return ssuper.isAssignableFrom(value);
-        }
-    }
-    
-    /**
-     * Grupowa wersja funkcji {@code Class.isAssignableFrom} - sprawdza, czy odpowiednie
-     * elementy z tablicy {@code supers} są assignable względem odpowiednich
-     * elementów {@code values}, czyli czy <br>
-     * {@code for(i) supers[i].isAssignableFrom( values[i] ) }
-     * Uwzględnia autoboxing argumentów.
-     * @param supers
-     * @param values
-     * @return
-     */
-    public static boolean isAssignableFrom(Class<?>[] supers, Class<?>[] values) {
-        if(supers.length != values.length) {
-            return false;
-        }
-        for(int i=0; i<supers.length; i++) {
-            if( !isAssignableFrom(supers[i], values[i]) ) { return false; }
-        }
-        return true;
-    }
-
-    /**
-     * Sprawdza, czy podany obiekt {@code get} jest instancją klasy {@code ssuper}.
-     * Uwzględnia autoboxing argumentów.
-     * @param ssuper
-     * @param value
-     * @return
-     */
-    public static boolean isInstance(Class<?> ssuper, Object value) {
-        return value==null || ssuper.isInstance(value) || box(ssuper).isInstance(value);
-    }
-
-    /**
-     * Sprawdza, czy odpowiednie obiekty z tablicy {@code values} są istancjami
-     * odpowiednich klas z tablicy {@code supers}. Uwzględnia autoboxing argumentów.
-     * @param supers
-     * @param values
-     * @return
-     */
-    public static boolean isInstance(Class<?>[] supers, Object[] values) {
-        if(supers.length != values.length) {
-            return false;
-        }
-        for(int i=0; i<supers.length; i++) {
-            if( !isInstance(supers[i], values[i]) ) { return false; }
-        }
-        return true;
-    }
-    
-}
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.util;
+
+import java.lang.reflect.Modifier;
+import net.ranides.assira.trace.ExceptionInspector;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public final class ClassUtils {
+    
+    private ClassUtils() {
+        // utility class
+    }
+    
+    @SuppressWarnings("PMD")
+    public static Class<?> box(Class<?> clazz) {
+        if (byte.class.equals(clazz)) {
+            return Byte.class;
+        } else if (short.class.equals(clazz)) {
+            return Short.class;
+        } else if (int.class.equals(clazz)) {
+            return Integer.class;
+        } else if (long.class.equals(clazz)) {
+            return Long.class;
+        } else if (char.class.equals(clazz)) {
+            return Character.class;
+        } else if (float.class.equals(clazz)) {
+            return Float.class;
+        } else if (double.class.equals(clazz)) {
+            return Double.class;
+        } else if (boolean.class.equals(clazz)) {
+            return Boolean.class;
+        } else if (void.class.equals(clazz)) {
+            return Void.class;
+        } else {
+            return clazz;
+        }
+    }
+
+    @SuppressWarnings("PMD")
+    public static Class<?> unbox(Class<?> clazz) {
+        if (Byte.class.equals(clazz)) {
+            return byte.class;
+        } else if (Short.class.equals(clazz)) {
+            return short.class;
+        } else if (Integer.class.equals(clazz)) {
+            return int.class;
+        } else if (Long.class.equals(clazz)) {
+            return long.class;
+        } else if (Character.class.equals(clazz)) {
+            return char.class;
+        } else if (Float.class.equals(clazz)) {
+            return float.class;
+        } else if (Double.class.equals(clazz)) {
+            return double.class;
+        } else if (Boolean.class.equals(clazz)) {
+            return boolean.class;
+        } else if (Void.class.equals(clazz)) {
+            return void.class;
+        } else {
+            return clazz;
+        }
+    }
+
+    
+    public static boolean isStatic(Class<?> clazz) {
+        return Modifier.isStatic(clazz.getModifiers());
+    }
+
+    public static boolean isPublic(Class<?> clazz) {
+        return Modifier.isPublic(clazz.getModifiers());
+    }
+
+    public static boolean isProtected(Class<?> clazz) {
+        return Modifier.isProtected(clazz.getModifiers());
+    }
+
+    public static boolean isPrivate(Class<?> clazz) {
+        return Modifier.isPrivate(clazz.getModifiers());
+    }
+
+    public static boolean isInterface(Class<?> clazz) {
+        return Modifier.isInterface(clazz.getModifiers());
+    }
+
+    public static boolean isFinal(Class<?> clazz) {
+        return Modifier.isFinal(clazz.getModifiers());
+    }
+
+    public static boolean isAbstract(Class<?> clazz) {
+        return Modifier.isAbstract(clazz.getModifiers());
+    }
+    
+    /**
+     * Rozszerzenie standardowej metody {@code Class.isAssignableFrom}.
+     * Uwzględnia autoboxing argumentów.
+     * @param ssuper
+     * @param value
+     * @return
+     */
+    @SuppressWarnings("PMD.CyclomaticComplexity")
+    public static boolean isAssignableFrom(Class<?> ssuper, Class<?> value) {
+        if (ssuper.equals(boolean.class) || ssuper.equals(Boolean.class)) {
+            return value.equals(boolean.class) || value.equals(Boolean.class);
+        } else if (ssuper.equals(char.class) || ssuper.equals(Character.class)) {
+            return value.equals(char.class) || value.equals(Character.class);
+        } else if (ssuper.equals(byte.class) || ssuper.equals(Byte.class)) {
+            return value.equals(byte.class) || value.equals(Byte.class);
+        } else if (ssuper.equals(short.class) || ssuper.equals(Short.class)) {
+            return value.equals(short.class) || value.equals(Short.class);
+        } else if (ssuper.equals(int.class) || ssuper.equals(Integer.class)) {
+            return value.equals(int.class) || value.equals(Integer.class);
+        } else if (ssuper.equals(long.class) || ssuper.equals(Long.class)) {
+            return value.equals(long.class) || value.equals(Long.class);
+        } else if (ssuper.equals(float.class) || ssuper.equals(Float.class)) {
+            return value.equals(float.class) || value.equals(Float.class);
+        } else if (ssuper.equals(double.class) || ssuper.equals(Double.class)) {
+            return value.equals(double.class) || value.equals(Double.class);
+        } else {
+            return ssuper.isAssignableFrom(value);
+        }
+    }
+    
+    /**
+     * Grupowa wersja funkcji {@code Class.isAssignableFrom} - sprawdza, czy odpowiednie
+     * elementy z tablicy {@code supers} są assignable względem odpowiednich
+     * elementów {@code values}, czyli czy <br>
+     * {@code for(i) supers[i].isAssignableFrom( values[i] ) }
+     * Uwzględnia autoboxing argumentów.
+     * @param supers
+     * @param values
+     * @return
+     */
+    public static boolean isAssignableFrom(Class<?>[] supers, Class<?>[] values) {
+        if(supers.length != values.length) {
+            return false;
+        }
+        for(int i=0; i<supers.length; i++) {
+            if( !isAssignableFrom(supers[i], values[i]) ) { return false; }
+        }
+        return true;
+    }
+
+    /**
+     * Sprawdza, czy podany obiekt {@code get} jest instancją klasy {@code ssuper}.
+     * Uwzględnia autoboxing argumentów.
+     * @param ssuper
+     * @param value
+     * @return
+     */
+    public static boolean isInstance(Class<?> ssuper, Object value) {
+        return value==null || ssuper.isInstance(value) || box(ssuper).isInstance(value);
+    }
+
+    /**
+     * Sprawdza, czy odpowiednie obiekty z tablicy {@code values} są istancjami
+     * odpowiednich klas z tablicy {@code supers}. Uwzględnia autoboxing argumentów.
+     * @param supers
+     * @param values
+     * @return
+     */
+    public static boolean isInstance(Class<?>[] supers, Object[] values) {
+        if(supers.length != values.length) {
+            return false;
+        }
+        for(int i=0; i<supers.length; i++) {
+            if( !isInstance(supers[i], values[i]) ) { return false; }
+        }
+        return true;
+    }
+    
+    public static boolean isLoaded(String name) {
+        try {
+            return null != Li.FIND_LOADED_CLASS.invoke(Thread.currentThread().getContextClassLoader(), name);
+        } catch(ReflectiveOperationException roe) {
+            throw ExceptionInspector.rethrow(roe);
+        }
+    }
+    
+    private static final class Li { // NOPMD - lazy init idiom
+        
+        public static final java.lang.reflect.Method FIND_LOADED_CLASS;
+        
+        static {
+            try {
+                FIND_LOADED_CLASS = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[] { String.class });
+                FIND_LOADED_CLASS.setAccessible(true);
+            } catch(ReflectiveOperationException ex) {
+                throw ExceptionInspector.rethrow(ex);
+            }
+        }
+        
+    }
+    
+}

+ 109 - 0
assira/src/main/java/net/ranides/assira/trace/LoggerLevel.java

@@ -0,0 +1,109 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.trace;
+
+import java.util.function.IntPredicate;
+import org.slf4j.Logger;
+import static org.slf4j.spi.LocationAwareLogger.*;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public enum LoggerLevel implements IntPredicate {
+    
+    TRACE(TRACE_INT) {
+        @Override
+        public boolean isEnabled(Logger logger) {
+            return logger.isTraceEnabled();
+        }
+    },
+    DEBUG(DEBUG_INT) {
+        @Override
+        public boolean isEnabled(Logger logger) {
+            return logger.isDebugEnabled();
+        }
+    },
+    INFO(INFO_INT) {
+        @Override
+        public boolean isEnabled(Logger logger) {
+            return logger.isInfoEnabled();
+        }
+    },
+    WARN(WARN_INT) {
+        @Override
+        public boolean isEnabled(Logger logger) {
+            return logger.isWarnEnabled();
+        }
+    },
+    ERROR(ERROR_INT) {
+        @Override
+        public boolean isEnabled(Logger logger) {
+            return logger.isErrorEnabled();
+        }
+    },
+    UNKNOWN(Integer.MAX_VALUE) {
+        @Override
+        public boolean isEnabled(Logger logger) {
+            return true;
+        }
+    };
+    
+    private final int level;
+    
+    LoggerLevel(int level) {
+        this.level = level;
+    }
+    
+    public int level() {
+        return level;
+    }
+    
+    public abstract boolean isEnabled(Logger logger);
+    
+    @Override // NOPMD
+    public boolean test(int level) {
+        return level >= this.level;
+    }
+
+    public static LoggerLevel valueOf(Logger logger) {
+        if(logger.isTraceEnabled()) {
+            return TRACE;
+        }
+        if(logger.isDebugEnabled()) {
+            return DEBUG;
+        }
+        if(logger.isInfoEnabled()) {
+            return INFO;
+        }
+        if(logger.isWarnEnabled()) {
+            return WARN;
+        }
+        if(logger.isErrorEnabled()) {
+            return ERROR;
+        }
+        return UNKNOWN;
+    }
+    
+    public static LoggerLevel valueOf(int level) {
+        switch(level) {
+            case TRACE_INT:
+                return TRACE;
+            case DEBUG_INT:
+                return DEBUG;
+            case INFO_INT:
+                return INFO;
+            case WARN_INT:
+                return WARN;
+            case ERROR_INT:
+                return ERROR;
+            default:
+                return UNKNOWN;
+        }
+    }
+    
+}

+ 4 - 56
assira/src/main/java/net/ranides/assira/trace/LoggerUtils.java

@@ -6,8 +6,6 @@
  */
 package net.ranides.assira.trace;
 
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import org.slf4j.LoggerFactory;
 
 /**
@@ -16,66 +14,16 @@ import org.slf4j.LoggerFactory;
  */
 public final class LoggerUtils {
     
-    private LoggerUtils() { }
+    private LoggerUtils() {
+        /* utility class */
+    }
     
     /**
      * Returns logger for the "current" class, so you don't have to hardcode class name.
      * @return 
      */
     public static org.slf4j.Logger getLogger() {
-        return LoggerFactory.getLogger(Thread.currentThread().getStackTrace()[2].getClassName());
+        return LoggerFactory.getLogger(StackInspector.getCallerName());
     }
     
-    /**
-     * Returns logger printing messages with any logging level.
-     * <p><b>Warning:</b> It works only with manually invoked JUnit tests configured
-     * to use {@code slf4j-simple}. In other environments it works exactly in the 
-     * same way as {@link #getLogger()}. </p>
-     * @return 
-     */
-    public static org.slf4j.Logger getTraceLogger() {
-        if( isInsideSingleTest() ) {
-            initTraceLogger();
-        }
-        return LoggerFactory.getLogger(Thread.currentThread().getStackTrace()[2].getClassName());
-    }
-
-    private static boolean isInsideSingleTest() {
-        // we don't use RuntimeUtils because we must avoid slf4j initialization
-        return null != AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty("test"));
-    }
-
-    private static void initTraceLogger() throws AssertionError {
-        if( isLoaded("org.slf4j.impl.SimpleLogger") ) {
-            throw new AssertionError("org.slf4j.SimpleLogger is already loaded. You can't reconfigure it now.");
-        }
-        System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "trace");
-    }
-    
-    // @todo (assira #3) reflection: ClassInspector#isLoaded
-    // stworzyć metodę, jakkolwiek tutaj jej nie używać, bo nam Logger załaduje)
-    
-    private static boolean isLoaded(String name) {
-        try {
-            return null != Li.FIND_LOADED_CLASS.invoke(Thread.currentThread().getContextClassLoader(), name);
-        } catch(ReflectiveOperationException roe) {
-            throw ExceptionInspector.rethrow(roe);
-        }
-    }
-    
-    private static final class Li { // NOPMD - lazy init idiom
-        
-        public static final java.lang.reflect.Method FIND_LOADED_CLASS;
-        
-        static {
-            try {
-                FIND_LOADED_CLASS = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[] { String.class });
-                FIND_LOADED_CLASS.setAccessible(true);
-            } catch(ReflectiveOperationException ex) {
-                throw ExceptionInspector.rethrow(ex);
-            }
-        }
-        
-    }
-
 }

+ 23 - 20
assira/src/main/java/net/ranides/assira/trace/StackInspector.java

@@ -11,7 +11,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import net.ranides.assira.generic.ValueUtils;
-import net.ranides.assira.reflection.InspectException;
 
 /**
  * 
@@ -56,7 +55,9 @@ public final class StackInspector {
         RESOLVER_ES
     );
 
-    private StackInspector() { /* utility class */ }
+    private StackInspector() { 
+        /* utility class */ 
+    }
     
     public static List<StackTraceElement> getFrames() {
         return new FrameList();
@@ -95,24 +96,17 @@ public final class StackInspector {
     }
     
     @SuppressWarnings("PMD")
-    static List<StackTraceElement> test_getFramesArray() {
-        // we know that's incorrect, but we want to test performance, not "indexing"
-        // it will have 2~3 items more
-        return Arrays.asList(new Exception().getStackTrace());
-    }
-    
-    @SuppressWarnings("PMD")
-    static List<Class> test_getClassList(Resolver resolver) {
+    static List<Class> test_getTypes(Resolver resolver) {
         return resolver.list();
     }
     
     @SuppressWarnings("PMD")
-    static List<String> test_getClassNames(Resolver resolver) {
+    static List<String> test_getNames(Resolver resolver) {
         return resolver.names();
     }
     
 	@SuppressWarnings("PMD")
-    static Class test_getCalleeClass(Resolver resolver) {
+    static Class test_getCalleeType(Resolver resolver) {
         return resolver.callee();
     }
     
@@ -120,6 +114,16 @@ public final class StackInspector {
     static String test_getCalleeName(Resolver resolver) {
         return resolver.calleeName();
     }
+    
+    @SuppressWarnings("PMD")
+    static Class test_getCallerType(Resolver resolver) {
+        return resolver.caller();
+    }
+    
+	@SuppressWarnings("PMD")
+    static String test_getCallerName(Resolver resolver) {
+        return resolver.callerName();
+    }
 
     interface Resolver {
         
@@ -399,10 +403,13 @@ public final class StackInspector {
         
         private final Throwable cause;
         
+        private final int size;
+        
         private StackTraceElement[] array;
         
         public FrameList() {
             this.cause = new Throwable(); // NOPMD
+            this.size = ReflectFrame.depth(cause)-FIRST;
             this.array = null;
         }
         
@@ -419,10 +426,7 @@ public final class StackInspector {
         
         @Override
         public int size() {
-            if(null == array) {
-                array = new StackTraceElement[ReflectFrame.depth(cause)-FIRST];
-            }
-            return array.length;
+            return size;
         }
         
     }
@@ -441,7 +445,7 @@ public final class StackInspector {
                 DEPTH = Throwable.class.getDeclaredMethod("getStackTraceDepth");
                 DEPTH.setAccessible(true);
             } catch(ReflectiveOperationException ex) {
-                throw ExceptionInspector.rethrow(ex);
+                throw new UnsupportedOperationException(NSE, ex);
             }
         }
         
@@ -449,7 +453,7 @@ public final class StackInspector {
             try {
                 return (int)DEPTH.invoke(that);
             } catch(ReflectiveOperationException ex) {
-                throw new InspectException(ex);
+                throw new UnsupportedOperationException(NSE, ex);
             }
         }
         
@@ -458,8 +462,7 @@ public final class StackInspector {
 
                 return (StackTraceElement)GET.invoke(that, index);
             } catch(ReflectiveOperationException ex) {
-                ex.printStackTrace();
-                throw new InspectException(ex);
+                throw new UnsupportedOperationException(NSE, ex);
             }
         }
         

+ 2 - 2
assira/src/test/java/net/ranides/assira/events/EventLockTest.java

@@ -256,7 +256,7 @@ public class EventLockTest {
             main.signalEvent(new WriteEvent(203));
             main.signalEvent(new WriteEvent(204));
             
-            sleep(200);
+            sleep(1000);
             main.signalEvent(new ReadEvent(107));
             main.signalEvent(new ReadEvent(108));
             main.signalEvent(new ReadEvent(109));
@@ -264,7 +264,7 @@ public class EventLockTest {
              main.stop();
         }).start();
         
-        sleep(100);
+        sleep(500);
 
         assertEquals(201, lock.waitForEvent(IOEvent.class).handle());
         assertEquals(202, lock.waitForEvent(IOEvent.class).handle());

+ 66 - 10
assira/src/test/java/net/ranides/assira/io/IOUtilsTest.java

@@ -12,10 +12,14 @@ import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 import net.ranides.assira.events.Events;
 import net.ranides.assira.events.EventListener;
+import net.ranides.assira.junit.LogObserver;
+import static net.ranides.assira.junit.NewAssert.*;
 import net.ranides.assira.trace.LoggerUtils;
-import static org.junit.Assert.*;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 
 /**
@@ -24,30 +28,81 @@ import org.junit.Test;
  */
 public class IOUtilsTest {
     
-    public IOUtilsTest() {
+    private static final org.slf4j.Logger LOGGER = LoggerUtils.getLogger();
+    
+    @Before
+    public void init() {
+        LogObserver.reset(true);
     }
-
+    
+    @After
+    public void release() {
+        LogObserver.reset(false);
+    }
+    
+    @Test
+    public void testClose_Object() throws Exception {
+        List<Integer> out = new ArrayList<>();
+        
+        assertFalse( IOUtils.close((Object)null) );
+        assertTrue( IOUtils.close((Object) (Closeable)() -> { out.add(7); }) );
+        assertTrue( IOUtils.close((Object) (AutoCloseable)() -> { out.add(8); }) );
+        
+        assertEquals(Arrays.asList(7,8), out);
+                
+        assertThrows(IOException.class, ()->{
+            IOUtils.close((Object)new CFile());
+        });
+        assertThrows(SQLException.class, ()->{
+            IOUtils.close((Object)new SFile());
+        });
+    }
+    
     @Test
-    public void testCloseConsumer() {
+    public void testClose_Closeable() throws IOException {
+        List<Integer> out = new ArrayList<>();
+        
+        assertFalse( IOUtils.close((Closeable)null) );
+        assertTrue( IOUtils.close((Closeable)() -> { out.add(7); }) );
+        
+        assertEquals(Arrays.asList(7), out);
+                
+        assertThrows(IOException.class, ()->{
+            IOUtils.close(new CFile());
+        });
+    }
+ 
+    @Test
+    public void testClose_Consumer() {
         List<String> errors = new ArrayList<>();
         
         EventListener<Events.Failure> listener = (e) -> {
             errors.add(e.cause().toString());
         };
         
-        IOUtils.close(null, e -> Events.failure(e));
-        
+        // listener
         IOUtils.close(new CFile(), listener.consumer(e -> Events.failure(e)));
         
+        // listener
         IOUtils.close(new SFile(), listener.consumer(Events::failure));
         
-        IOUtils.close(new SFile(), null);
+        // real NOP - ignore exception silently
+        IOUtils.close(new SFile(), e -> {});
         
-        if(false) {
-            System.out.printf("%s%n", errors);
-        }
+        // "safe" NOP - write exception to log (with WARN level)
+        IOUtils.close(new SFile(), null);
+                
+        // explicit logger
+        IOUtils.close(new SFile(), e -> LOGGER.error("close!", e));
         
         assertEquals(Arrays.asList("java.io.IOException: IO", "java.sql.SQLException: SQL"), errors);
+        
+        assertTrue("WARN expected", LogObserver.match(m->
+            m.text().equals("[main] WARN net.ranides.assira.io.IOUtils - Exception ignored on #close @ java.sql.SQLException: SQL")
+        ));
+        assertTrue("ERROR expected", LogObserver.match(m->
+            m.text().equals("[main] ERROR net.ranides.assira.io.IOUtilsTest - close! @ java.sql.SQLException: SQL")
+        ));
     }
     
     private static final class CFile implements Closeable {
@@ -59,6 +114,7 @@ public class IOUtilsTest {
     
     }
     
+    
     private static final class SFile implements AutoCloseable {
 
         @Override

+ 476 - 4
assira/src/test/java/net/ranides/assira/text/StrBuilderTest.java

@@ -6,10 +6,13 @@
  */
 package net.ranides.assira.text;
 
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
 import java.util.Arrays;
 import java.util.List;
 import net.ranides.assira.collection.arrays.NativeArray;
-import org.junit.Assert;
+import static net.ranides.assira.junit.NewAssert.*;
 import org.junit.Test;
 
 /**
@@ -32,7 +35,7 @@ public class StrBuilderTest {
             .builder()
                 .open().append(list1, Integer::toHexString).close()
                 .endl()
-                .open().append(NativeArray.wrap(array), i -> Integer.toHexString(array[i])).close()
+                .open().append(array.length, i -> Integer.toHexString(array[i])).close()
                 .endl();
         sb
             .open("<", ">", ":").append(list2).close()
@@ -45,7 +48,7 @@ public class StrBuilderTest {
             .close()
             .endl();
                 
-        if(true) { // NOPMD
+        if(false) { // NOPMD
             System.out.printf("%s%n", sb.toString());
         }
         
@@ -55,7 +58,476 @@ public class StrBuilderTest {
             "<10:11:12:13>%n" +
             "[Q P [3 4 5] {3 4 5}]%n"
         );
-        Assert.assertEquals(expected, sb.toString());
+        assertEquals(expected, sb.toString());
+    }
+    
+    @Test
+    public void testOpenClose() {
+        StrBuilder sb = new StrBuilder();
+        
+        assertThrows(IllegalStateException.class, sb::close);
+        
+        List<Integer> list = Arrays.asList(1,2,3);
+        sb
+            .options().open("{").close("}").separator("-").builder()
+            .open().append(list).close().append(" ")
+            .open("<", ">", "+").append(list).append(" ")
+                .open("(", ")").append(list).append(" ")
+                    .open("//").append(list).append(" ").close()
+                .close()
+            .close();
+        
+        if(false) {
+            System.out.printf("%s%n", sb.toString());
+        }
+        assertEquals("{1-2-3} <1+2+3 (1+2+3 //1+2+3 ))>", sb.toString());
+        
+        assertThrows(IllegalStateException.class, sb::close);
+    }
+    
+    @Test
+    public void testOptions() {
+        StrBuilder sb = new StrBuilder();
+        
+        sb
+            .options().blank("b1").endl("o1").separator("c1").builder()
+            .open()
+                .options().blank("b2").endl("o2").builder()
+                .open()
+                    .options().blank("b3").builder();
+        
+        assertEquals("{ blank='62 33', endl='6F 32', separator='63 31', open='', close='' }", sb.options().toString());
+        sb.close();
+        assertEquals("{ blank='62 32', endl='6F 32', separator='63 31', open='', close='' }", sb.options().toString());
+        sb.close();
+        assertEquals("{ blank='62 31', endl='6F 31', separator='63 31', open='', close='' }", sb.options().toString());
+        
+        assertThrows(IllegalStateException.class, sb::close);
+        
+        sb
+            .options().blank("b1").endl("o1").separator("c1").builder()
+            .open()
+                .options().blank("b2").endl("o2").builder()
+                .open()
+                    .options().blank("b3").builder();
+        sb.clear();
+        assertEquals("{ blank='62 33', endl='6F 32', separator='63 31', open='', close='' }", sb.options().toString());
+        
+        assertThrows(IllegalStateException.class, sb::close);
+    }
+    
+    @Test
+    public void testAppend_String() {
+        StrBuilder builder = new StrBuilder();
+        builder.options().blank("-");
+        
+        // String
+        builder.append("Hello ");
+        builder.append((String)null );
+        builder.append("..world..", 2, 7);
+        builder.append((String)null, 1, 5);
+        
+        assertEquals("Hello -world-", builder.toString());
+        
+        // char
+        builder.append('!');
+        
+        // CharSequence
+        builder.append(cs(" Quick "));
+        builder.append((CharSequence)null);
+        builder.append(cs("..fox.."), 2, 5);
+        builder.append((CharSequence)null, 1, 5);
+        
+        assertEquals("Hello -world-! Quick -fox-", builder.toString());
+        
+        // StringBuffer
+        builder.append(new StringBuffer(" jumps "));
+        builder.append((StringBuffer)null);
+        builder.append(new StringBuffer("..over..."), 2, 6);
+        builder.append((StringBuffer)null, 1, 5);
+        
+        assertEquals("Hello -world-! Quick -fox- jumps -over-", builder.toString());
+        
+        // StringBuilder
+        builder.append(new StringBuilder(" lazy "));
+        builder.append((StringBuilder)null);
+        builder.append(new StringBuilder("..dog..."), 2, 5);
+        builder.append((StringBuilder)null, 1, 5);
+        
+        assertEquals("Hello -world-! Quick -fox- jumps -over- lazy -dog-", builder.toString());
+        
+    }
+    
+    @Test
+    public void testAppend_Chars() {
+        StrBuilder builder = new StrBuilder();
+        builder.options().blank("-");
+        
+        // char[]
+        builder.append("Quick ".toCharArray());
+        builder.append((char[])null);
+        builder.append("..fox..".toCharArray(), 2, 5);
+        builder.append((char[])null, 1, 5);
+        
+        assertEquals("Quick -fox-", builder.toString());
+        
+        // Object
+        builder.append(os(" jumps over lazy dog"));
+        builder.append((Object)null);
+        assertEquals("Quick -fox- jumps over lazy dog-", builder.toString());
+        
+    }
+    
+    @Test
+    public void testAppend_Primitive() {
+        StrBuilder builder = new StrBuilder();
+
+        // boolean
+        builder
+            .append(true).append(" ")
+            .append(false).append(" ");
+        assertEquals("true false ", builder.toString());
+        
+        // numbers
+        builder
+            .append(334).append(" ")
+            .append(8000L).append(" ")
+            .append(0.5f).append(" ")
+            .append(0.25).append(" ");
+            
+        assertEquals("true false 334 8000 0.5 0.25 ", builder.toString());
+    }
+    
+    @Test
+    public void testAppend_Iterable() {
+        StrBuilder builder = new StrBuilder();
+        builder.options()
+            .separator(",")
+            .blank("-")
+            .endl(" / ");
+        
+        // Iterable
+        builder.append(Arrays.asList("a","b","c")).endl();
+        builder.append(Arrays.asList("d")).endl();
+        builder.append(Arrays.asList()).endl();
+        
+        assertEquals("a,b,c / d /  / ", builder.toString());
+        
+        // Iterator
+        builder.append(Arrays.asList("A","B","C").iterator()).endl();
+        builder.append(Arrays.asList("D").iterator()).endl();
+        builder.append(Arrays.asList().iterator()).endl();
+        
+        assertEquals("a,b,c / d /  / A,B,C / D /  / ", builder.toString());
+        
+        // Iterable + Function
+        builder.append(Arrays.asList(11,12,13), v -> String.valueOf(v%10)).endl();
+        builder.append(Arrays.asList(14), v -> String.valueOf(v%10)).endl();
+        builder.append(Arrays.<Integer>asList(), v -> String.valueOf(v%10)).endl();
+        
+        assertEquals("a,b,c / d /  / A,B,C / D /  / 1,2,3 / 4 /  / ", builder.toString());
+        
+        // Iterator + Function
+        builder.append(Arrays.asList(11,12,13).iterator(), v -> String.valueOf(7 * (v%10))).endl();
+        builder.append(Arrays.asList(14).iterator(), v -> String.valueOf(7 * (v%10))).endl();
+        builder.append(Arrays.<Integer>asList().iterator(), v -> String.valueOf(7 * (v%10))).endl();
+        
+        assertEquals("a,b,c / d /  / A,B,C / D /  / 1,2,3 / 4 /  / 7,14,21 / 28 /  / ", builder.toString());
+    }
+    
+    @Test
+    public void testAppend_Array() {
+        StrBuilder builder = new StrBuilder();
+        builder.options()
+            .separator(",")
+            .blank("-")
+            .endl(" / ");
+        
+        // array
+        builder.append(new String[]{"a","b","c"}).endl();
+        builder.append(new String[]{"d"}).endl();
+        builder.append(new String[]{}).endl();
+        
+        assertEquals("a,b,c / d /  / ", builder.toString());
+        
+        // array + Function
+        builder.append(new Integer[]{11,12,13}, v -> String.valueOf(v%10)).endl();
+        builder.append(new Integer[]{14}, v -> String.valueOf(v%10)).endl();
+        builder.append(new Integer[]{}, v -> String.valueOf(v%10)).endl();
+        
+        assertEquals("a,b,c / d /  / 1,2,3 / 4 /  / ", builder.toString());
+        
+        // NativeArray
+        builder.append(NativeArray.wrap(new String[]{"A","B","C"})).endl();
+        builder.append(NativeArray.wrap(new String[]{"D"})).endl();
+        builder.append(NativeArray.wrap(new String[]{})).endl();
+        
+        assertEquals("a,b,c / d /  / 1,2,3 / 4 /  / A,B,C / D /  / ", builder.toString());
+        
+        // size + IntFunction
+        builder.append(3, v -> String.valueOf(7*(1+v)) ).endl();
+        builder.append(1, v -> String.valueOf(7*(1+v)) ).endl();
+        builder.append(0, v -> String.valueOf(7*(1+v)) ).endl();
+        
+        assertEquals("a,b,c / d /  / 1,2,3 / 4 /  / A,B,C / D /  / 7,14,21 / 7 /  / ", builder.toString());
+
+    }
+    
+    @Test
+    public void testReserve() {
+        StrBuilder sb = new StrBuilder(128);
+        sb.append("Hello world");
+        assertEquals(128, sb.capacity());
+        assertEquals(11, sb.length());
+        
+        sb.reserve(64);
+        assertEquals(128, sb.capacity());
+        sb.reserve(160);
+        assertEquals(256, sb.capacity());
+        sb.reserve(513);
+        assertEquals(513, sb.capacity());
+    }
+    
+    @Test
+    public void testTrim() {
+        StrBuilder sb = new StrBuilder(128);
+        sb.append("Hello world");
+        assertEquals(128, sb.capacity());
+        assertEquals(11, sb.length());
+        
+        sb.trim(64);
+        assertEquals(64, sb.capacity());
+        sb.trim();
+        assertEquals(11, sb.capacity());
+        
+        sb.reserve(128);
+        assertEquals(128, sb.capacity());
+        sb.trim(8);
+        assertEquals(11, sb.capacity());
+    }
+    
+    @Test
+    public void testResize() {
+        StrBuilder sb = new StrBuilder(128);
+        sb.append("Hello world");
+
+        sb.resize(8, '.');
+        assertEquals("Hello wo", sb.toString());
+                
+        sb.resize(12, '.');
+        assertEquals("Hello wo....", sb.toString());
+        
+        assertThrows(IllegalArgumentException.class, ()->{
+            sb.resize(-5, '.');
+        });
+        
+        sb.resize(0, '.');
+        assertEquals("", sb.toString());
+    }
+    
+    @Test
+    public void testClear() {
+        StrBuilder sb = new StrBuilder(8);
+        sb.append("Hello world");
+        assertEquals(16, sb.capacity());
+        assertEquals(11, sb.length());
+        
+        sb.clear();
+        assertEquals(16, sb.capacity());
+        assertEquals(0, sb.length());
+        assertEquals("", sb.toString());
+    }
+    
+    @Test
+    public void testSequence() {
+        StrBuilder sb = new StrBuilder().append("Hello world");
+        
+        StringTester.assertString("Hello world", sb);
+        StringTester.assertString("ello wo", sb.subSequence(1, 8));
+        
+        sb.setCharAt(0, 'h');
+        sb.setCharAt(1, 'a');
+        StringTester.assertString("hallo world", sb);
+        
+        assertThrows(IndexOutOfBoundsException.class, ()->{
+            sb.setCharAt(-1, 'z');
+        });
+        assertThrows(IndexOutOfBoundsException.class, ()->{
+            sb.setCharAt(53, 'z');
+        });
+    }
+    
+    @Test
+    public void testGetChars() {
+        StrBuilder sb = new StrBuilder(32).append("Hello world");
+        
+        assertArrayEquals("Hello world".toCharArray(), sb.getChars());
+        
+        assertArrayEquals("llo wo".toCharArray(), sb.getChars(2,8));
+        assertArrayEquals("".toCharArray(), sb.getChars(2,2));
+        assertThrows(IndexOutOfBoundsException.class, ()->{
+            sb.getChars(2,13);
+        });
+        assertThrows(IndexOutOfBoundsException.class, ()->{
+            sb.getChars(13,13);
+        });
+        assertThrows(IndexOutOfBoundsException.class, ()->{
+            sb.getChars(-1,3);
+        });
+        
+        char[] a = "###########...".toCharArray();
+        sb.getChars(a);
+        assertArrayEquals("Hello world...".toCharArray(), a);
+        
+        char[] b = "###########...".toCharArray();
+        sb.getChars(2,8,b,3);
+        assertArrayEquals("###llo wo##...".toCharArray(), b);
+    }
+    
+    @Test
+    public void testFragmet() {
+        StrBuilder sb = new StrBuilder(32).append("Hello world");
+        
+        assertEquals("", sb.getLeftFragment(0));
+        assertEquals("Hell", sb.getLeftFragment(4));
+        assertEquals("Hello world", sb.getLeftFragment(60));
+        
+        assertEquals("", sb.getRightFragment(0));
+        assertEquals("orld", sb.getRightFragment(4));
+        assertEquals("Hello world", sb.getRightFragment(60));
+    }
+    
+    @Test
+    public void testReverse() {
+        StrBuilder sb = new StrBuilder(32).append("Hello world");
+        
+        sb.reverse();
+        assertEquals("dlrow olleH", sb.toString());
+        sb.append("!");
+        assertEquals("dlrow olleH!", sb.toString());
+        sb.reverse();
+        sb.append("?");
+        assertEquals("!Hello world?", sb.toString());
+    }
+    
+    @Test
+    public void testToBuilder() {
+        StrBuilder sb = new StrBuilder(32).append("Hello world");
+        assertEquals("Hello world!", sb.toBuilder().append("!").toString());
+        assertEquals("Hello world", sb.toString());
+    }
+    
+    @Test
+    public void testEquals() {
+        StrBuilder a = new StrBuilder(16).append("Hello");
+        StrBuilder b = new StrBuilder(160).append("He").append("llo");
+        StrBuilder c = new StrBuilder(160).append("He").append("ll!");
+        
+        assertTrue(a.equals(a));
+        
+        assertFalse(a.equals(null));
+        assertFalse(a.equals(new Object()));
+        
+        assertFalse(a.equals(new StrBuilder(160).append("Hallo")));
+        assertFalse(a.equals(new StrBuilder(160).append("Hello!")));
+        
+        assertFalse(a.equals("Hello!"));
+        assertFalse(a.equals("Hella"));
+        
+        assertTrue(a.equals("Hello"));
+
+        assertTrue(a.equals(b));
+        assertEquality(a, b, c);
+    }
+    
+    @Test
+    public void testWriter() throws IOException {
+        StrBuilder sb = new StrBuilder();
+        Writer writer = sb.asWriter();
+        sb.append("Hello ");
+        
+        // #close should be NOP
+        writer.close(); 
+        
+        writer.write('w');
+        writer.write("orld. ".toCharArray());
+        writer.write("##tex..".toCharArray(), 2, 5);
+        writer.write("t :)");
+        writer.write("##EOF..", 2, 5);
+        
+        // we don't have to use #flush
+        
+        assertEquals("Hello world. text :)EOF", sb.toString());
+    }
+    
+    @Test
+    public void testReader() throws IOException {
+        StrBuilder sb = new StrBuilder();
+        Reader reader = sb.asReader();
+        sb.append("Hello world");
+        
+        // #close should be NOP
+        reader.close();
+        
+        int a = reader.read();
+        assertEquals('H', (char)a);
+        
+        char[] b = ".##...".toCharArray();
+        assertEquals(2, reader.read(b, 1, 2));
+        assertArrayEquals(".el...".toCharArray(), b);
+
+        assertEquals(0, reader.skip(-5));        
+        assertEquals(5, reader.skip(5));
+        
+        char[] c = ".###...".toCharArray();
+        assertEquals(3, reader.read(c, 1, 30));
+        assertArrayEquals(".rld...".toCharArray(), c);
+        
+        assertFalse(reader.ready());
+        assertEquals(0, reader.skip(3));
+        assertEquals(-1, reader.read());
+        
+        sb.append("!? ");
+        assertTrue(reader.ready());
+        assertEquals('!', (char)reader.read());
+        assertEquals(2, reader.skip(7));
+        assertFalse(reader.ready());
+        
+        sb.append("text.");
+        assertTrue(reader.ready());
+        assertTrue(reader.markSupported());
+        reader.mark(100);
+        char d[] = "-----".toCharArray();
+        assertEquals(5, reader.read(d, 0, 5));
+        assertArrayEquals("text.".toCharArray(), d);
+        
+        char e[] = "-----".toCharArray();
+        assertEquals(-1, reader.read(e, 0, 30));
+        assertEquals(-1, reader.read(e, 0, 30));
+        reader.reset();
+        assertEquals(5, reader.read(e, 0, 30));
+        assertArrayEquals("text.".toCharArray(), e);
+        
+        reader.close();
+    }
+    
+    @Test
+    public void testHashcode() {
+        assertEquals(Arrays.hashCode("Hello".toCharArray()), new StrBuilder(32).append("Hello").hashCode());
+    }
+
+    
+    private static CharSequence cs(String value) {
+        return StringUtils.wrap(value.toCharArray());
+    }
+    
+    private static Object os(String value) {
+        return new Object(){
+            @Override
+            public String toString() {
+                return value;
+            }
+        };
     }
     
 }

+ 176 - 0
assira/src/test/java/net/ranides/assira/trace/LoggerLevelTest.java

@@ -0,0 +1,176 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.trace;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.List;
+import net.ranides.assira.junit.LogMessage;
+import net.ranides.assira.junit.LogObserver;
+import static net.ranides.assira.junit.NewAssert.*;
+import net.ranides.assira.text.Wildcard;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.Before;
+import org.slf4j.Logger;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class LoggerLevelTest {
+    
+    private static final Logger LOGGER = LoggerUtils.getLogger();
+    
+    @Before
+    public void init() {
+        LogObserver.reset(true);
+    }
+    
+    @After
+    public void release() {
+        LogObserver.reset(false);
+    }
+    
+    @Test
+    public void testEnumInvariants() throws Exception {
+        assertEnumInvariants(LoggerLevel.class);
+    }
+    
+    @Test
+    public void testLogObserver() {
+        LOGGER.trace("m1");
+        LOGGER.debug("m2");
+        LOGGER.info("m3");
+        LOGGER.warn("m4");
+        LOGGER.error("m5");
+
+        LogMessage m1 = LogObserver.forText("[main] TRACE net.ranides.assira.trace.LoggerLevelTest - m1").findFirst().get();
+        LogMessage m5 = LogObserver.forText(Wildcard.compile("*5")).findFirst().get();
+        LogMessage m3 = LogObserver.forLevel(LoggerLevel.INFO::test).findFirst().get();        
+        LogMessage m2 = LogObserver.forLevel(LoggerLevel.DEBUG.level()).findFirst().get();
+        LogMessage m4 = LogObserver.forLevel(LoggerLevel.WARN).findFirst().get();
+        
+        
+        assertEquals("[main] TRACE net.ranides.assira.trace.LoggerLevelTest - m1", m1.text());
+        assertEquals("[main] DEBUG net.ranides.assira.trace.LoggerLevelTest - m2", m2.text());
+        assertEquals("[main] INFO net.ranides.assira.trace.LoggerLevelTest - m3", m3.text());
+        assertEquals("[main] WARN net.ranides.assira.trace.LoggerLevelTest - m4", m4.text());
+        assertEquals("[main] ERROR net.ranides.assira.trace.LoggerLevelTest - m5", m5.text());
+    }
+    
+    @Test
+    public void testGetFLogger() {
+        Logger r1 = getFLogger(LoggerLevel.INFO.level());
+        assertFalse(r1.isTraceEnabled() );
+        assertFalse(r1.isDebugEnabled() );
+        assertTrue(r1.isInfoEnabled() );
+        assertTrue(r1.isWarnEnabled() );
+        assertTrue(r1.isErrorEnabled() );
+    }
+    
+    @Test
+    public void testIsEnabled_Logger() {
+        Logger r1 = getFLogger(LoggerLevel.TRACE.level());
+
+        assertTrue( LoggerLevel.UNKNOWN.isEnabled(r1) );        
+        assertTrue( LoggerLevel.ERROR.isEnabled(r1) );
+        assertTrue( LoggerLevel.WARN.isEnabled(r1) );
+        assertTrue( LoggerLevel.INFO.isEnabled(r1) );
+        assertTrue( LoggerLevel.DEBUG.isEnabled(r1) );
+        assertTrue( LoggerLevel.TRACE.isEnabled(r1) );
+        
+        Logger r2 = getFLogger(LoggerLevel.WARN.level());
+        
+        assertTrue( LoggerLevel.UNKNOWN.isEnabled(r2) );
+        assertTrue( LoggerLevel.ERROR.isEnabled(r2) );
+        assertTrue( LoggerLevel.WARN.isEnabled(r2) );
+        assertFalse( LoggerLevel.INFO.isEnabled(r2) );
+        assertFalse( LoggerLevel.DEBUG.isEnabled(r2) );
+        assertFalse( LoggerLevel.TRACE.isEnabled(r2) );
+        
+    }
+    
+    @Test
+    public void testTestIntLevel() {
+        int r1 = LoggerLevel.TRACE.level();
+        
+        assertFalse( LoggerLevel.UNKNOWN.test(r1) );
+        assertFalse( LoggerLevel.ERROR.test(r1) );
+        assertFalse( LoggerLevel.WARN.test(r1) );
+        assertFalse( LoggerLevel.INFO.test(r1) );
+        assertFalse( LoggerLevel.DEBUG.test(r1) );
+        assertTrue( LoggerLevel.TRACE.test(r1) );
+        
+        
+        int r2 = LoggerLevel.INFO.level();
+
+        assertFalse( LoggerLevel.UNKNOWN.test(r2) );        
+        assertFalse( LoggerLevel.ERROR.test(r2) );
+        assertFalse( LoggerLevel.WARN.test(r2) );
+        assertTrue( LoggerLevel.INFO.test(r2) );
+        assertTrue( LoggerLevel.DEBUG.test(r2) );
+        assertTrue( LoggerLevel.TRACE.test(r2) );
+    }
+    
+    @Test
+    public void testValueOf_int() throws Exception {
+        LOGGER.trace("m1");
+        LOGGER.debug("m2");
+        LOGGER.info("m3");
+        LOGGER.warn("m4");
+        LOGGER.error("m5");
+        
+        List<LogMessage> ms = LogObserver.list();
+        assertEquals(LoggerLevel.TRACE, LoggerLevel.valueOf(ms.get(0).level()) );
+        assertEquals(LoggerLevel.DEBUG, LoggerLevel.valueOf(ms.get(1).level()) );
+        assertEquals(LoggerLevel.INFO, LoggerLevel.valueOf(ms.get(2).level()) );
+        assertEquals(LoggerLevel.WARN, LoggerLevel.valueOf(ms.get(3).level()) );
+        assertEquals(LoggerLevel.ERROR, LoggerLevel.valueOf(ms.get(4).level()) );
+        assertEquals(LoggerLevel.UNKNOWN, LoggerLevel.valueOf(13) );
+        assertEquals(LoggerLevel.UNKNOWN, LoggerLevel.valueOf(1113) );
+    }
+    
+    @Test
+    public void testValueOf_Logger() throws Exception {
+        Logger r1 = getFLogger(LoggerLevel.TRACE.level());
+        Logger r2 = getFLogger(LoggerLevel.DEBUG.level());
+        Logger r3 = getFLogger(LoggerLevel.INFO.level());
+        Logger r4 = getFLogger(LoggerLevel.WARN.level());
+        Logger r5 = getFLogger(LoggerLevel.ERROR.level());
+        Logger r6 = getFLogger(LoggerLevel.ERROR.level() + 20);
+        
+        assertEquals(LoggerLevel.TRACE, LoggerLevel.valueOf(r1) );
+        assertEquals(LoggerLevel.DEBUG, LoggerLevel.valueOf(r2) );
+        assertEquals(LoggerLevel.INFO, LoggerLevel.valueOf(r3) );
+        assertEquals(LoggerLevel.WARN, LoggerLevel.valueOf(r4) );
+        assertEquals(LoggerLevel.ERROR, LoggerLevel.valueOf(r5) );
+        assertEquals(LoggerLevel.UNKNOWN, LoggerLevel.valueOf(r6) );
+    }
+    
+    private static Logger getFLogger(int level) {
+        return (Logger)Proxy.newProxyInstance(Logger.class.getClassLoader(), new Class[]{Logger.class}, (Object proxy, Method method, Object[] args)->{
+            if(method.getName().equals("isTraceEnabled")) {
+                return level <= LoggerLevel.TRACE.level();
+            }
+            if(method.getName().equals("isDebugEnabled")) {
+                return level <= LoggerLevel.DEBUG.level();
+            }
+            if(method.getName().equals("isInfoEnabled")) {
+                return level <= LoggerLevel.INFO.level();
+            }
+            if(method.getName().equals("isWarnEnabled")) {
+                return level <= LoggerLevel.WARN.level();
+            }
+            if(method.getName().equals("isErrorEnabled")) {
+                return level <= LoggerLevel.ERROR.level();
+            }
+            throw new UnsupportedOperationException();
+        });
+    }
+    
+}

+ 26 - 60
assira/src/test/java/net/ranides/assira/trace/LoggerUtilsTest.java

@@ -1,60 +1,26 @@
-/*
- * @author Ranides Atterwim <ranides@gmail.com>
- * @copyright Ranides Atterwim
- * @license WTFPL
- * @url http://ranides.net/projects/assira
- */
-package net.ranides.assira.trace;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
-import net.ranides.assira.junit.NewAssert;
-import net.ranides.assira.system.RuntimeUtils;
-import net.ranides.assira.text.Charsets;
-import static org.junit.Assert.*;
-import org.junit.Test;
-import org.slf4j.Logger;
-
-/**
- *
- * @author msieron
- */
-
-
-public class LoggerUtilsTest {
-	
-	private static final String EXPECTED = String.format(
-		"[main] ERROR net.ranides.assira.trace.LoggerUtilsTest - Hello world!%n"
-	);
-	
-	public LoggerUtilsTest() {
-	}
-
-	@Test
-	public void testTraceLogger() throws UnsupportedEncodingException {
-		PrintStream preverr = System.err;
-		ByteArrayOutputStream output = new ByteArrayOutputStream();
-		System.setErr(new PrintStream(output, true, "UTF-8"));
-		
-		try {
-			Logger logger = LoggerUtils.getTraceLogger();
-
-			if( !RuntimeUtils.invokedInsideSingleTest()) {
-				return;
-			}
-
-			logger.error("Hello world!");
-			assertEquals(EXPECTED, output.toString(Charsets.UTF8.name()));
-
-			NewAssert.assertThrows(AssertionError.class, ()->{
-				LoggerUtils.getTraceLogger();
-			});
-
-		} finally {
-			System.setErr(preverr);
-		}
-		
-	}
-	
-}
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.trace;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class LoggerUtilsTest {
+    
+    private static final org.slf4j.Logger LOGGER = LoggerUtils.getLogger();
+
+    @Test
+    public void testLoggerName() {
+        assertEquals("net.ranides.assira.trace.LoggerUtilsTest", LOGGER.getName());
+        assertEquals("net.ranides.assira.trace.LoggerUtilsTest", LoggerUtils.getLogger().getName());
+    }
+    
+}

+ 14 - 6
assira/src/test/java/net/ranides/assira/trace/StackInspectorBenchmark.java

@@ -7,6 +7,8 @@
 package net.ranides.assira.trace;
 
 import com.google.caliper.SimpleBenchmark;
+import java.util.Arrays;
+import java.util.List;
 import net.ranides.assira.junit.BenchmarkRunner;
 
 /**
@@ -72,7 +74,7 @@ public class StackInspectorBenchmark extends SimpleBenchmark {
     public int timeFrameDefault(int reps) {
         int ret = 0;
         for(int i=0; i<reps; i++) {
-            ret += StackInspector.test_getFramesArray().get(1).getLineNumber();
+            ret += getFramesArray().get(1).getLineNumber();
         }
         return ret;
     }
@@ -90,7 +92,7 @@ public class StackInspectorBenchmark extends SimpleBenchmark {
     public int timeFrameListDefault(int reps) {
         int ret = 0;
         for(int i=0; i<reps; i++) {
-            for(StackTraceElement e : StackInspector.test_getFramesArray()) {
+            for(StackTraceElement e : getFramesArray()) {
                 ret += e.getLineNumber();
             }
         }
@@ -100,7 +102,7 @@ public class StackInspectorBenchmark extends SimpleBenchmark {
     public int timeListSecurityManager(int reps) {
         int ret = 0;
         for(int i=0; i<reps; i++) {
-            ret += StackInspector.test_getClassNames(StackInspector.RESOLVER_SM).size();
+            ret += StackInspector.test_getNames(StackInspector.RESOLVER_SM).size();
         }
         return ret;
     }
@@ -108,7 +110,7 @@ public class StackInspectorBenchmark extends SimpleBenchmark {
     public int timeListThread(int reps) {
         int ret = 0;
         for(int i=0; i<reps; i++) {
-            ret += StackInspector.test_getClassNames(StackInspector.RESOLVER_TS).size();
+            ret += StackInspector.test_getNames(StackInspector.RESOLVER_TS).size();
         }
         return ret;
     }
@@ -116,7 +118,7 @@ public class StackInspectorBenchmark extends SimpleBenchmark {
     public int timeListSunReflect(int reps) {
         int ret = 0;
         for(int i=0; i<reps; i++) {
-            ret += StackInspector.test_getClassNames(StackInspector.RESOLVER_SR).size();
+            ret += StackInspector.test_getNames(StackInspector.RESOLVER_SR).size();
         }
         return ret;
     }
@@ -124,7 +126,7 @@ public class StackInspectorBenchmark extends SimpleBenchmark {
     public int timeListException(int reps) {
         int ret = 0;
         for(int i=0; i<reps; i++) {
-            ret += StackInspector.test_getClassNames(StackInspector.RESOLVER_ES).size();
+            ret += StackInspector.test_getNames(StackInspector.RESOLVER_ES).size();
         }
         return ret;
     }
@@ -161,6 +163,12 @@ public class StackInspectorBenchmark extends SimpleBenchmark {
         return ret;
     }
     
+    private static List<StackTraceElement> getFramesArray() {
+        // we know that's incorrect, but we want to test performance, not semantic correctness
+        // it will have few (2-3) items more than should be
+        return Arrays.asList(new Exception().getStackTrace());
+    }
+    
     public static void main(String[] args) {
         BenchmarkRunner.run(StackInspectorBenchmark.class);
     }

+ 240 - 97
assira/src/test/java/net/ranides/assira/trace/StackInspectorTest.java

@@ -7,7 +7,8 @@
 package net.ranides.assira.trace;
 
 import java.util.List;
-import static org.junit.Assert.*;
+import static net.ranides.assira.junit.NewAssert.*;
+import net.ranides.assira.text.Wildcard;
 import org.junit.Test;
 
 /**
@@ -16,126 +17,268 @@ import org.junit.Test;
  */
 public class StackInspectorTest {
     
-    private static final Class<?> CALLER = StackInspectorTest.class;
+//    private static StackTraceElement innerFrame(int index) {
+//        return StackInspector.getFrames().get(index);
+//    }
+//    
+//    private static List<StackTraceElement> innerFrames() {
+//        return StackInspector.getFrames();
+//    }
+//    
+    @Test
+    public void testCallerType() {
+        assertTrue( SI0.runCallerType0() );
+    }
+    
+    @Test
+    public void testCalleeType() {
+        assertTrue( SI0.runCalleeType0() );
+    }
     
-    private static StackTraceElement innerFrame(int index) {
-        return StackInspector.getFrames().get(index);
+    @Test
+    public void testCallerName() {
+        assertTrue( SI0.runCallerName0() );
     }
     
-    private static List<StackTraceElement> innerFrames() {
-        return StackInspector.getFrames();
+    @Test
+    public void testCalleeName() {
+        assertTrue( SI0.runCalleeName0() );
     }
     
     @Test
-    public void testCallerClass() {
-        Class callerAuto = StackInspector.getCalleeType();
-        Class callerSM   = StackInspector.test_getCalleeClass(StackInspector.RESOLVER_SM);
-        Class callerSR   = StackInspector.test_getCalleeClass(StackInspector.RESOLVER_SR);
-                
-        assertEquals(CALLER, callerAuto);
-        assertEquals(CALLER, callerSM);
-        assertEquals(CALLER, callerSR);
+    public void testGetTypes0() {
+        assertTrue( SI0.runGetTypes0() );
     }
     
     @Test
-    public void testCallerClassName() {
-        String callerAuto = StackInspector.getCalleeName();
-        String callerSM   = StackInspector.test_getCalleeName(StackInspector.RESOLVER_SM);
-        String callerSR   = StackInspector.test_getCalleeName(StackInspector.RESOLVER_SR);
-        String callerTS   = StackInspector.test_getCalleeName(StackInspector.RESOLVER_TS);
-        String callerES   = StackInspector.test_getCalleeName(StackInspector.RESOLVER_ES);
-        
-        assertEquals(CALLER.getName(), callerAuto);
-        assertEquals(CALLER.getName(), callerSM);
-        assertEquals(CALLER.getName(), callerSR);
-        assertEquals(CALLER.getName(), callerTS);
-        assertEquals(CALLER.getName(), callerES);
+    public void testGetNames() {
+        assertTrue( SI0.runGetNames0() );
     }
-
+    
     @Test
-    public void testClassList() {
-        List<Class> listAuto = StackInspector.getTypes();
-        List<Class> listSM   = StackInspector.test_getClassList(StackInspector.RESOLVER_SM);
-        List<Class> listSR   = StackInspector.test_getClassList(StackInspector.RESOLVER_SR);
-        
-        if(false) { //NOPMD
-            dump(listAuto);
-            dump(listSM);
-            dump(listSR);
+    public void testFrame() {
+        assertTrue( SI0.runFrame0() );
+    }
+    
+    private static final class SI0 {
+        
+        private SI0() { /* utility class */ }
+        
+        public static boolean runCallerType0() {
+            SI1.runCallerType1();
+            return true;
         }
         
-        assertTrue(
-            listAuto.equals(listSM) ||
-            listAuto.equals(listSR)
-        );
-
-        assertEquals(listSM, listSR);
+        public static boolean runCalleeType0() {
+            SI1.runCalleeType1();
+            return true;
+        }
         
-        assertTrue(listSM.size() > 5);
+        public static boolean runCallerName0() {
+            SI1.runCallerName1();
+            return true;
+        }
+        
+        public static boolean runCalleeName0() {
+            SI1.runCalleeName1();
+            return true;
+        }
+        
+        public static boolean runGetTypes0() {
+            SI1.runGetTypes1();
+            return true;
+        }
+        
+        public static boolean runGetNames0() {
+            SI1.runGetNames1();
+            return true;
+        }
         
-        assertEquals(CALLER, listSM.get(0));
-        assertEquals(CALLER, listSR.get(0));
+        public static boolean runFrame0() {
+            SI1.runFrame1();
+            return true;
+        }
         
-        assertFalse(CALLER.equals(listSM.get(1)));
-        assertFalse(CALLER.equals(listSR.get(1)));
     }
+    
+    private static final class SI1 {
+        
+        private SI1() { /* utility class */ }
+        
+        public static void runCallerType1() {
+            Class<?> caller = SI0.class;
 
-    @Test
-    public void testClassNames() {
-        List<String> listAuto = StackInspector.getNames();
-        List<String> listSM  = StackInspector.test_getClassNames(StackInspector.RESOLVER_SM);
-        List<String> listSR  = StackInspector.test_getClassNames(StackInspector.RESOLVER_SR);
-        List<String> listTS  = StackInspector.test_getClassNames(StackInspector.RESOLVER_TS);
-        List<String> listES  = StackInspector.test_getClassNames(StackInspector.RESOLVER_ES);
-        
-        if(false) { //NOPMD
-            dump(listAuto);
-            dump(listSM);
-            dump(listSR);
-            dump(listTS);
-            dump(listES);
+            Class callerAuto = StackInspector.getCallerType();
+            Class callerSM   = StackInspector.test_getCallerType(StackInspector.RESOLVER_SM);
+            Class callerSR   = StackInspector.test_getCallerType(StackInspector.RESOLVER_SR);
+
+            assertEquals(caller, callerAuto);
+            assertEquals(caller, callerSM);
+            assertEquals(caller, callerSR);
+            
+            assertThrows(UnsupportedOperationException.class, ()->{
+                StackInspector.test_getCallerType(StackInspector.RESOLVER_TS);
+            });
+            assertThrows(UnsupportedOperationException.class, ()->{
+                StackInspector.test_getCallerType(StackInspector.RESOLVER_ES);
+            });
+        }
+        
+        public static void runCalleeType1() {
+            Class<?> callee = SI1.class;
+
+            Class calleeAuto = StackInspector.getCalleeType();
+            Class calleeSM   = StackInspector.test_getCalleeType(StackInspector.RESOLVER_SM);
+            Class calleeSR   = StackInspector.test_getCalleeType(StackInspector.RESOLVER_SR);
+
+            assertEquals(callee, calleeAuto);
+            assertEquals(callee, calleeSM);
+            assertEquals(callee, calleeSR);
+            
+            assertThrows(UnsupportedOperationException.class, ()->{
+                StackInspector.test_getCalleeType(StackInspector.RESOLVER_TS);
+            });
+            assertThrows(UnsupportedOperationException.class, ()->{
+                StackInspector.test_getCalleeType(StackInspector.RESOLVER_ES);
+            });
         }
         
-        assertTrue(
-            listAuto.equals(listSM) ||
-            listAuto.equals(listSR) ||
-            listAuto.equals(listTS) ||
-            listAuto.equals(listES) 
-        );
+        public static void runCallerName1() {
+            String caller = SI0.class.getName();
+            
+            String callerAuto = StackInspector.getCallerName();
+            String callerSM   = StackInspector.test_getCallerName(StackInspector.RESOLVER_SM);
+            String callerSR   = StackInspector.test_getCallerName(StackInspector.RESOLVER_SR);
+            String callerTS   = StackInspector.test_getCallerName(StackInspector.RESOLVER_TS);
+            String callerES   = StackInspector.test_getCallerName(StackInspector.RESOLVER_ES);
+
+            assertEquals(caller, callerAuto);
+            assertEquals(caller, callerSM);
+            assertEquals(caller, callerSR);
+            assertEquals(caller, callerTS);
+            assertEquals(caller, callerES);
+        }
         
-        assertEquals(listSM, listSR);
-        assertEquals(listTS, listES);
+        public static void runCalleeName1() {
+            String callee = SI1.class.getName();
+            
+            String calleeAuto = StackInspector.getCalleeName();
+            String calleeSM   = StackInspector.test_getCalleeName(StackInspector.RESOLVER_SM);
+            String calleeSR   = StackInspector.test_getCalleeName(StackInspector.RESOLVER_SR);
+            String calleeTS   = StackInspector.test_getCalleeName(StackInspector.RESOLVER_TS);
+            String calleeES   = StackInspector.test_getCalleeName(StackInspector.RESOLVER_ES);
+
+            assertEquals(callee, calleeAuto);
+            assertEquals(callee, calleeSM);
+            assertEquals(callee, calleeSR);
+            assertEquals(callee, calleeTS);
+            assertEquals(callee, calleeES);
+        }
         
-        assertTrue(listSM.size() > 5);
-        assertTrue(listSM.size() <= listTS.size());
+        public static void runGetTypes1() {
+            Class<?> callee = SI1.class;
+            Class<?> caller = SI0.class;
+                    
+            List<Class> listAuto = StackInspector.getTypes();
+            List<Class> listSM   = StackInspector.test_getTypes(StackInspector.RESOLVER_SM);
+            List<Class> listSR   = StackInspector.test_getTypes(StackInspector.RESOLVER_SR);
+
+            if(false) { //NOPMD
+                dump(listAuto);
+                dump(listSM);
+                dump(listSR);
+            }
+
+            assertTrue(
+                listAuto.equals(listSM) ||
+                listAuto.equals(listSR)
+            );
+
+            assertEquals(listSM, listSR);
+
+            assertTrue(listSM.size() > 5);
+
+            assertEquals(callee, listSM.get(0));
+            assertEquals(callee, listSR.get(0));
+            
+            assertEquals(caller, listSM.get(1));
+            assertEquals(caller, listSR.get(1));
+            
+            assertThrows(UnsupportedOperationException.class, ()->{
+                StackInspector.test_getTypes(StackInspector.RESOLVER_TS);
+            });
+            assertThrows(UnsupportedOperationException.class, ()->{
+                StackInspector.test_getTypes(StackInspector.RESOLVER_ES);
+            });
+        }
         
-        assertEquals(CALLER.getName(), listSM.get(0));
-        assertEquals(CALLER.getName(), listSR.get(0));
-        assertEquals(CALLER.getName(), listTS.get(0));
-        assertEquals(CALLER.getName(), listES.get(0));
+        public static void runGetNames1() {
+            String callee = SI1.class.getName();
+            String caller = SI0.class.getName();
+            
+            List<String> listAuto = StackInspector.getNames();
+            List<String> listSM  = StackInspector.test_getNames(StackInspector.RESOLVER_SM);
+            List<String> listSR  = StackInspector.test_getNames(StackInspector.RESOLVER_SR);
+            List<String> listTS  = StackInspector.test_getNames(StackInspector.RESOLVER_TS);
+            List<String> listES  = StackInspector.test_getNames(StackInspector.RESOLVER_ES);
+
+            if(false) { //NOPMD
+                dump(listAuto);
+                dump(listSM);
+                dump(listSR);
+                dump(listTS);
+                dump(listES);
+            }
+
+            assertTrue(
+                listAuto.equals(listSM) ||
+                listAuto.equals(listSR) ||
+                listAuto.equals(listTS) ||
+                listAuto.equals(listES) 
+            );
+
+            assertEquals(listSM, listSR);
+            assertEquals(listTS, listES);
+
+            assertTrue(listSM.size() > 5);
+            assertTrue(listSM.size() <= listTS.size());
+
+            assertEquals(callee, listSM.get(0));
+            assertEquals(callee, listSR.get(0));
+            assertEquals(callee, listTS.get(0));
+            assertEquals(callee, listES.get(0));
+
+            assertEquals(caller, listSM.get(1));
+            assertEquals(caller, listSR.get(1));
+            assertEquals(caller, listTS.get(1));
+            assertEquals(caller, listES.get(1));
+        }
         
-        assertFalse(CALLER.getName().equals(listSM.get(1)));
-        assertFalse(CALLER.getName().equals(listSR.get(1)));
-        assertFalse(CALLER.getName().equals(listTS.get(1)));
-        assertFalse(CALLER.getName().equals(listES.get(1)));
-    }
-    
-    @Test
-    public void testFrame() {
-        String t1 = "net.ranides.assira.trace.StackInspectorTest.innerFrame(StackInspectorTest.java:22)";
-        String t2 = "net.ranides.assira.trace.StackInspectorTest.testFrame(StackInspectorTest.java:128)";
-        assertEquals(t1, innerFrame(0).toString());
-        assertEquals(t2, innerFrame(1).toString());
-        assertFalse(innerFrame(2).toString().startsWith("net.ranides"));
-    }
-    
-    @Test
-    public void testFrames() {
-        String t1 = "net.ranides.assira.trace.StackInspectorTest.innerFrames(StackInspectorTest.java:26)";
-        String t2 = "net.ranides.assira.trace.StackInspectorTest.testFrames(StackInspectorTest.java:137)";
-        assertEquals(t1, innerFrames().get(0).toString());
-        assertEquals(t2, innerFrames().get(1).toString());
-        assertFalse(innerFrames().get(2).toString().startsWith("net.ranides"));
+        public static void runFrame1() {
+            List<StackTraceElement> frames = StackInspector.getFrames();
+            List<String> names = StackInspector.test_getNames(StackInspector.RESOLVER_TS);
+            
+            if(false) { // NOPMD
+                System.out.printf("frames = %d%n", frames.size());
+                System.out.printf("names = %d%n", names.size());
+                dump(frames);
+                dump(names);
+            }
+            
+            Wildcard callee = Wildcard.compile("net.ranides.assira.trace.StackInspectorTest$SI1.runFrame1(StackInspectorTest.java:*)");
+            Wildcard caller = Wildcard.compile("net.ranides.assira.trace.StackInspectorTest$SI0.runFrame0(StackInspectorTest.java:*)");
+            Wildcard frame2 = Wildcard.compile("net.ranides.assira.trace.StackInspectorTest.testFrame(StackInspectorTest.java:*)");
+
+            assertTrue(callee.test(StackInspector.getCalleeFrame().toString()));
+            assertTrue(caller.test(StackInspector.getCallerFrame().toString()));
+
+            assertTrue(callee.test(frames.get(0).toString()));
+            assertTrue(caller.test(frames.get(1).toString()));
+            assertTrue(frame2.test(frames.get(2).toString()));
+
+            assertEquals(frames.size(), names.size());
+        }
+
     }
     
     @SuppressWarnings("PMD")