commit 569794c4b648bb2d3d4757deb6c6dbfa48b61d81 Author: M. Petra Baranski Date: Mon Dec 25 12:22:35 2017 +0100 initial release 1.0.0 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5c2baf6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{h,hh,hpp,c,cc,cpp,cxx}] +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ef7c1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,497 @@ +# Created by https://www.gitignore.io/api/vim,c++,xcode,clion,macos,valgrind,visualstudio,visualstudiocode + +### C++ ### +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +### CLion ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# CMake +cmake-build-debug/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Ruby plugin and RubyMine +/.rakeTasks + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### CLion Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Valgrind ### +# Callgrind output files +callgrind.out +callgrind.out.* + +# Cachegrind output files +cachegrind.out +cachegrind.out.* + +# Massif output files +massif.out +massif.out.* + +# BBV output files +bb.out +bb.out.* + + + +### Vim ### +# swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-v][a-z] +[._]sw[a-p] +# session +Session.vim +# temporary +.netrwhist +*~ +# auto-generated tag files +tags + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Xcode ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + +# End of https://www.gitignore.io/api/vim,c++,xcode,clion,macos,valgrind,visualstudio,visualstudiocode + +tmp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a692fc2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libs/gtest"] + path = libs/gtest + url = https://github.com/google/googletest.git diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..de388e1 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,7 @@ +The following authors have all licensed their contributions to maddy under the +licensing terms detailed in LICENSE. + +(Authors keep copyright of their contributions, of course; they just grant +a license to everyone to use it as detailed in LICENSE.) + +M. Petra Baranski (info@progsource.de) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ce9e447 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,55 @@ +# This project is licensed under the MITlicense. For more information see the +# LICENSE file. + +cmake_minimum_required(VERSION 2.8) + +project(maddy) + +enable_testing() + +# ------------------------------------------------------------------------------ + +set(MADDY_CPP_VERSION 14) +add_definitions(-DCPP_VERSION=${MADDY_CPP_VERSION}) + +# ------------------------------------------------------------------------------ + +set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build) +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) +set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}) + +# ------------------------------------------------------------------------------ + +set(MADDY_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) +file(GLOB_RECURSE MADDY_TESTS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/maddy/*.cpp) + +# ------------------------------------------------------------------------------ + +set( + CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -g -std=c++${MADDY_CPP_VERSION} -Wall -Wpedantic -Wextra -Wno-ignored-qualifiers -fno-rtti -fno-exceptions" # -O2 +) + +# ------------------------------------------------------------------------------ + +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/gtest/googlemock) +add_subdirectory(libs) + +# ------------------------------------------------------------------------------ + +include_directories( + ${LIBS_INCLUDE_DIRS} + ${MADDY_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/tests +) + +# ------------------------------------------------------------------------------ + +add_executable( + MaddyTests + ${MADDY_TESTS_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/tests/main.cpp +) +target_link_libraries(MaddyTests gmock_main) +add_test(MaddyTests ${CMAKE_CURRENT_SOURCE_DIR}/build/MaddyTests) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..85ae8d0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +Copyright 2017 M. Petra Baranski + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4864251 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# maddy + +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-brightgreen.svg)](https://semver.org/) + +maddy is a C++ Markdown to HTML **header-only** parser library. + +## Supportes OS + +It actually should work on any OS, that supports the C++14 standard library. + +It is tested to work on: + +* Linux (without exceptions and without RTTI) + +## Dependencies + +* C++14 + +## Why maddy? + +When I was needing a Markdown parser in C++ I couldn't find any, that was +fitting my needs. So I simply wrote my own one. + +## Markdown syntax + +The supported syntax can be found in the [definitions docs](docs/definitions.md). + +## HowTo use + +To use maddy in your project, simply add the include path of maddy to yours +and in the code, you can then do the following: + +```c++ +#include +#include + +#include "maddy/parser.h" + +std::stringstream markdownInput(""); +std::shared_ptr parser = std::make_shared(); +std::string htmlOutput = parser->Parse(markdownInput); +``` + +## How to contribute + +There are different possibilities: + +* Create a GitHub issue +* Create a pull request with an own branch (don't forget to put yourself in the + AUTHORS file) diff --git a/docs/definitions.md b/docs/definitions.md new file mode 100644 index 0000000..431fe1b --- /dev/null +++ b/docs/definitions.md @@ -0,0 +1,303 @@ +# Markdown Definitions + +This specification defines which markdown syntax can be parsed by maddy. +There is no HTML allowed in the markdown syntax - or said otherwise - it might +destroy the output, if there was HTML in your markdown. + +The Parser expects you to use spaces and not tabs for indentation in the +markdown. + +## Headlines + +``` +# h1 heading +## h2 heading +### h3 heading +#### h4 heading +##### h5 heading +###### h6 heading +``` +results in: +```html +

h1 heading

+

h2 heading

+

h3 heading

+

h4 heading

+
h5 heading
+
h6 heading
+``` + +## Links + +``` +[Text of the link](http://example.com) +``` +results in +```html +Text of the link +``` + +## Lists + +### unordered +``` + +* unordered +* list +* items + +``` +results in +```html +
    +
  • unordered
  • +
  • list
  • +
  • items
  • +
+``` + +``` + +* unorederd + * list + * items + * in + * an + * hierarchy + +``` +results in +```html +
    +
  • list
  • +
  • items +
      +
    • in
    • +
    • an
    • +
    +
  • +
  • hierarchy
  • +
+``` + +### ordered + +``` + +1. ordered +* list +* items + +``` +results in +```html +
    +
  1. ordered
  2. +
  3. list
  4. +
  5. items
  6. +
+``` + +``` + +1. ordered +* list + 1. items + * in + 1. an + * hierarchy + +``` +results in +```html +
    +
  1. ordered
  2. +
  3. list +
      +
    1. items
    2. +
    3. in +
        an
      +
    4. +
    5. hierarchy
    6. +
    +
  4. +
+``` + +### combination + +``` + +* combination +* of + 1. unordered and + * ordered +* list + +``` +results in +```html +
    +
  • combination
  • +
  • of +
      +
    1. unordered and
    2. +
    3. ordered
    4. +
    +
  • +
  • list
  • +
+``` + +### checklist + +``` + +- [ ] some item + - [ ] another item +- [x] some checked item + +``` +results in +```html +
    +
  • +
  • +
+``` +might not work in combination with other lists + +## Code Blocks + + ``` + some code + ``` + +results in +```html +

+some code
+
+``` + +## Inline code + + some text `some inline code` some other text + +results in +```html +some text some inline code some other text +``` + +## quotes + +``` +> Some quote +``` +results in +```html + +

Some quote

+ +``` + +## bold + +``` +**bold text** +``` +results in +```html +bold text +``` + +## emphasized + +``` +*emphasized text* +``` +results in +```html +emphasized text +``` + +## strikethrough + +``` +~~striked through text~~ +``` +results in +```html +striked through text +``` + +## horizontal line + +``` +--- +``` +results in +```html +
+``` + +## Images + +``` +![Image alt text](http://example.com/example.png) +``` +results in +```html +Image alt text +``` + +## Tables + +``` + +|table> +Left header | middle header | last header +- | - | - +cell 1 | cell 2 | cell 3 +cell 4 | cell 5 | cell 6 +- | - | - +foot a | foot b | foot c +| + + + + + + + + + + + + + + + + + + + + + + + + + + +
Left headermiddle headerlast header
cell 1cell 2cell 3
cell 4cell 5cell 6
foot afoot bfoot c
+``` +table header and footer are optional diff --git a/include/maddy/blockparser.h b/include/maddy/blockparser.h new file mode 100644 index 0000000..00bf5f3 --- /dev/null +++ b/include/maddy/blockparser.h @@ -0,0 +1,190 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * BlockParser + * + * The code expects every child to have the following static function to be + * implemented: + * `static bool IsStartingLine(const std::string& line)` + * + * @class + */ +class BlockParser +{ +public: + /** + * ctor + * + * @method + * @param {std::function} parseLineCallback + * @param {std::function(const std::string& line)>} getBlockParserForLineCallback + */ + BlockParser( + std::function parseLineCallback, + std::function(const std::string& line)> getBlockParserForLineCallback + ) + : result("", std::ios_base::ate | std::ios_base::in | std::ios_base::out) + , childParser(nullptr) + , parseLineCallback(parseLineCallback) + , getBlockParserForLineCallback(getBlockParserForLineCallback) + {} + + /** + * AddLine + * + * Adding a line which has to be parsed. + * + * @method + * @param {std::string&} line + * @return {void} + */ + virtual void + AddLine(std::string& line) + { + this->parseBlock(line); + + if (this->isInlineBlockAllowed() && !this->childParser) + { + this->childParser = this->getBlockParserForLine(line); + } + + if (this->childParser) + { + this->childParser->AddLine(line); + + if (this->childParser->IsFinished()) + { + this->result << this->childParser->GetResult().str(); + this->childParser = nullptr; + } + + return; + } + + if (this->isLineParserAllowed()) + { + this->parseLine(line); + } + + this->result << line; + } + + /** + * IsFinished + * + * Check if the BlockParser is done + * + * @method + * @return {bool} + */ + virtual bool IsFinished() const = 0; + + /** + * GetResult + * + * Get the parsed HTML output. + * + * @method + * @return {std::stringstream} + */ + std::stringstream& + GetResult() + { + return this->result; + } + + /** + * Clear + * + * Clear the result to reuse the parser object. + * + * It is only used by one test for now. + * + * @method + * @return {void} + */ + void + Clear() + { + this->result.str(""); + } + +protected: + std::stringstream result; + std::shared_ptr childParser; + + virtual bool isInlineBlockAllowed() const = 0; + virtual bool isLineParserAllowed() const = 0; + virtual void parseBlock(std::string& line) = 0; + + void + parseLine(std::string& line) + { + if (parseLineCallback) + { + parseLineCallback(line); + } + } + + uint32_t + getIndentationWidth(const std::string& line) const + { + bool hasMetNonSpace = false; + + uint32_t indentation = std::count_if( + line.begin(), + line.end(), + [&hasMetNonSpace](unsigned char c) + { + if (hasMetNonSpace) + { + return false; + } + + if (std::isspace(c)) + { + return true; + } + + hasMetNonSpace = true; + return false; + } + ); + + return indentation; + } + + std::shared_ptr + getBlockParserForLine(const std::string& line) + { + if (getBlockParserForLineCallback) + { + return getBlockParserForLineCallback(line); + } + + return nullptr; + } + +private: + std::function parseLineCallback; + std::function(const std::string& line)> getBlockParserForLineCallback; +}; // class BlockParser + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/include/maddy/checklistparser.h b/include/maddy/checklistparser.h new file mode 100644 index 0000000..bfc487c --- /dev/null +++ b/include/maddy/checklistparser.h @@ -0,0 +1,140 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include +#include + +#include "maddy/blockparser.h" + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * ChecklistParser + * + * @class + */ +class ChecklistParser : public BlockParser +{ +public: + /** + * ctor + * + * @method + * @param {std::function} parseLineCallback + * @param {std::function(const std::string& line)>} getBlockParserForLineCallback + */ + ChecklistParser( + std::function parseLineCallback, + std::function(const std::string& line)> getBlockParserForLineCallback + ) + : BlockParser(parseLineCallback, getBlockParserForLineCallback) + , isStarted(false) + , isFinished(false) + {} + + /** + * IsStartingLine + * + * An unordered list starts with `* `. + * + * @method + * @param {const std::string&} line + * @return {bool} + */ + static bool + IsStartingLine(const std::string& line) + { + static std::regex re("^- \\[[x| ]\\] .*"); + return std::regex_match(line, re); + } + + /** + * IsFinished + * + * @method + * @return {bool} + */ + bool + IsFinished() const override + { + return this->isFinished; + } + +protected: + bool + isInlineBlockAllowed() const override + { + return true; + } + + bool + isLineParserAllowed() const override + { + return true; + } + + void + parseBlock(std::string& line) override + { + bool isStartOfNewListItem = IsStartingLine(line); + uint32_t indentation = getIndentationWidth(line); + + static std::regex lineRegex("^(- )"); + line = std::regex_replace(line, lineRegex, ""); + + static std::regex emptyBoxRegex("^\\[ \\]"); + static std::string emptyBoxReplacement = ""; + line = std::regex_replace(line, emptyBoxRegex, emptyBoxReplacement); + + static std::regex boxRegex("^\\[x\\]"); + static std::string boxReplacement = ""; + line = std::regex_replace(line, boxRegex, boxReplacement); + + if (!this->isStarted) + { + line = "
") != std::string::npos + ) + { + line = "" + line; + this->isFinished = true; + return; + } + + if (isStartOfNewListItem) + { + line = "
  • ") != std::string::npos + ) + { + line = "" + line; + this->isFinished = true; + return; + } + + if (isStartOfNewListItem) + { + line = "
  • " + line; + } + } + +private: + bool isStarted; + bool isFinished; + + bool + isStartOfNewListItem(const std::string& line) const + { + static std::regex re("^(?:1\\. |\\* ).*"); + return std::regex_match(line, re); + } +}; // class OrderedListParser + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/include/maddy/paragraphparser.h b/include/maddy/paragraphparser.h new file mode 100644 index 0000000..984f7b4 --- /dev/null +++ b/include/maddy/paragraphparser.h @@ -0,0 +1,114 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include + +#include "maddy/blockparser.h" + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * ParagraphParser + * + * @class + */ +class ParagraphParser : public BlockParser +{ +public: + /** + * ctor + * + * @method + * @param {std::function} parseLineCallback + * @param {std::function(const std::string& line)>} getBlockParserForLineCallback + */ + ParagraphParser( + std::function parseLineCallback, + std::function(const std::string& line)> getBlockParserForLineCallback + ) + : BlockParser(parseLineCallback, getBlockParserForLineCallback) + , isStarted(false) + , isFinished(false) + {} + + /** + * IsStartingLine + * + * If the line is not empty, it will be a paragraph. So this block parser has + * to always run as the last one! + * + * @method + * @param {const std::string&} line + * @return {bool} + */ + static bool + IsStartingLine(const std::string& line) + { + return !line.empty(); + } + + /** + * IsFinished + * + * An empty line will end the paragraph. + * + * @method + * @return {bool} + */ + bool + IsFinished() const override + { + return this->isFinished; + } + +protected: + bool + isInlineBlockAllowed() const override + { + return false; + } + + bool + isLineParserAllowed() const override + { + return true; + } + + void + parseBlock(std::string& line) override + { + if (!this->isStarted) + { + line = "

    " + line + " "; + this->isStarted = true; + return; + } + + if (line.empty()) + { + line += "

    "; + this->isFinished = true; + return; + } + + line += " "; + } + +private: + bool isStarted; + bool isFinished; +}; // class ParagraphParser + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/include/maddy/parser.h b/include/maddy/parser.h new file mode 100644 index 0000000..f1b6f34 --- /dev/null +++ b/include/maddy/parser.h @@ -0,0 +1,255 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include +#include + +// BlockParser +#include "maddy/checklistparser.h" +#include "maddy/codeblockparser.h" +#include "maddy/headlineparser.h" +#include "maddy/horizontallineparser.h" +#include "maddy/orderedlistparser.h" +#include "maddy/paragraphparser.h" +#include "maddy/quoteparser.h" +#include "maddy/tableparser.h" +#include "maddy/unorderedlistparser.h" + +// LineParser +#include "maddy/emphasizedparser.h" +#include "maddy/imageparser.h" +#include "maddy/inlinecodeparser.h" +#include "maddy/linkparser.h" +#include "maddy/strikethroughparser.h" +#include "maddy/strongparser.h" + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * Parser + * + * Transforms Markdown to HTML + * + * @class + */ +class Parser +{ +public: + /** + * ctor + * + * Initializes all `LineParser` + * + * @method + */ + Parser() + : emphasizedParser(std::make_shared()) + , imageParser(std::make_shared()) + , inlineCodeParser(std::make_shared()) + , linkParser(std::make_shared()) + , strikeThroughParser(std::make_shared()) + , strongParser(std::make_shared()) + {} + + /** + * Parse + * + * @method + * @param {const std::stringstream&} markdown + * @return {std::string} HTML + */ + std::string + Parse(std::stringstream& markdown) const + { + std::string result = ""; + std::shared_ptr currentBlockParser = nullptr; + + for (std::string line; std::getline(markdown, line);) + { + if (!currentBlockParser) + { + currentBlockParser = getBlockParserForLine(line); + } + + if (currentBlockParser) + { + currentBlockParser->AddLine(line); + + if (currentBlockParser->IsFinished()) + { + result += currentBlockParser->GetResult().str(); + currentBlockParser = nullptr; + } + } + } + + return result; + } + +private: + std::shared_ptr emphasizedParser; + std::shared_ptr imageParser; + std::shared_ptr inlineCodeParser; + std::shared_ptr linkParser; + std::shared_ptr strikeThroughParser; + std::shared_ptr strongParser; + + // block parser have to run before + void + runLineParser(std::string& line) const + { + // Attention! ImageParser has to be before LinkParser + this->imageParser->Parse(line); + this->linkParser->Parse(line); + + // Attention! StrongParser has to be before EmphasizedParser + this->strongParser->Parse(line); + this->emphasizedParser->Parse(line); + + this->strikeThroughParser->Parse(line); + + this->inlineCodeParser->Parse(line); + } + + std::shared_ptr + getBlockParserForLine(const std::string& line) const + { + std::shared_ptr parser; + + if (maddy::CodeBlockParser::IsStartingLine(line)) + { + parser = std::make_shared( + nullptr, + nullptr + ); + } + else if (maddy::HeadlineParser::IsStartingLine(line)) + { + parser = std::make_shared( + nullptr, + nullptr + ); + } + else if (maddy::HorizontalLineParser::IsStartingLine(line)) + { + parser = std::make_shared( + nullptr, + nullptr + ); + } + else if (maddy::QuoteParser::IsStartingLine(line)) + { + parser = std::make_shared( + [this](std::string& line){ this->runLineParser(line); }, + [this](const std::string& line){ return this->getBlockParserForLine(line); } + ); + } + else if (maddy::TableParser::IsStartingLine(line)) + { + parser = std::make_shared( + [this](std::string& line){ this->runLineParser(line); }, + nullptr + ); + } + else if (maddy::ChecklistParser::IsStartingLine(line)) + { + parser = this->createChecklistParser(); + } + else if (maddy::OrderedListParser::IsStartingLine(line)) + { + parser = this->createOrderedListParser(); + } + else if (maddy::UnorderedListParser::IsStartingLine(line)) + { + parser = this->createUnorderedListParser(); + } + else if (maddy::ParagraphParser::IsStartingLine(line)) + { + parser = std::make_shared( + [this](std::string& line){ this->runLineParser(line); }, + nullptr + ); + } + + return parser; + } + + std::shared_ptr + createChecklistParser() const + { + return std::make_shared( + [this](std::string& line){ this->runLineParser(line); }, + [this](const std::string& line) + { + std::shared_ptr parser; + + if (maddy::ChecklistParser::IsStartingLine(line)) + { + parser = this->createChecklistParser(); + } + + return parser; + } + ); + } + + std::shared_ptr + createOrderedListParser() const + { + return std::make_shared( + [this](std::string& line){ this->runLineParser(line); }, + [this](const std::string& line) + { + std::shared_ptr parser; + + if (maddy::OrderedListParser::IsStartingLine(line)) + { + parser = this->createOrderedListParser(); + } + else if (maddy::UnorderedListParser::IsStartingLine(line)) + { + parser = this->createUnorderedListParser(); + } + + return parser; + } + ); + } + + std::shared_ptr + createUnorderedListParser() const + { + return std::make_shared( + [this](std::string& line){ this->runLineParser(line); }, + [this](const std::string& line) + { + std::shared_ptr parser; + + if (maddy::OrderedListParser::IsStartingLine(line)) + { + parser = this->createOrderedListParser(); + } + else if (maddy::UnorderedListParser::IsStartingLine(line)) + { + parser = this->createUnorderedListParser(); + } + + return parser; + } + ); + } +}; // class Parser + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/include/maddy/quoteparser.h b/include/maddy/quoteparser.h new file mode 100644 index 0000000..a3b48d0 --- /dev/null +++ b/include/maddy/quoteparser.h @@ -0,0 +1,165 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include +#include + +#include "maddy/blockparser.h" + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * QuoteParser + * + * @class + */ +class QuoteParser : public BlockParser +{ +public: + /** + * ctor + * + * @method + * @param {std::function} parseLineCallback + * @param {std::function(const std::string& line)>} getBlockParserForLineCallback + */ + QuoteParser( + std::function parseLineCallback, + std::function(const std::string& line)> getBlockParserForLineCallback + ) + : BlockParser(parseLineCallback, getBlockParserForLineCallback) + , isStarted(false) + , isFinished(false) + {} + + /** + * IsStartingLine + * + * A quote starts with `> `. + * + * @method + * @param {const std::string&} line + * @return {bool} + */ + static bool + IsStartingLine(const std::string& line) + { + static std::regex re("^\\>.*"); + return std::regex_match(line, re); + } + + /** + * AddLine + * + * Adding a line which has to be parsed. + * + * @method + * @param {std::string&} line + * @return {void} + */ + void + AddLine(std::string& line) override + { + if (!this->isStarted) + { + this->result << "
    "; + this->isStarted = true; + } + + bool finish = false; + if (line.empty()) + { + finish = true; + } + + this->parseBlock(line); + + if (this->isInlineBlockAllowed() && !this->childParser) + { + this->childParser = this->getBlockParserForLine(line); + } + + if (this->childParser) + { + this->childParser->AddLine(line); + + if (this->childParser->IsFinished()) + { + this->result << this->childParser->GetResult().str(); + this->childParser = nullptr; + } + + return; + } + + if (this->isLineParserAllowed()) + { + this->parseLine(line); + } + + if (finish) + { + this->result << "
    "; + this->isFinished = true; + } + + this->result << line; + } + + /** + * IsFinished + * + * @method + * @return {bool} + */ + bool + IsFinished() const override + { + return this->isFinished; + } + +protected: + bool + isInlineBlockAllowed() const override + { + return true; + } + + bool + isLineParserAllowed() const override + { + return true; + } + + void + parseBlock(std::string& line) override + { + static std::regex lineRegexWithSpace("^\\> "); + line = std::regex_replace(line, lineRegexWithSpace, ""); + static std::regex lineRegexWithoutSpace("^\\>"); + line = std::regex_replace(line, lineRegexWithoutSpace, ""); + + if (!line.empty()) + { + line += " "; + } + } + +private: + bool isStarted; + bool isFinished; +}; // class QuoteParser + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/include/maddy/strikethroughparser.h b/include/maddy/strikethroughparser.h new file mode 100644 index 0000000..22fb1c4 --- /dev/null +++ b/include/maddy/strikethroughparser.h @@ -0,0 +1,51 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include + +#include "maddy/lineparser.h" + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * StrikeThroughParser + * + * @class + */ +class StrikeThroughParser : public LineParser +{ +public: + /** + * Parse + * + * From Markdown: `text ~~text~~` + * + * To HTML: `text text` + * + * @method + * @param {std::string&} line The line to interpret + * @return {void} + */ + void + Parse(std::string& line) override + { + static std::regex re("\\~\\~([^\\~]*)\\~\\~"); + static std::string replacement = "$1"; + + line = std::regex_replace(line, re, replacement); + } +}; // class StrikeThroughParser + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/include/maddy/strongparser.h b/include/maddy/strongparser.h new file mode 100644 index 0000000..339af79 --- /dev/null +++ b/include/maddy/strongparser.h @@ -0,0 +1,53 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include + +#include "maddy/lineparser.h" + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * StrongParser + * + * Has to be used before the `EmphasizedParser`. + * + * @class + */ +class StrongParser : public LineParser +{ +public: + /** + * Parse + * + * From Markdown: `text **text**` + * + * To HTML: `text text` + * + * @method + * @param {std::string&} line The line to interpret + * @return {void} + */ + void + Parse(std::string& line) override + { + static std::regex re("\\*\\*([^\\*\\*]*)\\*\\*"); + static std::string replacement = "$1"; + + line = std::regex_replace(line, re, replacement); + } +}; // class StrongParser + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/include/maddy/tableparser.h b/include/maddy/tableparser.h new file mode 100644 index 0000000..c230cc6 --- /dev/null +++ b/include/maddy/tableparser.h @@ -0,0 +1,246 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include +#include + +#include "maddy/blockparser.h" + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * TableParser + * + * For more information, see the docs folder. + * + * @class + */ +class TableParser : public BlockParser +{ +public: + /** + * ctor + * + * @method + * @param {std::function} parseLineCallback + * @param {std::function(const std::string& line)>} getBlockParserForLineCallback + */ + TableParser( + std::function parseLineCallback, + std::function(const std::string& line)> getBlockParserForLineCallback + ) + : BlockParser(parseLineCallback, getBlockParserForLineCallback) + , isStarted(false) + , isFinished(false) + , currentBlock(0) + , currentRow(0) + {} + + /** + * IsStartingLine + * + * If the line has exact `|table>`, then it is starting the table. + * + * @method + * @param {const std::string&} line + * @return {bool} + */ + static bool + IsStartingLine(const std::string& line) + { + static std::string matchString("|table>"); + return line == matchString; + } + + /** + * AddLine + * + * Adding a line which has to be parsed. + * + * @method + * @param {std::string&} line + * @return {void} + */ + void + AddLine(std::string& line) override + { + if (!this->isStarted && line == "|table>") + { + this->isStarted = true; + return; + } + + if (this->isStarted) + { + if (line == "- | - | -") + { + ++this->currentBlock; + this->currentRow = 0; + return; + } + + if (line == "|parseBlock(emptyLine); + this->isFinished = true; + return; + } + + if (this->table.size() < this->currentBlock + 1) + { + this->table.push_back(std::vector>()); + } + this->table[this->currentBlock].push_back(std::vector()); + + std::string segment; + std::stringstream streamToSplit(line); + + while (std::getline(streamToSplit, segment, '|')) + { + this->parseLine(segment); + this->table[this->currentBlock][this->currentRow].push_back(segment); + } + + ++this->currentRow; + } + } + + /** + * IsFinished + * + * A table ends with `|isFinished; + } + +protected: + bool + isInlineBlockAllowed() const override + { + return false; + } + + bool + isLineParserAllowed() const override + { + return true; + } + + void + parseBlock(std::string&) override + { + result << ""; + + bool hasHeader = false; + bool hasFooter = false; + bool isFirstBlock = true; + uint32_t currentBlockNumber = 0; + + if (this->table.size() > 1) + { + hasHeader = true; + } + + if (this->table.size() >= 3) + { + hasFooter = true; + } + + for (const std::vector>& block : this->table) + { + bool isInHeader = false; + bool isInFooter = false; + ++currentBlockNumber; + + if (hasHeader && isFirstBlock) + { + result << ""; + isInHeader = true; + } + else if (hasFooter && currentBlockNumber == this->table.size()) + { + result << ""; + isInFooter = true; + } + else + { + result << ""; + } + + for (const std::vector& row : block) + { + result << ""; + + for (const std::string& column : row) + { + if (isInHeader) + { + result << ""; + } + } + + result << ""; + } + + if (isInHeader) + { + result << ""; + } + else if (isInFooter) + { + result << ""; + } + else + { + result << ""; + } + + isFirstBlock = false; + } + + result << "
    "; + } + else + { + result << ""; + } + + result << column; + + if (isInHeader) + { + result << ""; + } + else + { + result << "
    "; + } + +private: + bool isStarted; + bool isFinished; + uint32_t currentBlock; + uint32_t currentRow; + std::vector>> table; +}; // class TableParser + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/include/maddy/unorderedlistparser.h b/include/maddy/unorderedlistparser.h new file mode 100644 index 0000000..d8706af --- /dev/null +++ b/include/maddy/unorderedlistparser.h @@ -0,0 +1,133 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +// ----------------------------------------------------------------------------- + +#include +#include +#include + +#include "maddy/blockparser.h" + +// ----------------------------------------------------------------------------- + +namespace maddy { + +// ----------------------------------------------------------------------------- + +/** + * UnorderedListParser + * + * @class + */ +class UnorderedListParser : public BlockParser +{ +public: + /** + * ctor + * + * @method + * @param {std::function} parseLineCallback + * @param {std::function(const std::string& line)>} getBlockParserForLineCallback + */ + UnorderedListParser( + std::function parseLineCallback, + std::function(const std::string& line)> getBlockParserForLineCallback + ) + : BlockParser(parseLineCallback, getBlockParserForLineCallback) + , isStarted(false) + , isFinished(false) + {} + + /** + * IsStartingLine + * + * An unordered list starts with `* `. + * + * @method + * @param {const std::string&} line + * @return {bool} + */ + static bool + IsStartingLine(const std::string& line) + { + static std::regex re("^\\* .*"); + return std::regex_match(line, re); + } + + /** + * IsFinished + * + * @method + * @return {bool} + */ + bool + IsFinished() const override + { + return this->isFinished; + } + +protected: + bool + isInlineBlockAllowed() const override + { + return true; + } + + bool + isLineParserAllowed() const override + { + return true; + } + + void + parseBlock(std::string& line) override + { + bool isStartOfNewListItem = IsStartingLine(line); + uint32_t indentation = getIndentationWidth(line); + + static std::regex lineRegex("^(\\* )"); + line = std::regex_replace(line, lineRegex, ""); + + if (!this->isStarted) + { + line = "
    • " + line; + this->isStarted = true; + return; + } + + if (indentation >= 2) + { + line = line.substr(2); + return; + } + + if ( + line.empty() || + line.find("
    • ") != std::string::npos || + line.find("
    • ") != std::string::npos || + line.find("
    ") != std::string::npos + ) + { + line = "
  • " + line; + this->isFinished = true; + return; + } + + if (isStartOfNewListItem) + { + line = "
  • " + line; + } + } + +private: + bool isStarted; + bool isFinished; +}; // class UnorderedListParser + +// ----------------------------------------------------------------------------- + +} // namespace maddy diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt new file mode 100644 index 0000000..ec8335f --- /dev/null +++ b/libs/CMakeLists.txt @@ -0,0 +1,14 @@ +# This project is licensed under the MIT license. For more information see the +# LICENSE file. + +cmake_minimum_required(VERSION 2.8) + +set(LIBS_INCLUDE_DIRS +# -- googletest / -mock -------------------------------------------------------- + ${CMAKE_CURRENT_SOURCE_DIR}/gtest/googletest/include + ${CMAKE_CURRENT_SOURCE_DIR}/gtest/googlemock/include +# ------------------------------------------------------------------------------ +PARENT_SCOPE) + +set(LIBS_SRC_FILES +PARENT_SCOPE) diff --git a/libs/gtest b/libs/gtest new file mode 160000 index 0000000..5490beb --- /dev/null +++ b/libs/gtest @@ -0,0 +1 @@ +Subproject commit 5490beb0602eab560fa3969a4410e11d94bf12af diff --git a/tests/maddy/test_maddy_checklistparser.cpp b/tests/maddy/test_maddy_checklistparser.cpp new file mode 100644 index 0000000..927652c --- /dev/null +++ b/tests/maddy/test_maddy_checklistparser.cpp @@ -0,0 +1,99 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/checklistparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_CHECKLISTPARSER : public ::testing::Test +{ +protected: + std::shared_ptr clParser; + + void + SetUp() override + { + std::function(const std::string& line)> getBlockParserForLineCallback = [](const std::string& line) + { + if (maddy::ChecklistParser::IsStartingLine(line)) + { + return std::static_pointer_cast( + std::make_shared(nullptr, nullptr) + ); + } + + std::shared_ptr empty; + return empty; + }; + + this->clParser = std::make_shared( + nullptr, + getBlockParserForLineCallback + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_CHECKLISTPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfList) +{ + ASSERT_TRUE(maddy::ChecklistParser::IsStartingLine("- [ ] a")); + ASSERT_TRUE(maddy::ChecklistParser::IsStartingLine("- [x] b")); +} + +TEST_F(MADDY_CHECKLISTPARSER, IsFinishedAlwaysReturnsFalseInTheBeginning) +{ + ASSERT_FALSE(clParser->IsFinished()); +} + +TEST_F(MADDY_CHECKLISTPARSER, ItReplacesMarkdownWithAnHtmlChecklist) +{ + std::vector markdown = { + "- [ ] a" + , "- [x] b" + , "" + }; + std::string expected = "
    "; + + for (std::string md : markdown) + { + clParser->AddLine(md); + } + + ASSERT_TRUE(clParser->IsFinished()); + + std::stringstream& output(clParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} + +TEST_F(MADDY_CHECKLISTPARSER, ItReplacesMarkdownWithAnHierachicalHtmlList) +{ + std::vector markdown = { + "- [ ] a" + , " - [ ] d" + , " - [ ] e" + , "- [ ] b" + , " - [x] c" + , "" + }; + std::string expected = "
    "; + + for (std::string md : markdown) + { + clParser->AddLine(md); + } + + ASSERT_TRUE(clParser->IsFinished()); + + std::stringstream& output(clParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/maddy/test_maddy_codeblockparser.cpp b/tests/maddy/test_maddy_codeblockparser.cpp new file mode 100644 index 0000000..849c7d8 --- /dev/null +++ b/tests/maddy/test_maddy_codeblockparser.cpp @@ -0,0 +1,61 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/codeblockparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_CODEBLOCKPARSER : public ::testing::Test +{ +protected: + std::shared_ptr cbParser; + + void + SetUp() override + { + this->cbParser = std::make_shared( + nullptr, + nullptr + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_CODEBLOCKPARSER, IsStartingLineReturnsTrueWhenFacedWithThreeSigns) +{ + ASSERT_TRUE(maddy::CodeBlockParser::IsStartingLine("```")); +} + +TEST_F(MADDY_CODEBLOCKPARSER, IsFinishedReturnsFalseInTheBeginning) +{ + ASSERT_FALSE(cbParser->IsFinished()); +} + +TEST_F(MADDY_CODEBLOCKPARSER, ItReplacesMarkdownWithAnHtmlCodeBlock) +{ + std::vector markdown = { + "```" + , "some code" + , "some other code" + , "```" + }; + + std::string expected = "
    \nsome code\nsome other code\n
    "; + + for (std::string md : markdown) + { + cbParser->AddLine(md); + } + ASSERT_TRUE(cbParser->IsFinished()); + + std::stringstream& output(cbParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/maddy/test_maddy_emphasizedparser.cpp b/tests/maddy/test_maddy_emphasizedparser.cpp new file mode 100644 index 0000000..886a451 --- /dev/null +++ b/tests/maddy/test_maddy_emphasizedparser.cpp @@ -0,0 +1,22 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/emphasizedparser.h" + +// ----------------------------------------------------------------------------- + +TEST(MADDY_EMPHASIZEDPARSER, ItReplacesMarkdownWithEmphasizedHTML) +{ + std::string text = "some text *bla* text testing *it* out"; + std::string expected = "some text bla text testing it out"; + auto emphasizedParser = std::make_shared(); + + emphasizedParser->Parse(text); + + ASSERT_EQ(expected, text); +} diff --git a/tests/maddy/test_maddy_headlineparser.cpp b/tests/maddy/test_maddy_headlineparser.cpp new file mode 100644 index 0000000..33b2144 --- /dev/null +++ b/tests/maddy/test_maddy_headlineparser.cpp @@ -0,0 +1,88 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/headlineparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_HEADLINEPARSER : public ::testing::Test +{ +protected: + std::shared_ptr hlParser; + + void + SetUp() override + { + this->hlParser = std::make_shared( + nullptr, + nullptr + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_HEADLINEPARSER, IsStartingLineReturnsTrueWhenFacedWithOneToSixHashes) +{ + ASSERT_TRUE(maddy::HeadlineParser::IsStartingLine("# a")); + ASSERT_TRUE(maddy::HeadlineParser::IsStartingLine("## a")); + ASSERT_TRUE(maddy::HeadlineParser::IsStartingLine("### a")); + ASSERT_TRUE(maddy::HeadlineParser::IsStartingLine("#### a")); + ASSERT_TRUE(maddy::HeadlineParser::IsStartingLine("##### a")); + ASSERT_TRUE(maddy::HeadlineParser::IsStartingLine("###### a")); +} + +TEST_F(MADDY_HEADLINEPARSER, IsFinishedAlwaysReturnsTrue) +{ + ASSERT_TRUE(hlParser->IsFinished()); +} + +TEST_F(MADDY_HEADLINEPARSER, ItReplacesMarkdownWithAnHtmlHeadline) +{ + std::vector markdown = { + "# a" + , "## a" + , "### a" + , "#### a" + , "##### a" + , "###### a" + }; + + std::vector expected = { + "

    a

    " + , "

    a

    " + , "

    a

    " + , "

    a

    " + , "
    a
    " + , "
    a
    " + }; + + for (uint8_t i = 0; i < 6; ++i) + { + hlParser->AddLine(markdown[i]); + std::stringstream& output(hlParser->GetResult()); + + const std::string& outputString = output.str(); + + ASSERT_EQ(expected[i], outputString); + hlParser->Clear(); + } +} + +TEST_F(MADDY_HEADLINEPARSER, ItReplacesInvalidMarkdownNotWithAnHtmlHeadline) +{ + std::string markdown = "####### a"; + std::string expected(markdown); + + hlParser->AddLine(markdown); + std::stringstream& output(hlParser->GetResult()); + + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/maddy/test_maddy_horizontallineparser.cpp b/tests/maddy/test_maddy_horizontallineparser.cpp new file mode 100644 index 0000000..c250285 --- /dev/null +++ b/tests/maddy/test_maddy_horizontallineparser.cpp @@ -0,0 +1,64 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/horizontallineparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_HORIZONTALLINEPARSER : public ::testing::Test +{ +protected: + std::shared_ptr hlParser; + + void + SetUp() override + { + this->hlParser = std::make_shared( + nullptr, + nullptr + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_HORIZONTALLINEPARSER, IsStartingLineReturnsTrueWhenFacedWithThreeDashes) +{ + ASSERT_TRUE(maddy::HorizontalLineParser::IsStartingLine("---")); +} + +TEST_F(MADDY_HORIZONTALLINEPARSER, IsFinishedAlwaysReturnsTrue) +{ + ASSERT_TRUE(hlParser->IsFinished()); +} + +TEST_F(MADDY_HORIZONTALLINEPARSER, ItReplacesMarkdownWithAnHtmlLine) +{ + std::string markdown = "---"; + std::string expected = "
    "; + + hlParser->AddLine(markdown); + std::stringstream& output(hlParser->GetResult()); + + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} + +TEST_F(MADDY_HORIZONTALLINEPARSER, ItReplacesInvalidMarkdownNotWithAnHtmlLine) +{ + std::string markdown = "--- "; + std::string expected(markdown); + + hlParser->AddLine(markdown); + std::stringstream& output(hlParser->GetResult()); + + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/maddy/test_maddy_imageparser.cpp b/tests/maddy/test_maddy_imageparser.cpp new file mode 100644 index 0000000..b48b2fa --- /dev/null +++ b/tests/maddy/test_maddy_imageparser.cpp @@ -0,0 +1,44 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/imageparser.h" + +// ----------------------------------------------------------------------------- + +TEST(MADDY_IMAGEPARSER, ItReplacesMarkdownWithAnImage) +{ + std::string text = "Some text ![Image Title](http://example.com/a.png)"; + std::string expected = "Some text \"Image"; + auto imageParser = std::make_shared(); + + imageParser->Parse(text); + + ASSERT_EQ(expected, text); +} + +TEST(MADDY_IMAGEPARSER, ItReplacesMarkdownWithImages) +{ + std::string text = "Some text ![Image Title](http://example.com/a.png) bla ![Image Title](http://example.com/a.png)"; + std::string expected = "Some text \"Image bla \"Image"; + auto imageParser = std::make_shared(); + + imageParser->Parse(text); + + ASSERT_EQ(expected, text); +} + +TEST(MADDY_IMAGEPARSER, ItReplacesNoLinkMarkdownWithImages) +{ + std::string text = "Some text [Image Title](http://example.com)"; + std::string expected(text); + auto imageParser = std::make_shared(); + + imageParser->Parse(text); + + ASSERT_EQ(expected, text); +} diff --git a/tests/maddy/test_maddy_inlinecodeparser.cpp b/tests/maddy/test_maddy_inlinecodeparser.cpp new file mode 100644 index 0000000..ad34e71 --- /dev/null +++ b/tests/maddy/test_maddy_inlinecodeparser.cpp @@ -0,0 +1,22 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/inlinecodeparser.h" + +// ----------------------------------------------------------------------------- + +TEST(MADDY_INLINECODEPARSER, ItReplacesMarkdownWithCodeHTML) +{ + std::string text = "some text `bla` text testing `it` out"; + std::string expected = "some text bla text testing it out"; + auto emphasizedParser = std::make_shared(); + + emphasizedParser->Parse(text); + + ASSERT_EQ(expected, text); +} diff --git a/tests/maddy/test_maddy_linkparser.cpp b/tests/maddy/test_maddy_linkparser.cpp new file mode 100644 index 0000000..aae3ed8 --- /dev/null +++ b/tests/maddy/test_maddy_linkparser.cpp @@ -0,0 +1,50 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/linkparser.h" + +// ----------------------------------------------------------------------------- + +TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithALink) +{ + std::string text = "Some text [Link Title](http://example.com)"; + std::string expected = "Some text Link Title"; + auto linkParser = std::make_shared(); + + linkParser->Parse(text); + + ASSERT_EQ(expected, text); +} + +TEST(MADDY_LINKPARSER, ItReplacesMarkdownWithLinks) +{ + std::string text = "Some text [Link Title](http://example.com) bla [Link Title](http://example.com)"; + std::string expected = "Some text Link Title bla Link Title"; + auto linkParser = std::make_shared(); + + linkParser->Parse(text); + + ASSERT_EQ(expected, text); +} + +// ----------------------------------------------------------------------------- + +class DISABLED_MADDY_LINKPARSER : public ::testing::Test { }; + +// This test is disabled for now, so make sure, to first run the ImageParser +// before using the LinkParser +TEST_F(DISABLED_MADDY_LINKPARSER, ItReplacesNoImageMarkdownWithLinks) +{ + std::string text = "Some text ![Image Title](http://example.com/example.png)"; + std::string expected(text); + auto linkParser = std::make_shared(); + + linkParser->Parse(text); + + ASSERT_EQ(expected, text); +} diff --git a/tests/maddy/test_maddy_orderedlistparser.cpp b/tests/maddy/test_maddy_orderedlistparser.cpp new file mode 100644 index 0000000..326fe96 --- /dev/null +++ b/tests/maddy/test_maddy_orderedlistparser.cpp @@ -0,0 +1,98 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/orderedlistparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_ORDEREDLISTPARSER : public ::testing::Test +{ +protected: + std::shared_ptr olParser; + + void + SetUp() override + { + std::function(const std::string& line)> getBlockParserForLineCallback = [](const std::string& line) + { + if (maddy::OrderedListParser::IsStartingLine(line)) + { + return std::static_pointer_cast( + std::make_shared(nullptr, nullptr) + ); + } + + std::shared_ptr empty; + return empty; + }; + + this->olParser = std::make_shared( + nullptr, + getBlockParserForLineCallback + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_ORDEREDLISTPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfList) +{ + ASSERT_TRUE(maddy::OrderedListParser::IsStartingLine("1. a")); +} + +TEST_F(MADDY_ORDEREDLISTPARSER, IsFinishedAlwaysReturnsFalseInTheBeginning) +{ + ASSERT_FALSE(olParser->IsFinished()); +} + +TEST_F(MADDY_ORDEREDLISTPARSER, ItReplacesMarkdownWithAnHtmlOrderedList) +{ + std::vector markdown = { + "1. a" + , "* b" + , "" + }; + std::string expected = "
    1. a
    2. b
    "; + + for (std::string md : markdown) + { + olParser->AddLine(md); + } + + ASSERT_TRUE(olParser->IsFinished()); + + std::stringstream& output(olParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} + +TEST_F(MADDY_ORDEREDLISTPARSER, ItReplacesMarkdownWithAnHierachicalHtmlList) +{ + std::vector markdown = { + "1. a" + , " 1. d" + , " * e" + , "* b" + , " 1. c" + , "" + }; + std::string expected = "
    1. a
      1. d
      2. e
    2. b
      1. c
    "; + + for (std::string md : markdown) + { + olParser->AddLine(md); + } + + ASSERT_TRUE(olParser->IsFinished()); + + std::stringstream& output(olParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/maddy/test_maddy_paragraphparser.cpp b/tests/maddy/test_maddy_paragraphparser.cpp new file mode 100644 index 0000000..90c0655 --- /dev/null +++ b/tests/maddy/test_maddy_paragraphparser.cpp @@ -0,0 +1,59 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/paragraphparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_PARAGRAPHPARSER : public ::testing::Test +{ +protected: + std::shared_ptr pParser; + + void + SetUp() override + { + this->pParser = std::make_shared( + nullptr, + nullptr + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_PARAGRAPHPARSER, IsStartingLineReturnsTrueWhenFacedWithThreeDashes) +{ + ASSERT_TRUE(maddy::ParagraphParser::IsStartingLine("---")); +} + +TEST_F(MADDY_PARAGRAPHPARSER, IsFinishedReturnsFalseInTheBeginning) +{ + ASSERT_FALSE(pParser->IsFinished()); +} + +TEST_F(MADDY_PARAGRAPHPARSER, ItReplacesMarkdownWithAnHtmlLine) +{ + std::vector markdown = { + "Some text" + , "and some other text" + , "" + }; + std::string expected = "

    Some text and some other text

    "; + + for (std::string md : markdown) + { + pParser->AddLine(md); + } + ASSERT_TRUE(pParser->IsFinished()); + + std::stringstream& output(pParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/maddy/test_maddy_parser.cpp b/tests/maddy/test_maddy_parser.cpp new file mode 100644 index 0000000..91e03e0 --- /dev/null +++ b/tests/maddy/test_maddy_parser.cpp @@ -0,0 +1,21 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ + +#include "gmock/gmock.h" + +#include "maddy/parser.h" +#include "maddy/test_maddy_parser.h" + +// ----------------------------------------------------------------------------- + +TEST(MADDY_PARSER, ItShouldParse) +{ + auto parser = std::make_shared(); + std::stringstream markdown(testMarkdown); + + const std::string output = parser->Parse(markdown); + + ASSERT_EQ(testHtml, output); +} diff --git a/tests/maddy/test_maddy_parser.h b/tests/maddy/test_maddy_parser.h new file mode 100644 index 0000000..00bbc1c --- /dev/null +++ b/tests/maddy/test_maddy_parser.h @@ -0,0 +1,70 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#pragma once + +#include + +const std::string testMarkdown = "# This is a test\n\ +\n\ +This should result in a praragraph\n\ +it's that simple.\n\ +\n\ +* an unordered list\n\ + * with some **hierarchy**\n\ + 1. and an *ordered*\n\ + * list\n\ + * directly\n\ + * inside\n\ +\n\ +```\n\ +var c = 'blub';\n\ +```\n\ +\n\ +> A Quote\n\ +>\n\ +> With some ~~text~~ blocks inside\n\ +>\n\ +> * even a list\n\ +> * should be\n\ +> * possible\n\ +>\n\ +\n\ +And well `inline code` should also work.\n\ +\n\ +## Another Headline\n\ +\n\ +And not to forget [link to progsource](http://progsource.de) should work.\n\ +And well - let's see how an image would be shown:\n\ +\n\ +![an image](http://progsource.de/img/progsource.png)\n\ +\n\ +---\n\ +\n\ +### and more headlines\n\ +\n\ +- [ ] how\n\ +- [ ] about\n\ + - [ ] a\n\ + - [x] nice\n\ +- [x] check\n\ +- [ ] list\n\ +\n\ +#### even a table\n\ +\n\ +|table>\n\ +Left header|middle header|last header\n\ +- | - | -\n\ +cell 1|cell **2**|cell 3\n\ +cell 4|cell 5|cell 6\n\ +- | - | -\n\ +foot a|foot b|foot c\n\ +|link to progsource should work. And well - let's see how an image would be shown:

    \"an


    and more headlines

    even a table

    Left headermiddle headerlast header
    cell 1cell 2cell 3
    cell 4cell 5cell 6
    foot afoot bfoot c
    h5
    h6
    "; diff --git a/tests/maddy/test_maddy_quoteparser.cpp b/tests/maddy/test_maddy_quoteparser.cpp new file mode 100644 index 0000000..432a31d --- /dev/null +++ b/tests/maddy/test_maddy_quoteparser.cpp @@ -0,0 +1,62 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/quoteparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_QUOTEPARSER : public ::testing::Test +{ +protected: + std::shared_ptr quoteParser; + + void + SetUp() override + { + this->quoteParser = std::make_shared( + nullptr, + nullptr + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_QUOTEPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfAQuote) +{ + ASSERT_TRUE(maddy::QuoteParser::IsStartingLine("> a")); +} + +TEST_F(MADDY_QUOTEPARSER, IsFinishedAlwaysReturnsFalseInTheBeginning) +{ + ASSERT_FALSE(quoteParser->IsFinished()); +} + +TEST_F(MADDY_QUOTEPARSER, ItReplacesMarkdownWithAnHtmlBlockQuote) +{ + std::vector markdown = { + "> a" + , "> b" + , ">" + , "> c" + , "" + }; + std::string expected = "
    a b c
    "; + + for (std::string md : markdown) + { + quoteParser->AddLine(md); + } + + ASSERT_TRUE(quoteParser->IsFinished()); + + std::stringstream& output(quoteParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/maddy/test_maddy_strikethroughparser.cpp b/tests/maddy/test_maddy_strikethroughparser.cpp new file mode 100644 index 0000000..b1ec7fb --- /dev/null +++ b/tests/maddy/test_maddy_strikethroughparser.cpp @@ -0,0 +1,22 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/strikethroughparser.h" + +// ----------------------------------------------------------------------------- + +TEST(MADDY_STRIKETHROUGHPARSER, ItReplacesMarkdownWithStrikeThroughHTML) +{ + std::string text = "some text ~~bla~~ text testing ~~it~~ out"; + std::string expected = "some text bla text testing it out"; + auto strikeThroughParser = std::make_shared(); + + strikeThroughParser->Parse(text); + + ASSERT_EQ(expected, text); +} diff --git a/tests/maddy/test_maddy_strongparser.cpp b/tests/maddy/test_maddy_strongparser.cpp new file mode 100644 index 0000000..b222952 --- /dev/null +++ b/tests/maddy/test_maddy_strongparser.cpp @@ -0,0 +1,33 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/strongparser.h" + +// ----------------------------------------------------------------------------- + +TEST(MADDY_STRONGPARSER, ItReplacesMarkdownWithStrongHTML) +{ + std::string text = "some text **bla** text testing **it** out"; + std::string expected = "some text bla text testing it out"; + auto strongParser = std::make_shared(); + + strongParser->Parse(text); + + ASSERT_EQ(expected, text); +} + +TEST(MADDY_STRONGPARSER, ItReplacesEmphasizedMarkdownNotWithStrongHTML) +{ + std::string text = "some text *bla* text testing **it** out"; + std::string expected = "some text *bla* text testing it out"; + auto strongParser = std::make_shared(); + + strongParser->Parse(text); + + ASSERT_EQ(expected, text); +} diff --git a/tests/maddy/test_maddy_tableparser.cpp b/tests/maddy/test_maddy_tableparser.cpp new file mode 100644 index 0000000..addb1ae --- /dev/null +++ b/tests/maddy/test_maddy_tableparser.cpp @@ -0,0 +1,66 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/tableparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_TABLEPARSER : public ::testing::Test +{ +protected: + std::shared_ptr tableParser; + + void + SetUp() override + { + this->tableParser = std::make_shared( + nullptr, + nullptr + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_TABLEPARSER, IsStartingLineReturnsTrueWhenFacedWithTheBeginningOfATable) +{ + ASSERT_EQ(true, maddy::TableParser::IsStartingLine("|table>")); +} + +TEST_F(MADDY_TABLEPARSER, IsFinishedReturnsFalseInTheBeginning) +{ + ASSERT_FALSE(tableParser->IsFinished()); +} + +TEST_F(MADDY_TABLEPARSER, ItReplacesMarkdownWithAnHtmlTable) +{ + std::vector markdown = { + "|table>" + , "Left header|middle header|last header" + , "- | - | -" + , "cell 1|cell 2|cell 3" + , "cell 4|cell 5|cell 6" + , "- | - | -" + , "foot a|foot b|foot c" + , "|AddLine(md); + } + + ASSERT_TRUE(tableParser->IsFinished()); + + std::stringstream& output(tableParser->GetResult()); + + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/maddy/test_maddy_unorderedlistparser.cpp b/tests/maddy/test_maddy_unorderedlistparser.cpp new file mode 100644 index 0000000..df94ba0 --- /dev/null +++ b/tests/maddy/test_maddy_unorderedlistparser.cpp @@ -0,0 +1,98 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include + +#include "gmock/gmock.h" + +#include "maddy/unorderedlistparser.h" + +// ----------------------------------------------------------------------------- + +class MADDY_UNORDEREDLISTPARSER : public ::testing::Test +{ +protected: + std::shared_ptr ulParser; + + void + SetUp() override + { + std::function(const std::string& line)> getBlockParserForLineCallback = [](const std::string& line) + { + if (maddy::UnorderedListParser::IsStartingLine(line)) + { + return std::static_pointer_cast( + std::make_shared(nullptr, nullptr) + ); + } + + std::shared_ptr empty; + return empty; + }; + + this->ulParser = std::make_shared( + nullptr, + getBlockParserForLineCallback + ); + } +}; + +// ----------------------------------------------------------------------------- + +TEST_F(MADDY_UNORDEREDLISTPARSER, IsStartingLineReturnsTrueWhenFacedWithBeginningOfList) +{ + ASSERT_TRUE(maddy::UnorderedListParser::IsStartingLine("* a")); +} + +TEST_F(MADDY_UNORDEREDLISTPARSER, IsFinishedAlwaysReturnsFalseInTheBeginning) +{ + ASSERT_FALSE(ulParser->IsFinished()); +} + +TEST_F(MADDY_UNORDEREDLISTPARSER, ItReplacesMarkdownWithAnHtmlUnorderedList) +{ + std::vector markdown = { + "* a" + , "* b" + , "" + }; + std::string expected = "
    • a
    • b
    "; + + for (std::string md : markdown) + { + ulParser->AddLine(md); + } + + ASSERT_TRUE(ulParser->IsFinished()); + + std::stringstream& output(ulParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} + +TEST_F(MADDY_UNORDEREDLISTPARSER, ItReplacesMarkdownWithAnHierachicalHtmlList) +{ + std::vector markdown = { + "* a" + , " * d" + , " * e" + , "* b" + , " * c" + , "" + }; + std::string expected = "
    • a
      • d
      • e
    • b
      • c
    "; + + for (std::string md : markdown) + { + ulParser->AddLine(md); + } + + ASSERT_TRUE(ulParser->IsFinished()); + + std::stringstream& output(ulParser->GetResult()); + const std::string& outputString = output.str(); + + ASSERT_EQ(expected, outputString); +} diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..a71f12e --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,14 @@ +/* + * This project is licensed under the MIT license. For more information see the + * LICENSE file. + */ +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +// ----------------------------------------------------------------------------- + +int main (int argc, char** argv) { + ::testing::GTEST_FLAG(throw_on_failure) = false; + ::testing::InitGoogleMock(&argc, argv); + return RUN_ALL_TESTS(); +}