Improvements for markdown parsing.
This commit is contained in:
parent
fc44290e3f
commit
8705859115
40 changed files with 957 additions and 537 deletions
|
@ -1,5 +1,6 @@
|
|||
set(COMPILER_UNIT_TEST_FILES
|
||||
compiler/TestTemplatingEngine.cpp
|
||||
compiler/TestLexer.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
|
|
19
test/compiler/TestLexer.cpp
Normal file
19
test/compiler/TestLexer.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include "Lexer.h"
|
||||
|
||||
#include "TestFramework.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE(TestLexer_MatchPattern, "[compiler]")
|
||||
{
|
||||
std::string input = "[I'm inside the tag](I'm inside the brackets), followed by more text.";
|
||||
std::string pattern = "[@](@)";
|
||||
|
||||
std::vector<std::string> hits;
|
||||
const auto matched = Lexer::matchPattern(pattern, input, '@', hits);
|
||||
REQUIRE(matched);
|
||||
REQUIRE(hits.size() == 2);
|
||||
REQUIRE(hits[0] == "I'm inside the tag");
|
||||
REQUIRE(hits[1] == "I'm inside the brackets");
|
||||
}
|
|
@ -3,13 +3,28 @@
|
|||
#include "TestFramework.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE(TestStringUtils_Strip, "core")
|
||||
TEST_CASE(TestStringUtils_StripSurroundingWhitepsace, "core")
|
||||
{
|
||||
std::string input = " super() ";
|
||||
std::string stripped = StringUtils::strip(input);
|
||||
|
||||
auto predicate = stripped == "super()";
|
||||
REQUIRE(predicate);
|
||||
std::string stripped = StringUtils::stripSurroundingWhitepsace(input);
|
||||
REQUIRE(stripped == "super()");
|
||||
}
|
||||
|
||||
TEST_CASE(TestStringUtils_RemoveUpTo, "core")
|
||||
{
|
||||
std::string input = "def{filename}abc/123/456";
|
||||
std::string removed = StringUtils::removeUpTo(input, "{filename}");
|
||||
REQUIRE(removed == "abc/123/456");
|
||||
}
|
||||
|
||||
TEST_CASE(TestStringUtils_startsWith, "core")
|
||||
{
|
||||
std::string input = " ```some triple ticks ";
|
||||
bool ignore_whitespace{false};
|
||||
auto starts_with = StringUtils::startsWith(input, "```", ignore_whitespace);
|
||||
REQUIRE(!starts_with);
|
||||
|
||||
ignore_whitespace = true;
|
||||
starts_with = StringUtils::startsWith(input, "```", ignore_whitespace);
|
||||
REQUIRE(starts_with);
|
||||
}
|
||||
|
|
30
test/data/simple_markdown.md
Normal file
30
test/data/simple_markdown.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
# I'm a level one header
|
||||
I'm some text under level one
|
||||
|
||||
## I'm a level two header
|
||||
I'm some text under level two
|
||||
|
||||
```
|
||||
I'm a code block
|
||||
```
|
||||
|
||||
I'm a line under the code block, with some `inline code`.
|
||||
|
||||
### I'm a level three header
|
||||
I'm a bullet point list:
|
||||
|
||||
* First point
|
||||
* Second point
|
||||
* Third point
|
||||
|
||||
With a [hyperlink](www.imahyperlink.com) embedded.
|
||||
|
||||
# I'm another level one header
|
||||
|
||||
I'm some inline math $a = b + c$ and I'm some standalone math:
|
||||
|
||||
$$
|
||||
d = e + f
|
||||
$$
|
||||
|
||||

|
|
@ -1,17 +1,22 @@
|
|||
#include "TestFramework.h"
|
||||
|
||||
#include "CommandLineArgs.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
//int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
|
||||
int main()
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
#endif
|
||||
|
||||
auto result = TestCaseRunner::getInstance().run();
|
||||
auto args = CommandLineArgs::Create();
|
||||
args->process(argc, argv);
|
||||
|
||||
auto result = TestCaseRunner::getInstance().run(args->getUserArgs());
|
||||
|
||||
#ifdef _WIN32
|
||||
CoUninitialize();
|
||||
|
|
|
@ -36,17 +36,30 @@ void TestCaseRunner::markTestFailure(const std::string& line)
|
|||
sFailureLine = line;
|
||||
}
|
||||
|
||||
bool TestCaseRunner::run()
|
||||
bool TestCaseRunner::run(const std::vector<std::string>& args)
|
||||
{
|
||||
std::string test_to_run;
|
||||
if (args.size() > 0 )
|
||||
{
|
||||
test_to_run = args[0];
|
||||
}
|
||||
FileLogger::GetInstance().disable();
|
||||
for (auto test_case : mCases)
|
||||
{
|
||||
if (!test_to_run.empty())
|
||||
{
|
||||
if (test_case->getName() != test_to_run)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sLastTestFailed = false;
|
||||
std::cout << "TestFramework: Running Test - " << test_case->getName() << std::endl;
|
||||
test_case->run();
|
||||
if (sLastTestFailed)
|
||||
{
|
||||
std::cout << "Failed at line: " << sLastTestFailed << std::endl;
|
||||
std::cout << "Failed at line: " << sFailureLine << std::endl;
|
||||
mFailingTests.push_back(test_case->getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
|
||||
void markTestFailure(const std::string& line);
|
||||
|
||||
bool run();
|
||||
bool run(const std::vector<std::string>& args);
|
||||
|
||||
private:
|
||||
std::vector<std::string> mFailingTests;
|
||||
|
|
|
@ -16,12 +16,12 @@ struct Holder
|
|||
static void Test##NAME() \
|
||||
|
||||
|
||||
#define REQUIRE(predicate) \
|
||||
if(!predicate) \
|
||||
{ \
|
||||
TestCaseRunner::getInstance().markTestFailure(std::to_string(__LINE__)); \
|
||||
return; \
|
||||
} \
|
||||
#define REQUIRE(predicate) \
|
||||
if(!bool(predicate)) \
|
||||
{ \
|
||||
TestCaseRunner::getInstance().markTestFailure(std::to_string(__LINE__) + " with check: '" + std::string(#predicate) + "'"); \
|
||||
return; \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -7,9 +7,17 @@ using Path = std::filesystem::path;
|
|||
class TestUtils
|
||||
{
|
||||
public:
|
||||
static Path getTestOutputDir()
|
||||
static Path getTestOutputDir(const std::string& testFileName = {})
|
||||
{
|
||||
return std::filesystem::current_path() / "test_output";
|
||||
if (!testFileName.empty())
|
||||
{
|
||||
const auto name = Path(testFileName).filename().stem();
|
||||
return std::filesystem::current_path() / "test_output" / name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::filesystem::current_path() / "test_output";
|
||||
}
|
||||
}
|
||||
|
||||
static Path getTestDataDir()
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include "TestFramework.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
TEST_CASE(TestMarkdownParser, "web")
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE(TestMarkdownParser, "[web]")
|
||||
{
|
||||
File md_file(TestUtils::getTestDataDir() / "sample_markdown.md");
|
||||
const auto md_content = md_file.readText();
|
||||
|
@ -19,12 +21,59 @@ TEST_CASE(TestMarkdownParser, "web")
|
|||
MarkdownParser parser;
|
||||
auto md_doc = parser.run(md_content);
|
||||
|
||||
std::vector<MarkdownElement::Type> expected_top_level = {
|
||||
MarkdownElement::Type::HEADING,
|
||||
MarkdownElement::Type::PARAGRAPH,
|
||||
MarkdownElement::Type::HEADING,
|
||||
MarkdownElement::Type::PARAGRAPH,
|
||||
MarkdownElement::Type::MULTILINE_QUOTE,
|
||||
MarkdownElement::Type::PARAGRAPH,
|
||||
MarkdownElement::Type::HEADING,
|
||||
MarkdownElement::Type::PARAGRAPH
|
||||
};
|
||||
|
||||
REQUIRE(expected_top_level.size() <= md_doc->getNumElements());
|
||||
for(unsigned idx=0; idx<expected_top_level.size(); idx++)
|
||||
{
|
||||
REQUIRE(md_doc->getElement(idx)->getType() == expected_top_level[idx]);
|
||||
}
|
||||
|
||||
MarkdownConverter converter;
|
||||
auto html = converter.convert(md_doc.get());
|
||||
|
||||
HtmlWriter writer;
|
||||
const auto html_string = writer.toString(html.get());
|
||||
|
||||
File html_file(TestUtils::getTestOutputDir() / "TestMarkdownParserOut.html");
|
||||
File html_file(TestUtils::getTestOutputDir(__FILE__) / "TestMarkdownParser.html");
|
||||
html_file.writeText(html_string);
|
||||
}
|
||||
|
||||
TEST_CASE(TestMarkdownParser_Simple, "[web]")
|
||||
{
|
||||
File md_file(TestUtils::getTestDataDir() / "simple_markdown.md");
|
||||
const auto md_content = md_file.readText();
|
||||
|
||||
REQUIRE(!md_content.empty());
|
||||
|
||||
MarkdownParser parser;
|
||||
auto md_doc = parser.run(md_content);
|
||||
|
||||
std::vector<MarkdownElement::Type> expected_top_level = {
|
||||
MarkdownElement::Type::PARAGRAPH,
|
||||
MarkdownElement::Type::BULLET_LIST};
|
||||
|
||||
//REQUIRE(expected_top_level.size() <= md_doc->getNumElements());
|
||||
for(unsigned idx=0; idx<expected_top_level.size(); idx++)
|
||||
{
|
||||
//REQUIRE(md_doc->getElement(idx)->getType() == expected_top_level[idx]);
|
||||
}
|
||||
|
||||
MarkdownConverter converter;
|
||||
auto html = converter.convert(md_doc.get());
|
||||
|
||||
HtmlWriter writer;
|
||||
const auto html_string = writer.toString(html.get());
|
||||
|
||||
File html_file(TestUtils::getTestOutputDir(__FILE__) / "TestMarkdownParser_simple.html");
|
||||
html_file.writeText(html_string);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue