From 620f732927beb44ba33d35cc47646ec53b5f535b Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Wed, 14 Mar 2018 07:45:49 +0100 Subject: [PATCH] Fix text justification and linked tests --- src/be/nikiroo/utils/StringJustifier.java | 170 ++++++++++-------- .../nikiroo/utils/test/StringUtilsTest.java | 29 ++- src/be/nikiroo/utils/test/Test.java | 5 +- src/be/nikiroo/utils/test/TestCase.java | 40 ++++- 4 files changed, 145 insertions(+), 99 deletions(-) diff --git a/src/be/nikiroo/utils/StringJustifier.java b/src/be/nikiroo/utils/StringJustifier.java index 174c7e9..9ea0b72 100644 --- a/src/be/nikiroo/utils/StringJustifier.java +++ b/src/be/nikiroo/utils/StringJustifier.java @@ -49,77 +49,7 @@ class StringJustifier { * @return the list of justified lines */ static List left(final String data, final int width) { - List lines = new LinkedList(); - - for (String dataLine : data.split("\n")) { - String line = rightTrim(dataLine.replace("\t", " ")); - - if (width > 0 && line.length() > width) { - while (line.length() > 0) { - int i = Math.min(line.length(), width - 1); // -1 for "-" - - boolean needDash = true; - // find the best space if any and if needed - int prevSpace = 0; - if (i < line.length()) { - prevSpace = -1; - int space = line.indexOf(' '); - - while (space > -1 && space <= i) { - prevSpace = space; - space = line.indexOf(' ', space + 1); - } - - if (prevSpace > 0) { - i = prevSpace; - needDash = false; - } - } - // - - // no dash before space/dash - if ((i + 1) < line.length()) { - char car = line.charAt(i); - char nextCar = line.charAt(i + 1); - if (nextCar == ' ' || car == '-' || nextCar == '-') { - needDash = false; - } - } - - // if the space freed by the removed dash allows it, or if - // it is the last char, add the next char - if (!needDash || i >= line.length() - 1) { - int checkI = Math.min(i + 1, line.length()); - if (checkI == i || checkI <= width) { - needDash = false; - i = checkI; - } - } - - // no dash before parenthesis (but cannot add one more - // after) - if ((i + 1) < line.length()) { - char car = line.charAt(i + 1); - if (car == '(' || car == ')') { - needDash = false; - } - } - - if (needDash) { - lines.add(rightTrim(line.substring(0, i)) + "-"); - } else { - lines.add(rightTrim(line.substring(0, i))); - } - - // full trim (remove spaces when cutting) - line = line.substring(i).trim(); - } - } else { - lines.add(line); - } - } - - return lines; + return left(data, width, false); } /** @@ -198,11 +128,11 @@ class StringJustifier { List result = new LinkedList(); /* - * Same as left(), but insert spaces between words to make each line n - * chars long. The "algorithm" here is pretty dumb: it performs a split - * on space and then re-inserts multiples of n between words. + * Same as left(true), but insert spaces between words to make each line + * n chars long. The "algorithm" here is pretty dumb: it performs a + * split on space and then re-inserts multiples of n between words. */ - List lines = left(str, n); + List lines = left(str, n, true); for (int lineI = 0; lineI < lines.size() - 1; lineI++) { String line = lines.get(lineI); String[] words = line.split(" "); @@ -241,6 +171,96 @@ class StringJustifier { return result; } + /** + * Process the given text into a list of left-justified lines of a given + * max-width. + * + * @param data + * the text to justify + * @param width + * the maximum width of a line + * @param minTwoWords + * use 2 words per line minimum if the text allows it + * + * @return the list of justified lines + */ + static private List left(final String data, final int width, + boolean minTwoWords) { + List lines = new LinkedList(); + + for (String dataLine : data.split("\n")) { + String line = rightTrim(dataLine.replace("\t", " ")); + + if (width > 0 && line.length() > width) { + while (line.length() > 0) { + int i = Math.min(line.length(), width - 1); // -1 for "-" + + boolean needDash = true; + // find the best space if any and if needed + int prevSpace = 0; + if (i < line.length()) { + prevSpace = -1; + int space = line.indexOf(' '); + int numOfSpaces = 0; + + while (space > -1 && space <= i) { + prevSpace = space; + space = line.indexOf(' ', space + 1); + numOfSpaces++; + } + + if (prevSpace > 0 && (!minTwoWords || numOfSpaces >= 2)) { + i = prevSpace; + needDash = false; + } + } + // + + // no dash before space/dash + if ((i + 1) < line.length()) { + char car = line.charAt(i); + char nextCar = line.charAt(i + 1); + if (nextCar == ' ' || car == '-' || nextCar == '-') { + needDash = false; + } + } + + // if the space freed by the removed dash allows it, or if + // it is the last char, add the next char + if (!needDash || i >= line.length() - 1) { + int checkI = Math.min(i + 1, line.length()); + if (checkI == i || checkI <= width) { + needDash = false; + i = checkI; + } + } + + // no dash before parenthesis (but cannot add one more + // after) + if ((i + 1) < line.length()) { + char car = line.charAt(i + 1); + if (car == '(' || car == ')') { + needDash = false; + } + } + + if (needDash) { + lines.add(rightTrim(line.substring(0, i)) + "-"); + } else { + lines.add(rightTrim(line.substring(0, i))); + } + + // full trim (remove spaces when cutting) + line = line.substring(i).trim(); + } + } else { + lines.add(line); + } + } + + return lines; + } + /** * Trim the given {@link String} on the right only. * diff --git a/src/be/nikiroo/utils/test/StringUtilsTest.java b/src/be/nikiroo/utils/test/StringUtilsTest.java index 4be7504..6ebf43e 100644 --- a/src/be/nikiroo/utils/test/StringUtilsTest.java +++ b/src/be/nikiroo/utils/test/StringUtilsTest.java @@ -144,6 +144,10 @@ class StringUtilsTest extends TestLauncher { @Override public void test() throws Exception { Map>>> source = new HashMap>>>(); + addValue(source, Alignment.LEFT, "testy", -1, "testy"); + addValue(source, Alignment.RIGHT, "testy", -1, "testy"); + addValue(source, Alignment.CENTER, "testy", -1, "testy"); + addValue(source, Alignment.JUSTIFY, "testy", -1, "testy"); addValue(source, Alignment.LEFT, "testy", 5, "testy"); addValue(source, Alignment.LEFT, "testy", 3, "te-", "sty"); addValue(source, Alignment.LEFT, @@ -164,14 +168,13 @@ class StringUtilsTest extends TestLauncher { " sur ", "plusie-", " urs ", "lignes "); addValue(source, Alignment.JUSTIFY, "Un petit texte qui se mettra sur plusieurs lignes", 7, - "Un", "petit", "texte", "qui se", "mettra", "sur", - "plusie-", "urs", "lignes"); + "Un pet-", "it tex-", "te qui", "se met-", "tra sur", + "plusie-", "urs li-", "gnes"); addValue(source, Alignment.JUSTIFY, "Un petit texte qui se mettra sur plusieurs lignes", 14, "Un petit", "texte qui se", "mettra sur", "plusieurs lig-", "nes"); - System.out.println(); for (String data : source.keySet()) { for (int size : source.get(data).keySet()) { Alignment align = source.get(data).get(size).getKey(); @@ -181,21 +184,17 @@ class StringUtilsTest extends TestLauncher { List result = StringUtils.justifyText(data, size, align); - System.out.println("[" + data + " (" + size + ")" - + "] -> ["); - for (int i = 0; i < result.size(); i++) { - String resultLine = result.get(i); - System.out.println(i + ": " + resultLine); - } - System.out.println("]"); + // System.out.println("[" + data + " (" + size + ")" + + // "] -> ["); + // for (int i = 0; i < result.size(); i++) { + // String resultLine = result.get(i); + // System.out.println(i + ": " + resultLine); + // } + // System.out.println("]"); - for (int i = 0; i < result.size() && i < values.size(); i++) { - assertEquals("The line " + i + " is not correct", - values.get(i), result.get(i)); - } + assertEquals(values, result); } } - System.out.println(); } }); diff --git a/src/be/nikiroo/utils/test/Test.java b/src/be/nikiroo/utils/test/Test.java index bb08e2b..dd6bf61 100644 --- a/src/be/nikiroo/utils/test/Test.java +++ b/src/be/nikiroo/utils/test/Test.java @@ -19,15 +19,14 @@ public class Test extends TestLauncher { public Test(String[] args) { super("Nikiroo-utils", args); - /* addSeries(new ProgressTest(args)); addSeries(new BundleTest(args)); addSeries(new IOUtilsTest(args)); addSeries(new VersionTest(args)); addSeries(new SerialTest(args)); addSeries(new SerialServerTest(args)); - */addSeries(new StringUtilsTest(args)); - //addSeries(new TempFilesTest(args)); + addSeries(new StringUtilsTest(args)); + addSeries(new TempFilesTest(args)); // TODO: test cache and downloader Cache cache = null; diff --git a/src/be/nikiroo/utils/test/TestCase.java b/src/be/nikiroo/utils/test/TestCase.java index a62cb0b..5cff363 100644 --- a/src/be/nikiroo/utils/test/TestCase.java +++ b/src/be/nikiroo/utils/test/TestCase.java @@ -1,5 +1,7 @@ package be.nikiroo.utils.test; +import java.util.List; + /** * A {@link TestCase} that can be run with {@link TestLauncher}. * @@ -140,7 +142,7 @@ abstract public class TestCase { } /** - * Check that 2 {@link Object}s are equals. + * Check that 2 longs are equals. * * @param expected * the expected value @@ -155,7 +157,7 @@ abstract public class TestCase { } /** - * Check that 2 {@link Object}s are equals. + * Check that 2 longs are equals. * * @param errorMessage * the error message to display if they differ @@ -173,7 +175,7 @@ abstract public class TestCase { } /** - * Check that 2 {@link Object}s are equals. + * Check that 2 booleans are equals. * * @param expected * the expected value @@ -189,7 +191,7 @@ abstract public class TestCase { } /** - * Check that 2 {@link Object}s are equals. + * Check that 2 booleans are equals. * * @param errorMessage * the error message to display if they differ @@ -208,7 +210,7 @@ abstract public class TestCase { } /** - * Check that 2 {@link Object}s are equals. + * Check that 2 doubles are equals. * * @param expected * the expected value @@ -224,7 +226,7 @@ abstract public class TestCase { } /** - * Check that 2 {@link Object}s are equals. + * Check that 2 doubles are equals. * * @param errorMessage * the error message to display if they differ @@ -242,6 +244,32 @@ abstract public class TestCase { Double.valueOf(actual)); } + /** + * Check that 2 {@link List}s are equals. + * + * @param errorMessage + * the error message to display if they differ + * @param expected + * the expected value + * @param actual + * the actual value + * + * @throws AssertException + * in case they differ + */ + public void assertEquals(List expected, List actual) + throws AssertException { + + assertEquals("The 2 lists don't contain the same number of items", + expected.size(), actual.size()); + + int size = expected.size(); + for (int i = 0; i < size; i++) { + assertEquals("Line " + i + " (0-based) is not correct", + expected.get(i), actual.get(i)); + } + } + /** * Check that given {@link Object} is not NULL. * -- 2.27.0