Upload files to "java/md2html"
This commit is contained in:
82
java/md2html/Md2Html.java
Normal file
82
java/md2html/Md2Html.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package md2html;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import markup.*;
|
||||||
|
|
||||||
|
public class Md2Html {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String text = readFile(args[0]);
|
||||||
|
BlockCreator creator = new BlockCreator(text);
|
||||||
|
List<String> blocks = creator.divideByBlocks();
|
||||||
|
|
||||||
|
try (
|
||||||
|
BufferedWriter writer = new BufferedWriter(
|
||||||
|
new OutputStreamWriter(
|
||||||
|
new FileOutputStream(args[1]),
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
for (int i = 0; i < blocks.size(); i++) {
|
||||||
|
PrimePartCreator creatorPrime = new PrimePartCreator(
|
||||||
|
blocks.get(i)
|
||||||
|
);
|
||||||
|
PrimePart part = creatorPrime.createPart();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
part.toHtml(sb);
|
||||||
|
writer.write(sb.toString());
|
||||||
|
if (i < blocks.size() - 1) {
|
||||||
|
writer.write(System.lineSeparator());
|
||||||
|
}
|
||||||
|
sb.setLength(0); // освобождаем память
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IOException: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String readFile(String nameOfFile) {
|
||||||
|
try (
|
||||||
|
BufferedReader reader = new BufferedReader(
|
||||||
|
new InputStreamReader(
|
||||||
|
new FileInputStream(nameOfFile),
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
int read = reader.read();
|
||||||
|
while (read != -1) {
|
||||||
|
text.append((char) read);
|
||||||
|
read = reader.read();
|
||||||
|
}
|
||||||
|
return text.toString();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
System.out.println("Input file not found: " + e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IOException file not found: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeToFile(String nameOfFile, String text) {
|
||||||
|
try (
|
||||||
|
BufferedWriter writer = new BufferedWriter(
|
||||||
|
new OutputStreamWriter(
|
||||||
|
new FileOutputStream(nameOfFile),
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
writer.write(text);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
System.out.println("Output file not found: " + e.getMessage());
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("IOException file not found: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
117
java/md2html/Md2HtmlTest.java
Normal file
117
java/md2html/Md2HtmlTest.java
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package md2html;
|
||||||
|
|
||||||
|
import base.Selector;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
|
||||||
|
*/
|
||||||
|
public final class Md2HtmlTest {
|
||||||
|
|
||||||
|
// === 3637
|
||||||
|
private static final Consumer<? super Md2HtmlTester> INS = tester ->
|
||||||
|
tester
|
||||||
|
.test("<<вставка>>", "<p><ins>вставка</ins></p>")
|
||||||
|
.test(
|
||||||
|
"Это <<вставка>>, вложенная в текст",
|
||||||
|
"<p>Это <ins>вставка</ins>, вложенная в текст</p>"
|
||||||
|
)
|
||||||
|
.spoiled(
|
||||||
|
"Это не <<вставка>>",
|
||||||
|
"<p>Это не <<вставка>></p>",
|
||||||
|
"<",
|
||||||
|
">"
|
||||||
|
)
|
||||||
|
.spoiled(
|
||||||
|
"Это не <<вставка>> 2",
|
||||||
|
"<p>Это не <<вставка>> 2</p>",
|
||||||
|
"<",
|
||||||
|
">"
|
||||||
|
)
|
||||||
|
.addElement("ins", "<<", ">>");
|
||||||
|
private static final Consumer<? super Md2HtmlTester> DEL = tester ->
|
||||||
|
tester
|
||||||
|
.test("}}удаление{{", "<p><del>удаление</del></p>")
|
||||||
|
.test(
|
||||||
|
"Это }}удаление{{, вложенное в текст",
|
||||||
|
"<p>Это <del>удаление</del>, вложенное в текст</p>"
|
||||||
|
)
|
||||||
|
.spoiled("Это не }}удаление{{", "<p>Это не }}удаление{{</p>", "{")
|
||||||
|
.spoiled(
|
||||||
|
"Это не }}удаление{{ 2",
|
||||||
|
"<p>Это не }}удаление{{ 2</p>",
|
||||||
|
"{"
|
||||||
|
)
|
||||||
|
.addElement("del", "}}", "{{");
|
||||||
|
|
||||||
|
// === 3839
|
||||||
|
private static final Consumer<? super Md2HtmlTester> PRE = tester ->
|
||||||
|
tester
|
||||||
|
.test(
|
||||||
|
"```код __без__ форматирования```",
|
||||||
|
"<p><pre>код __без__ форматирования</pre></p>"
|
||||||
|
)
|
||||||
|
.test(
|
||||||
|
"Это не `\\``код __без__ форматирования``\\`",
|
||||||
|
"<p>Это не <code>`</code>код <strong>без</strong> форматирования<code></code>`</p>"
|
||||||
|
)
|
||||||
|
.addElement("pre", "```", (checker, markup, input, output) -> {
|
||||||
|
final String contentS = checker
|
||||||
|
.generateInput(markup)
|
||||||
|
.replace("`", "");
|
||||||
|
|
||||||
|
input.append("```").append(contentS).append("```");
|
||||||
|
output
|
||||||
|
.append("<pre>")
|
||||||
|
.append(contentS.replace("<", "<").replace(">", ""))
|
||||||
|
.append("</pre>");
|
||||||
|
});
|
||||||
|
|
||||||
|
// === 3435
|
||||||
|
private static final Consumer<? super Md2HtmlTester> SAMP = tester ->
|
||||||
|
tester
|
||||||
|
.test("!!пример!!", "<p><samp>пример</samp></p>")
|
||||||
|
.test(
|
||||||
|
"Это !!пример!!, вложенный в текст",
|
||||||
|
"<p>Это <samp>пример</samp>, вложенный в текст</p>"
|
||||||
|
)
|
||||||
|
.spoiled("Это не !!пример!!", "<p>Это не !!пример!!</p>", "!")
|
||||||
|
.spoiled("Это не !!пример!! 2", "<p>Это не !!пример!! 2</p>", "!")
|
||||||
|
.addElement("samp", "!!");
|
||||||
|
|
||||||
|
// === 3233
|
||||||
|
private static final Consumer<Md2HtmlTester> VAR = tester ->
|
||||||
|
tester
|
||||||
|
.test("%переменная%", "<p><var>переменная</var></p>")
|
||||||
|
.test(
|
||||||
|
"Это %переменная%, вложенная в текст",
|
||||||
|
"<p>Это <var>переменная</var>, вложенная в текст</p>"
|
||||||
|
)
|
||||||
|
.spoiled("Это не %переменная%", "<p>Это не %переменная%</p>", "%")
|
||||||
|
.spoiled(
|
||||||
|
"Это не %переменная% 2",
|
||||||
|
"<p>Это не %переменная% 2</p>",
|
||||||
|
"%"
|
||||||
|
)
|
||||||
|
.addElement("var", "%");
|
||||||
|
|
||||||
|
// === Common
|
||||||
|
|
||||||
|
public static final Selector SELECTOR = Selector.composite(
|
||||||
|
Md2HtmlTest.class,
|
||||||
|
c -> new Md2HtmlTester(),
|
||||||
|
Md2HtmlTester::test
|
||||||
|
)
|
||||||
|
.variant("Base")
|
||||||
|
.variant("3637", INS, DEL)
|
||||||
|
.variant("3839", PRE)
|
||||||
|
.variant("3435", SAMP)
|
||||||
|
.variant("3233", VAR)
|
||||||
|
.selector();
|
||||||
|
|
||||||
|
private Md2HtmlTest() {}
|
||||||
|
|
||||||
|
public static void main(final String... args) {
|
||||||
|
SELECTOR.main(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
427
java/md2html/Md2HtmlTester.java
Normal file
427
java/md2html/Md2HtmlTester.java
Normal file
@@ -0,0 +1,427 @@
|
|||||||
|
package md2html;
|
||||||
|
|
||||||
|
import base.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
|
||||||
|
*/
|
||||||
|
public class Md2HtmlTester {
|
||||||
|
|
||||||
|
private static final Map<String, String> ESCAPES = Map.of(
|
||||||
|
"<",
|
||||||
|
"<",
|
||||||
|
">",
|
||||||
|
">"
|
||||||
|
);
|
||||||
|
|
||||||
|
private final Map<String, Generator> elements = new HashMap<>();
|
||||||
|
private final Map<String, List<String>> tags = new LinkedHashMap<>();
|
||||||
|
private final List<Pair<String, String>> tests = new ArrayList<>();
|
||||||
|
|
||||||
|
public Md2HtmlTester() {
|
||||||
|
addElement("em", "*");
|
||||||
|
addElement("em", "_");
|
||||||
|
addElement("strong", "**");
|
||||||
|
addElement("strong", "__");
|
||||||
|
addElement("s", "--");
|
||||||
|
addElement("code", "`");
|
||||||
|
|
||||||
|
test(
|
||||||
|
"# Заголовок первого уровня\n\n",
|
||||||
|
"<h1>Заголовок первого уровня</h1>"
|
||||||
|
);
|
||||||
|
test("## Второго\n\n", "<h2>Второго</h2>");
|
||||||
|
test("### Третьего ## уровня\n\n", "<h3>Третьего ## уровня</h3>");
|
||||||
|
test(
|
||||||
|
"#### Четвертого\n# Все еще четвертого\n\n",
|
||||||
|
"<h4>Четвертого\n# Все еще четвертого</h4>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"Этот абзац текста\nсодержит две строки.",
|
||||||
|
"<p>Этот абзац текста\nсодержит две строки.</p>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
" # Может показаться, что это заголовок.\nНо нет, это абзац, начинающийся с `#`.\n\n",
|
||||||
|
"<p> # Может показаться, что это заголовок.\nНо нет, это абзац, начинающийся с <code>#</code>.</p>"
|
||||||
|
);
|
||||||
|
test("#И это не заголовок.\n\n", "<p>#И это не заголовок.</p>");
|
||||||
|
test(
|
||||||
|
"###### Заголовки могут быть многострочными\n(и с пропуском заголовков предыдущих уровней)\n\n",
|
||||||
|
"<h6>Заголовки могут быть многострочными\n(и с пропуском заголовков предыдущих уровней)</h6>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"Мы все любим *выделять* текст _разными_ способами.\n**Сильное выделение**, используется гораздо реже,\nно __почему бы и нет__?\nНемного --зачеркивания-- еще никому не вредило.\nКод представляется элементом `code`.\n\n",
|
||||||
|
"<p>Мы все любим <em>выделять</em> текст <em>разными</em> способами.\n<strong>Сильное выделение</strong>, используется гораздо реже,\nно <strong>почему бы и нет</strong>?\nНемного <s>зачеркивания</s> еще никому не вредило.\nКод представляется элементом <code>code</code>.</p>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"Обратите внимание, как экранируются специальные\nHTML-символы, такие как `<`, `>` и `&`.\n\n",
|
||||||
|
"<p>Обратите внимание, как экранируются специальные\nHTML-символы, такие как <code><</code>, <code>></code> и <code>&</code>.</p>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"Экранирование должно работать во всех местах: <>&.\n\n",
|
||||||
|
"<p>Экранирование должно работать во всех местах: <>&.</p>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"Знаете ли вы, что в Markdown, одиночные * и _\nне означают выделение?\nОни так же могут быть заэкранированы\nпри помощи обратного слэша: \\*.",
|
||||||
|
"<p>Знаете ли вы, что в Markdown, одиночные * и _\nне означают выделение?\nОни так же могут быть заэкранированы\nпри помощи обратного слэша: *.</p>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"\n\n\nЛишние пустые строки должны игнорироваться.\n\n\n\n",
|
||||||
|
"<p>Лишние пустые строки должны игнорироваться.</p>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"Любите ли вы *вложенные __выделения__* так,\nкак __--люблю--__ их я?",
|
||||||
|
"<p>Любите ли вы <em>вложенные <strong>выделения</strong></em> так,\nкак <strong><s>люблю</s></strong> их я?</p>"
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
"""
|
||||||
|
# Заголовок первого уровня
|
||||||
|
|
||||||
|
## Второго
|
||||||
|
|
||||||
|
### Третьего ## уровня
|
||||||
|
|
||||||
|
#### Четвертого
|
||||||
|
# Все еще четвертого
|
||||||
|
|
||||||
|
Этот абзац текста
|
||||||
|
содержит две строки.
|
||||||
|
|
||||||
|
# Может показаться, что это заголовок.
|
||||||
|
Но нет, это абзац, начинающийся с `#`.
|
||||||
|
|
||||||
|
#И это не заголовок.
|
||||||
|
|
||||||
|
###### Заголовки могут быть многострочными
|
||||||
|
(и с пропуском заголовков предыдущих уровней)
|
||||||
|
|
||||||
|
Мы все любим *выделять* текст _разными_ способами.
|
||||||
|
**Сильное выделение**, используется гораздо реже,
|
||||||
|
но __почему бы и нет__?
|
||||||
|
Немного --зачеркивания-- еще никому не вредило.
|
||||||
|
Код представляется элементом `code`.
|
||||||
|
|
||||||
|
Обратите внимание, как экранируются специальные
|
||||||
|
HTML-символы, такие как `<`, `>` и `&`.
|
||||||
|
|
||||||
|
Знаете ли вы, что в Markdown, одиночные * и _
|
||||||
|
не означают выделение?
|
||||||
|
Они так же могут быть заэкранированы
|
||||||
|
при помощи обратного слэша: \\*.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Лишние пустые строки должны игнорироваться.
|
||||||
|
|
||||||
|
Любите ли вы *вложенные __выделения__* так,
|
||||||
|
как __--люблю--__ их я?
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
<h1>Заголовок первого уровня</h1>
|
||||||
|
<h2>Второго</h2>
|
||||||
|
<h3>Третьего ## уровня</h3>
|
||||||
|
<h4>Четвертого
|
||||||
|
# Все еще четвертого</h4>
|
||||||
|
<p>Этот абзац текста
|
||||||
|
содержит две строки.</p>
|
||||||
|
<p> # Может показаться, что это заголовок.
|
||||||
|
Но нет, это абзац, начинающийся с <code>#</code>.</p>
|
||||||
|
<p>#И это не заголовок.</p>
|
||||||
|
<h6>Заголовки могут быть многострочными
|
||||||
|
(и с пропуском заголовков предыдущих уровней)</h6>
|
||||||
|
<p>Мы все любим <em>выделять</em> текст <em>разными</em> способами.
|
||||||
|
<strong>Сильное выделение</strong>, используется гораздо реже,
|
||||||
|
но <strong>почему бы и нет</strong>?
|
||||||
|
Немного <s>зачеркивания</s> еще никому не вредило.
|
||||||
|
Код представляется элементом <code>code</code>.</p>
|
||||||
|
<p>Обратите внимание, как экранируются специальные
|
||||||
|
HTML-символы, такие как <code><</code>, <code>></code> и <code>&</code>.</p>
|
||||||
|
<p>Знаете ли вы, что в Markdown, одиночные * и _
|
||||||
|
не означают выделение?
|
||||||
|
Они так же могут быть заэкранированы
|
||||||
|
при помощи обратного слэша: *.</p>
|
||||||
|
<p>Лишние пустые строки должны игнорироваться.</p>
|
||||||
|
<p>Любите ли вы <em>вложенные <strong>выделения</strong></em> так,
|
||||||
|
как <strong><s>люблю</s></strong> их я?</p>
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
"# Без перевода строки в конце",
|
||||||
|
"<h1>Без перевода строки в конце</h1>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"# Один перевод строки в конце\n",
|
||||||
|
"<h1>Один перевод строки в конце</h1>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"# Два перевода строки в конце\n\n",
|
||||||
|
"<h1>Два перевода строки в конце</h1>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"Выделение может *начинаться на одной строке,\n а заканчиваться* на другой",
|
||||||
|
"<p>Выделение может <em>начинаться на одной строке,\n а заканчиваться</em> на другой</p>"
|
||||||
|
);
|
||||||
|
test(
|
||||||
|
"# *Выделение* и `код` в заголовках",
|
||||||
|
"<h1><em>Выделение</em> и <code>код</code> в заголовках</h1>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addElement(final String tag, final String markup) {
|
||||||
|
addElement(tag, markup, markup);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addElement(
|
||||||
|
final String tag,
|
||||||
|
final String begin,
|
||||||
|
final String end
|
||||||
|
) {
|
||||||
|
addElement(tag, begin, (checker, markup, input, output) -> {
|
||||||
|
checker.space(input, output);
|
||||||
|
input.append(begin);
|
||||||
|
open(output, tag);
|
||||||
|
|
||||||
|
checker.word(input, output);
|
||||||
|
checker.generate(markup, input, output);
|
||||||
|
checker.word(input, output);
|
||||||
|
|
||||||
|
input.append(end);
|
||||||
|
close(output, tag);
|
||||||
|
checker.space(input, output);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addElement(
|
||||||
|
final String tag,
|
||||||
|
final String begin,
|
||||||
|
final Generator generator
|
||||||
|
) {
|
||||||
|
Asserts.assertTrue(
|
||||||
|
"Duplicate element " + begin,
|
||||||
|
elements.put(begin, generator) == null
|
||||||
|
);
|
||||||
|
tags.computeIfAbsent(tag, k -> new ArrayList<>()).add(begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Runner runner = Runner.packages("md2html").files("Md2Html");
|
||||||
|
|
||||||
|
protected Md2HtmlTester test(final String input, final String output) {
|
||||||
|
tests.add(Pair.of(input, output));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Md2HtmlTester spoiled(
|
||||||
|
final String input,
|
||||||
|
final String output,
|
||||||
|
final String... spoilers
|
||||||
|
) {
|
||||||
|
for (final String spoiler : spoilers) {
|
||||||
|
final Indexer in = new Indexer(input, spoiler);
|
||||||
|
final Indexer out = new Indexer(
|
||||||
|
output,
|
||||||
|
ESCAPES.getOrDefault(spoiler, spoiler)
|
||||||
|
);
|
||||||
|
while (in.next() && out.next()) {
|
||||||
|
tests.add(Pair.of(in.cut(), out.cut()));
|
||||||
|
tests.add(Pair.of(in.escape(), output));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Indexer {
|
||||||
|
|
||||||
|
private final String string;
|
||||||
|
private final String spoiler;
|
||||||
|
private int index = -1;
|
||||||
|
|
||||||
|
public Indexer(final String string, final String spoiler) {
|
||||||
|
this.string = string;
|
||||||
|
this.spoiler = spoiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean next() {
|
||||||
|
index = string.indexOf(spoiler, index + 1);
|
||||||
|
return index >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String cut() {
|
||||||
|
return (
|
||||||
|
string.substring(0, index) +
|
||||||
|
string.substring(index + spoiler.length())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String escape() {
|
||||||
|
return string.substring(0, index) + "\\" + string.substring(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void open(final StringBuilder output, final String tag) {
|
||||||
|
output.append("<").append(tag).append(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void close(final StringBuilder output, final String tag) {
|
||||||
|
output.append("</").append(tag).append(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test(final TestCounter counter) {
|
||||||
|
counter.scope("Testing " + String.join(", ", tags.keySet()), () ->
|
||||||
|
new Checker(counter).test()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Checker extends BaseChecker {
|
||||||
|
|
||||||
|
public Checker(final TestCounter counter) {
|
||||||
|
super(counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void test() {
|
||||||
|
for (final Pair<String, String> test : tests) {
|
||||||
|
test(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final String markup : elements.keySet()) {
|
||||||
|
randomTest(3, 10, List.of(markup));
|
||||||
|
}
|
||||||
|
|
||||||
|
final int d = TestCounter.DENOMINATOR;
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
randomTest(100, 1000, randomMarkup());
|
||||||
|
}
|
||||||
|
randomTest(100, 100_000 / d, randomMarkup());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void test(final Pair<String, String> test) {
|
||||||
|
runner.testEquals(
|
||||||
|
counter,
|
||||||
|
Arrays.asList(test.first().split("\n")),
|
||||||
|
Arrays.asList(test.second().split("\n"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> randomMarkup() {
|
||||||
|
return Functional.map(tags.values(), random()::randomItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void randomTest(
|
||||||
|
final int paragraphs,
|
||||||
|
final int length,
|
||||||
|
final List<String> markup
|
||||||
|
) {
|
||||||
|
final StringBuilder input = new StringBuilder();
|
||||||
|
final StringBuilder output = new StringBuilder();
|
||||||
|
emptyLines(input);
|
||||||
|
final List<String> markupList = new ArrayList<>(markup);
|
||||||
|
for (int i = 0; i < paragraphs; i++) {
|
||||||
|
final StringBuilder inputSB = new StringBuilder();
|
||||||
|
paragraph(length, inputSB, output, markupList);
|
||||||
|
input.append(inputSB);
|
||||||
|
emptyLines(input);
|
||||||
|
}
|
||||||
|
test(Pair.of(input.toString(), output.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paragraph(
|
||||||
|
final int length,
|
||||||
|
final StringBuilder input,
|
||||||
|
final StringBuilder output,
|
||||||
|
final List<String> markup
|
||||||
|
) {
|
||||||
|
final int h = random().nextInt(0, 6);
|
||||||
|
final String tag = h == 0 ? "p" : "h" + h;
|
||||||
|
if (h > 0) {
|
||||||
|
input
|
||||||
|
.append(new String(new char[h]).replace('\0', '#'))
|
||||||
|
.append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
open(output, tag);
|
||||||
|
while (input.length() < length) {
|
||||||
|
generate(markup, input, output);
|
||||||
|
final String middle = random().randomString(
|
||||||
|
ExtendedRandom.ENGLISH
|
||||||
|
);
|
||||||
|
input.append(middle).append("\n");
|
||||||
|
output.append(middle).append("\n");
|
||||||
|
}
|
||||||
|
output.setLength(output.length() - 1);
|
||||||
|
close(output, tag);
|
||||||
|
|
||||||
|
output.append("\n");
|
||||||
|
input.append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void space(
|
||||||
|
final StringBuilder input,
|
||||||
|
final StringBuilder output
|
||||||
|
) {
|
||||||
|
if (random().nextBoolean()) {
|
||||||
|
final String space = random().nextBoolean() ? " " : "\n";
|
||||||
|
input.append(space);
|
||||||
|
output.append(space);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generate(
|
||||||
|
final List<String> markup,
|
||||||
|
final StringBuilder input,
|
||||||
|
final StringBuilder output
|
||||||
|
) {
|
||||||
|
word(input, output);
|
||||||
|
if (markup.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String type = random().randomItem(markup);
|
||||||
|
|
||||||
|
markup.remove(type);
|
||||||
|
elements.get(type).generate(this, markup, input, output);
|
||||||
|
markup.add(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void word(
|
||||||
|
final StringBuilder input,
|
||||||
|
final StringBuilder output
|
||||||
|
) {
|
||||||
|
final String word = random().randomString(
|
||||||
|
random().randomItem(
|
||||||
|
ExtendedRandom.ENGLISH,
|
||||||
|
ExtendedRandom.GREEK,
|
||||||
|
ExtendedRandom.RUSSIAN
|
||||||
|
)
|
||||||
|
);
|
||||||
|
input.append(word);
|
||||||
|
output.append(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void emptyLines(final StringBuilder sb) {
|
||||||
|
while (random().nextBoolean()) {
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String generateInput(final List<String> markup) {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
generate(markup, sb, new StringBuilder());
|
||||||
|
return sb
|
||||||
|
.toString()
|
||||||
|
.replace("<", "")
|
||||||
|
.replace(">", "")
|
||||||
|
.replace("]", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Generator {
|
||||||
|
void generate(
|
||||||
|
Checker checker,
|
||||||
|
List<String> markup,
|
||||||
|
StringBuilder input,
|
||||||
|
StringBuilder output
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
java/md2html/Pre.java
Normal file
11
java/md2html/Pre.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package md2html;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import markup.*;
|
||||||
|
|
||||||
|
public class Pre extends AbstractMarkup implements PartOfParagraph {
|
||||||
|
|
||||||
|
public Pre(List<PartOfParagraph> items) {
|
||||||
|
super(items, "```", "pre", "", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
8
java/md2html/package-info.java
Normal file
8
java/md2html/package-info.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Tests for <a href="https://www.kgeorgiy.info/courses/prog-intro/homeworks.html#md2html">Markdown to HTML</a> homework
|
||||||
|
* of <a href="https://www.kgeorgiy.info/courses/prog-intro/">Introduction to Programming</a> course.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
|
||||||
|
*/
|
||||||
|
package md2html;
|
||||||
Reference in New Issue
Block a user