From: Niki Roo Date: Tue, 30 Apr 2019 16:49:35 +0000 (+0200) Subject: now mostly streamified! X-Git-Url: http://git.nikiroo.be/?p=nikiroo-utils.git;a=commitdiff_plain;h=d2219aa05bbcc5603e90aa69220fecb4a6a41f55 now mostly streamified! --- diff --git a/changelog.md b/changelog.md index 0860480..4223b1b 100644 --- a/changelog.md +++ b/changelog.md @@ -8,9 +8,10 @@ - fix: IOUtils.readSmallStream and \n at the end - fix: Base64 implementation changed - change: serial: SSL -> CryptUtils -- change: MarkableFileInputStream moved to nikiroo.utils.streams -- change: Break compat with package utils.server (small change, Version not used anymore) -- change: Break compat with base64 methods in StringUtils (now it works correctly, too) +- change: markableFileInputStream moved to nikiroo.utils.streams +- change: break compat with package utils.server +- change: break compat with base64 methods in StringUtils (now it works correctly, too) +- change: TestLauncher is now "silent" by default (no exception details, see setDetails(true)) ## Version 4.7.2 diff --git a/src/be/nikiroo/utils/serial/CustomSerializer.java b/src/be/nikiroo/utils/serial/CustomSerializer.java index 496fcb1..e58ccf2 100644 --- a/src/be/nikiroo/utils/serial/CustomSerializer.java +++ b/src/be/nikiroo/utils/serial/CustomSerializer.java @@ -4,10 +4,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import be.nikiroo.utils.IOUtils; import be.nikiroo.utils.streams.BufferedInputStream; -import be.nikiroo.utils.streams.NextableInputStream; -import be.nikiroo.utils.streams.NextableInputStreamStep; import be.nikiroo.utils.streams.ReplaceInputStream; import be.nikiroo.utils.streams.ReplaceOutputStream; @@ -78,7 +75,12 @@ public abstract class CustomSerializer { protected abstract String getType(); /** - * Encode the object into the given {@link OutputStream}. + * Encode the object into the given {@link OutputStream}, i.e., generate the + * ENCODED_VALUE part. + *

+ * Use whatever scheme you wish, the system shall ensure that the content is + * correctly encoded and that you will receive the same content at decode + * time. * * @param out * the builder to append to @@ -105,6 +107,14 @@ public abstract class CustomSerializer { /** * Decode the value back into the supported object type. + *

+ * We do not expect the full content here but only: + *

+ * That is, we do not expect the "custom^TYPE^" + * part. * * @param in * the encoded value @@ -120,56 +130,12 @@ public abstract class CustomSerializer { new String[] { "\\", "\n" }); try { - NextableInputStream stream = new NextableInputStream( - replace.open(), new NextableInputStreamStep('^')); - try { - if (!stream.next()) { - throw new IOException( - "Cannot find the first custom^ element"); - } - - String custom = IOUtils.readSmallStream(stream); - if (!"custom".equals(custom)) { - throw new IOException( - "Cannot find the first custom^ element, it is: " - + custom + "^"); - } - - if (!stream.next()) { - throw new IOException("Cannot find the second custom^" - + getType() + " element"); - } - - String type = IOUtils.readSmallStream(stream); - if (!getType().equals(type)) { - throw new IOException("Cannot find the second custom^" - + getType() + " element, it is: custom^" + type - + "^"); - } - - if (!stream.nextAll()) { - throw new IOException("Cannot find the third custom^" - + getType() + "^value element"); - } - - return fromStream(stream); - } finally { - stream.close(); - } + return fromStream(replace); } finally { replace.close(false); } } - /** Use {@link CustomSerializer#isCustom(BufferedInputStream)}. */ - @Deprecated - public static boolean isCustom(String encodedValue) { - int pos1 = encodedValue.indexOf('^'); - int pos2 = encodedValue.indexOf('^', pos1 + 1); - - return pos1 >= 0 && pos2 >= 0 && encodedValue.startsWith("custom^"); - } - public static boolean isCustom(BufferedInputStream in) throws IOException { return in.startsWith("custom^"); } diff --git a/src/be/nikiroo/utils/serial/Importer.java b/src/be/nikiroo/utils/serial/Importer.java index 6718fb8..2608db2 100644 --- a/src/be/nikiroo/utils/serial/Importer.java +++ b/src/be/nikiroo/utils/serial/Importer.java @@ -169,65 +169,93 @@ public class Importer { // Custom objects if (CustomSerializer.isCustom(in)) { // not a field value but a direct value - String line = IOUtils.readSmallStream(in); - me = SerialUtils.decode(line); + me = SerialUtils.decode(in); return false; } - // TODO use the stream, Luke - // .. at least for REF - String line = IOUtils.readSmallStream(in); - - if (line.startsWith("REF ")) { // REF: create/link self - // TODO: here, line is REF type@999:xxx + // REF: (object) + if (in.startsWith("REF ")) { // REF: create/link self + // here, line is REF type@999:xxx // xxx is optional - // note: use .end() when containsKey(ref) - String[] tab = line.substring("REF ".length()).split("@"); - String type = tab[0]; - tab = tab[1].split(":"); - String ref = tab[0]; - - link = map.containsKey(ref); - if (link) { - me = map.get(ref); - } else { - if (line.endsWith(":")) { - // construct - me = SerialUtils.createObject(type); + + NextableInputStream stream = new NextableInputStream(in, + new NextableInputStreamStep(':')); + try { + stream.next(); + + stream.skip("REF ".length()); + String header = IOUtils.readSmallStream(stream); + + String[] tab = header.split("@"); + if (tab.length != 2) { + throw new IOException("Bad import header line: " + header); + } + String type = tab[0]; + String ref = tab[1]; + + stream.nextAll(); + + link = map.containsKey(ref); + if (link) { + me = map.get(ref); + stream.end(); } else { - // direct value - int pos = line.indexOf(":"); - String encodedValue = line.substring(pos + 1); - me = SerialUtils.decode(encodedValue); + if (stream.eof()) { + // construct + me = SerialUtils.createObject(type); + } else { + // direct value + me = SerialUtils.decode(stream); + } + map.put(ref, me); } - map.put(ref, me); + } finally { + stream.close(false); } - } else { // FIELD: new field *or* direct simple value - if (line.endsWith(":")) { - // field value is compound - currentFieldName = line.substring(0, line.length() - 1); - } else if (line.startsWith(":") || !line.contains(":") - || line.startsWith("\"")) { - // not a field value but a direct value - me = SerialUtils.decode(line); - } else { - // field value is direct - int pos = line.indexOf(":"); - String fieldName = line.substring(0, pos); - String encodedValue = line.substring(pos + 1); - Object value = null; - value = SerialUtils.decode(encodedValue); - - // To support simple types directly: - if (me == null) { - me = value; + + return false; + } + + if (SerialUtils.isDirectValue(in)) { + // not a field value but a direct value + me = SerialUtils.decode(in); + return false; + } + + if (in.startsWith("^")) { + in.skip(1); + + NextableInputStream nameThenContent = new NextableInputStream(in, + new NextableInputStreamStep(':')); + + try { + nameThenContent.next(); + String fieldName = IOUtils.readSmallStream(nameThenContent); + + if (nameThenContent.next() && !nameThenContent.eof()) { + // field value is direct or custom + Object value = null; + value = SerialUtils.decode(nameThenContent); + + // To support simple types directly: + if (me == null) { + me = value; + } else { + setField(fieldName, value); + } } else { - setField(fieldName, value); + // field value is compound + currentFieldName = fieldName; } + } finally { + nameThenContent.close(false); } + + return false; } - return false; + String line = IOUtils.readSmallStream(in); + throw new IOException("Line cannot be processed: <" + line + ">"); } private void setField(String name, Object value) diff --git a/src/be/nikiroo/utils/serial/SerialUtils.java b/src/be/nikiroo/utils/serial/SerialUtils.java index 6f85173..43aafb2 100644 --- a/src/be/nikiroo/utils/serial/SerialUtils.java +++ b/src/be/nikiroo/utils/serial/SerialUtils.java @@ -1,6 +1,5 @@ package be.nikiroo.utils.serial; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.NotSerializableException; @@ -21,6 +20,7 @@ import be.nikiroo.utils.Image; import be.nikiroo.utils.StringUtils; import be.nikiroo.utils.streams.Base64InputStream; import be.nikiroo.utils.streams.Base64OutputStream; +import be.nikiroo.utils.streams.BufferedInputStream; import be.nikiroo.utils.streams.NextableInputStream; import be.nikiroo.utils.streams.NextableInputStreamStep; @@ -359,7 +359,7 @@ public class SerialUtils { continue; } - write(out, "\n"); + write(out, "\n^"); write(out, field.getName()); write(out, ":"); @@ -418,26 +418,28 @@ public class SerialUtils { } else if (value instanceof Boolean) { write(out, value); } else if (value instanceof Byte) { - write(out, value); write(out, "b"); + write(out, value); } else if (value instanceof Character) { - encodeString(out, "" + value); write(out, "c"); + encodeString(out, "" + value); } else if (value instanceof Short) { - write(out, value); write(out, "s"); + write(out, value); } else if (value instanceof Integer) { + write(out, "i"); write(out, value); } else if (value instanceof Long) { + write(out, "l"); write(out, value); - write(out, "L"); } else if (value instanceof Float) { + write(out, "f"); write(out, value); - write(out, "F"); } else if (value instanceof Double) { - write(out, value); write(out, "d"); + write(out, value); } else if (value instanceof Enum) { + write(out, "E:"); String type = value.getClass().getCanonicalName(); write(out, type); write(out, "."); @@ -450,12 +452,85 @@ public class SerialUtils { return true; } + static boolean isDirectValue(BufferedInputStream encodedValue) + throws IOException { + if (CustomSerializer.isCustom(encodedValue)) { + return false; + } + + for (String fullValue : new String[] { "NULL", "null", "true", "false" }) { + if (encodedValue.is(fullValue)) { + return true; + } + } + + // TODO: Not efficient + for (String prefix : new String[] { "c\"", "\"", "b", "s", "i", "l", + "f", "d", "E:" }) { + if (encodedValue.startsWith(prefix)) { + return true; + } + } + + return false; + } + /** * Decode the data into an equivalent supported source object. *

* A supported object in this context means an object we can directly - * encode, like an Integer or a String. Custom objects and arrays are also - * considered supported, but compound objects are not supported here. + * encode, like an Integer or a String (see + * {@link SerialUtils#decode(String)}. + *

+ * Custom objects and arrays are also considered supported here, but + * compound objects are not. + *

+ * For compound objects, you should use {@link Importer}. + * + * @param encodedValue + * the encoded data, cannot be NULL + * + * @return the object (can be NULL for NULL encoded values) + * + * @throws IOException + * if the content cannot be converted + */ + static Object decode(BufferedInputStream encodedValue) throws IOException { + if (CustomSerializer.isCustom(encodedValue)) { + // custom^TYPE^ENCODED_VALUE + NextableInputStream content = new NextableInputStream(encodedValue, + new NextableInputStreamStep('^')); + try { + content.next(); + @SuppressWarnings("unused") + String custom = IOUtils.readSmallStream(content); + content.next(); + String type = IOUtils.readSmallStream(content); + content.nextAll(); + if (customTypes.containsKey(type)) { + return customTypes.get(type).decode(content); + } + content.end(); + throw new IOException("Unknown custom type: " + type); + } finally { + content.close(false); + // TODO: check what happens with thrown Exception in finally + encodedValue.end(); + } + } + + String encodedString = IOUtils.readSmallStream(encodedValue); + return decode(encodedString); + } + + /** + * Decode the data into an equivalent supported source object. + *

+ * A supported object in this context means an object we can directly + * encode, like an Integer or a String. + *

+ * For custom objects and arrays, you should use + * {@link SerialUtils#decode(InputStream)} or directly {@link Importer}. *

* For compound objects, you should use {@link Importer}. * @@ -471,48 +546,36 @@ public class SerialUtils { try { String cut = ""; if (encodedValue.length() > 1) { - cut = encodedValue.substring(0, encodedValue.length() - 1); + cut = encodedValue.substring(1); } - if (CustomSerializer.isCustom(encodedValue)) { - // custom:TYPE_NAME:"content is String-encoded" - String type = CustomSerializer.typeOf(encodedValue); - if (customTypes.containsKey(type)) { - // TODO: we should start with a stream - InputStream streamEncodedValue = new ByteArrayInputStream( - StringUtils.getBytes(encodedValue)); - try { - return customTypes.get(type).decode(streamEncodedValue); - } finally { - streamEncodedValue.close(); - } - } - throw new IOException("Unknown custom type: " + type); - } else if (encodedValue.equals("NULL") - || encodedValue.equals("null")) { + if (encodedValue.equals("NULL") || encodedValue.equals("null")) { return null; - } else if (encodedValue.endsWith("\"")) { + } else if (encodedValue.startsWith("\"")) { return decodeString(encodedValue); } else if (encodedValue.equals("true")) { return true; } else if (encodedValue.equals("false")) { return false; - } else if (encodedValue.endsWith("b")) { + } else if (encodedValue.startsWith("b")) { return Byte.parseByte(cut); - } else if (encodedValue.endsWith("c")) { + } else if (encodedValue.startsWith("c")) { return decodeString(cut).charAt(0); - } else if (encodedValue.endsWith("s")) { + } else if (encodedValue.startsWith("s")) { return Short.parseShort(cut); - } else if (encodedValue.endsWith("L")) { + } else if (encodedValue.startsWith("l")) { return Long.parseLong(cut); - } else if (encodedValue.endsWith("F")) { + } else if (encodedValue.startsWith("f")) { return Float.parseFloat(cut); - } else if (encodedValue.endsWith("d")) { + } else if (encodedValue.startsWith("d")) { return Double.parseDouble(cut); - } else if (encodedValue.endsWith(";")) { - return decodeEnum(encodedValue); + } else if (encodedValue.startsWith("i")) { + return Integer.parseInt(cut); + } else if (encodedValue.startsWith("E:")) { + cut = cut.substring(1); + return decodeEnum(cut); } else { - return Integer.parseInt(encodedValue); + throw new IOException("Unrecognized value: " + encodedValue); } } catch (Exception e) { if (e instanceof IOException) { diff --git a/src/be/nikiroo/utils/serial/server/ConnectAction.java b/src/be/nikiroo/utils/serial/server/ConnectAction.java index c02d734..d359e08 100644 --- a/src/be/nikiroo/utils/serial/server/ConnectAction.java +++ b/src/be/nikiroo/utils/serial/server/ConnectAction.java @@ -376,7 +376,7 @@ abstract class ConnectAction { contentToSend = false; } - if (in.next()) { + if (in.next() && !in.eof()) { // TODO: could be possible to check for non-crypt and only // do it for crypt InputStream read = new ReplaceInputStream(in.open(), // diff --git a/src/be/nikiroo/utils/streams/BufferedInputStream.java b/src/be/nikiroo/utils/streams/BufferedInputStream.java index d1f53df..683fa55 100644 --- a/src/be/nikiroo/utils/streams/BufferedInputStream.java +++ b/src/be/nikiroo/utils/streams/BufferedInputStream.java @@ -266,7 +266,7 @@ public class BufferedInputStream extends InputStream { } /** - * Check if this stream is totally spent (no more data to read or to + * Check if this stream is spent (no more data to read or to * process). * * @return TRUE if it is diff --git a/src/be/nikiroo/utils/streams/NextableInputStream.java b/src/be/nikiroo/utils/streams/NextableInputStream.java index 550aa24..fb4d01b 100644 --- a/src/be/nikiroo/utils/streams/NextableInputStream.java +++ b/src/be/nikiroo/utils/streams/NextableInputStream.java @@ -81,16 +81,14 @@ public class NextableInputStream extends BufferedInputStream { * It can only be called when the "current" stream is spent (i.e., you must * first process the stream until it is spent). *

- * We consider that when the under-laying {@link InputStream} is also spent, - * we cannot have a next sub-stream (it will thus return FALSE). - *

* {@link IOException}s can happen when we have no data available in the * buffer; in that case, we fetch more data to know if we can have a next * sub-stream or not. *

* This is can be a blocking call when data need to be fetched. * - * @return TRUE if we unblocked the next sub-stream, FALSE if not + * @return TRUE if we unblocked the next sub-stream, FALSE if not (i.e., + * FALSE when there are no more sub-streams to fetch) * * @throws IOException * in case of I/O error or if the stream is closed @@ -122,7 +120,7 @@ public class NextableInputStream extends BufferedInputStream { * process). *

* Note: when the stream is divided into sub-streams, each sub-stream will - * report it is eof when emptied. + * report its own eof when spent. * * @return TRUE if it is * @@ -158,11 +156,6 @@ public class NextableInputStream extends BufferedInputStream { return false; } - /** - * We have more data available in the buffer or we can fetch more. - * - * @return TRUE if it is the case, FALSE if not - */ @Override protected boolean hasMoreData() { return started && super.hasMoreData(); @@ -205,7 +198,8 @@ public class NextableInputStream extends BufferedInputStream { * TRUE for {@link NextableInputStream#nextAll()}, FALSE for * {@link NextableInputStream#next()} * - * @return TRUE if we unblocked the next sub-stream, FALSE if not + * @return TRUE if we unblocked the next sub-stream, FALSE if not (i.e., + * FALSE when there are no more sub-streams to fetch) * * @throws IOException * in case of I/O error or if the stream is closed @@ -220,9 +214,17 @@ public class NextableInputStream extends BufferedInputStream { if (all) { step = null; } + + return true; } - if (step != null && !hasMoreData() && stopped) { + // If started, must be stopped an no more data to continue + // i.e., sub-stream must be spent + if (!stopped || hasMoreData()) { + return false; + } + + if (step != null) { stop = step.getResumeLen(); start += step.getResumeSkip(); eof = step.getResumeEof(); @@ -233,17 +235,21 @@ public class NextableInputStream extends BufferedInputStream { } checkBuffer(false); - } - // consider that if EOF, there is no next - if (start >= stop) { - // Make sure, block if necessary - preRead(); - - return hasMoreData(); + return true; } - return true; + return false; + + // // consider that if EOF, there is no next + // if (start >= stop) { + // // Make sure, block if necessary + // preRead(); + // + // return hasMoreData(); + // } + // + // return true; } /** diff --git a/src/be/nikiroo/utils/test/TestLauncher.java b/src/be/nikiroo/utils/test/TestLauncher.java index 9b841a4..895b565 100644 --- a/src/be/nikiroo/utils/test/TestLauncher.java +++ b/src/be/nikiroo/utils/test/TestLauncher.java @@ -40,6 +40,8 @@ public class TestLauncher { private List series; private List tests; + private TestLauncher parent; + private int columns; private String okString; private String koString; @@ -50,6 +52,7 @@ public class TestLauncher { protected int total; private int currentSeries = 0; + private boolean details = false; /** * Create a new {@link TestLauncher} with default parameters. @@ -90,6 +93,33 @@ public class TestLauncher { cont = true; } + /** + * Display the details of the errors + * + * @return TRUE to display them, false to simply mark the test as failed + */ + public boolean isDetails() { + if (parent != null) { + return parent.isDetails(); + } + + return details; + } + + /** + * Display the details of the errors + * + * @param details + * TRUE to display them, false to simply mark the test as failed + */ + public void setDetails(boolean details) { + if (parent != null) { + parent.setDetails(details); + } + + this.details = details; + } + /** * Called before actually starting the tests themselves. * @@ -114,6 +144,7 @@ public class TestLauncher { protected void addSeries(TestLauncher series) { this.series.add(series); + series.parent = this; } /** @@ -304,12 +335,14 @@ public class TestLauncher { private void print(int depth, Throwable error) { if (error != null) { System.out.println(" " + koString); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - error.printStackTrace(pw); - String lines = sw.toString(); - for (String line : lines.split("\n")) { - System.out.println(prefix(depth, false) + "\t\t" + line); + if (isDetails()) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + error.printStackTrace(pw); + String lines = sw.toString(); + for (String line : lines.split("\n")) { + System.out.println(prefix(depth, false) + "\t\t" + line); + } } } else { System.out.println(" " + okString); diff --git a/src/be/nikiroo/utils/test_code/NextableInputStreamTest.java b/src/be/nikiroo/utils/test_code/NextableInputStreamTest.java index f8031f0..cfb205b 100644 --- a/src/be/nikiroo/utils/test_code/NextableInputStreamTest.java +++ b/src/be/nikiroo/utils/test_code/NextableInputStreamTest.java @@ -19,16 +19,7 @@ public class NextableInputStreamTest extends TestLauncher { byte[] expected = new byte[] { 42, 12, 0, 127 }; NextableInputStream in = new NextableInputStream( new ByteArrayInputStream(expected), null); - in.next(); - byte[] actual = IOUtils.toByteArray(in); - - assertEquals( - "The resulting array has not the same number of items", - expected.length, actual.length); - for (int i = 0; i < expected.length; i++) { - assertEquals("Item " + i + " (0-based) is not the same", - expected[i], actual[i]); - } + checkNext(this, "READ", in, expected); } }); diff --git a/src/be/nikiroo/utils/test_code/SerialServerTest.java b/src/be/nikiroo/utils/test_code/SerialServerTest.java index 9c346fd..382d9a6 100644 --- a/src/be/nikiroo/utils/test_code/SerialServerTest.java +++ b/src/be/nikiroo/utils/test_code/SerialServerTest.java @@ -43,63 +43,63 @@ class SerialServerTest extends TestLauncher { super(title + " " + skey + sbridge, args); - addTest(new TestCase("Simple connection " + skey) { - @Override - public void test() throws Exception { - final String[] rec = new String[1]; - - ServerString server = new ServerString(this.getName(), 0, key) { - @Override - protected String onRequest( - ConnectActionServerString action, String data) - throws Exception { - return null; - } - - @Override - protected void onError(Exception e) { - } - }; - - int port = server.getPort(); - assertEquals("A port should have been assigned", true, port > 0); - - server.start(); - - ServerBridge br = null; - if (bridge) { - br = new ServerBridge(0, key, "", port, key); - br.setTraceHandler(null); - - port = br.getPort(); - assertEquals( - "A port should have been assigned to the bridge", - true, port > 0); - - br.start(); - } - - try { - try { - new ConnectActionClientObject(null, port, key) { - @Override - public void action() throws Exception { - rec[0] = "ok"; - } - }.connect(); - } finally { - server.stop(); - } - } finally { - if (br != null) { - br.stop(); - } - } - - assertNotNull("The client action was not run", rec[0]); - assertEquals("ok", rec[0]); - } - }); + // addTest(new TestCase("Simple connection " + skey) { + // @Override + // public void test() throws Exception { + // final String[] rec = new String[1]; + // + // ServerString server = new ServerString(this.getName(), 0, key) { + // @Override + // protected String onRequest( + // ConnectActionServerString action, String data) + // throws Exception { + // return null; + // } + // + // @Override + // protected void onError(Exception e) { + // } + // }; + // + // int port = server.getPort(); + // assertEquals("A port should have been assigned", true, port > 0); + // + // server.start(); + // + // ServerBridge br = null; + // if (bridge) { + // br = new ServerBridge(0, key, "", port, key); + // br.setTraceHandler(null); + // + // port = br.getPort(); + // assertEquals( + // "A port should have been assigned to the bridge", + // true, port > 0); + // + // br.start(); + // } + // + // try { + // try { + // new ConnectActionClientObject(null, port, key) { + // @Override + // public void action() throws Exception { + // rec[0] = "ok"; + // } + // }.connect(); + // } finally { + // server.stop(); + // } + // } finally { + // if (br != null) { + // br.stop(); + // } + // } + // + // assertNotNull("The client action was not run", rec[0]); + // assertEquals("ok", rec[0]); + // } + // }); addTest(new TestCase("Simple exchange " + skey) { final String[] sent = new String[1]; diff --git a/src/be/nikiroo/utils/test_code/SerialTest.java b/src/be/nikiroo/utils/test_code/SerialTest.java index c008dec..1581965 100644 --- a/src/be/nikiroo/utils/test_code/SerialTest.java +++ b/src/be/nikiroo/utils/test_code/SerialTest.java @@ -75,6 +75,7 @@ class SerialTest extends TestLauncher { encodeRecodeTest(this, data); } }); + addTest(new TestCase() { @SuppressWarnings("unused") private TestCase me = setName("Anonymous inner class"); diff --git a/src/be/nikiroo/utils/test_code/Test.java b/src/be/nikiroo/utils/test_code/Test.java index f994480..1512f56 100644 --- a/src/be/nikiroo/utils/test_code/Test.java +++ b/src/be/nikiroo/utils/test_code/Test.java @@ -24,6 +24,8 @@ public class Test extends TestLauncher { public Test(String[] args) { super("Nikiroo-utils", args); + // setDetails(true); + addSeries(new ProgressTest(args)); addSeries(new BundleTest(args)); addSeries(new IOUtilsTest(args));