From 569794c4b648bb2d3d4757deb6c6dbfa48b61d81 Mon Sep 17 00:00:00 2001 From: "M. Petra Baranski" Date: Mon, 25 Dec 2017 12:22:35 +0100 Subject: [PATCH] initial release 1.0.0 --- .editorconfig | 12 + .gitignore | 497 ++++++++++++++++++ .gitmodules | 3 + AUTHORS | 7 + CMakeLists.txt | 55 ++ LICENSE | 18 + README.md | 51 ++ docs/definitions.md | 303 +++++++++++ include/maddy/blockparser.h | 190 +++++++ include/maddy/checklistparser.h | 140 +++++ include/maddy/codeblockparser.h | 137 +++++ include/maddy/emphasizedparser.h | 53 ++ include/maddy/headlineparser.h | 138 +++++ include/maddy/horizontallineparser.h | 106 ++++ include/maddy/imageparser.h | 53 ++ include/maddy/inlinecodeparser.h | 51 ++ include/maddy/lineparser.h | 39 ++ include/maddy/linkparser.h | 53 ++ include/maddy/orderedlistparser.h | 142 +++++ include/maddy/paragraphparser.h | 114 ++++ include/maddy/parser.h | 255 +++++++++ include/maddy/quoteparser.h | 165 ++++++ include/maddy/strikethroughparser.h | 51 ++ include/maddy/strongparser.h | 53 ++ include/maddy/tableparser.h | 246 +++++++++ include/maddy/unorderedlistparser.h | 133 +++++ libs/CMakeLists.txt | 14 + libs/gtest | 1 + tests/maddy/test_maddy_checklistparser.cpp | 99 ++++ tests/maddy/test_maddy_codeblockparser.cpp | 61 +++ tests/maddy/test_maddy_emphasizedparser.cpp | 22 + tests/maddy/test_maddy_headlineparser.cpp | 88 ++++ .../maddy/test_maddy_horizontallineparser.cpp | 64 +++ tests/maddy/test_maddy_imageparser.cpp | 44 ++ tests/maddy/test_maddy_inlinecodeparser.cpp | 22 + tests/maddy/test_maddy_linkparser.cpp | 50 ++ tests/maddy/test_maddy_orderedlistparser.cpp | 98 ++++ tests/maddy/test_maddy_paragraphparser.cpp | 59 +++ tests/maddy/test_maddy_parser.cpp | 21 + tests/maddy/test_maddy_parser.h | 70 +++ tests/maddy/test_maddy_quoteparser.cpp | 62 +++ .../maddy/test_maddy_strikethroughparser.cpp | 22 + tests/maddy/test_maddy_strongparser.cpp | 33 ++ tests/maddy/test_maddy_tableparser.cpp | 66 +++ .../maddy/test_maddy_unorderedlistparser.cpp | 98 ++++ tests/main.cpp | 14 + 46 files changed, 4073 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 AUTHORS create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.md create mode 100644 docs/definitions.md create mode 100644 include/maddy/blockparser.h create mode 100644 include/maddy/checklistparser.h create mode 100644 include/maddy/codeblockparser.h create mode 100644 include/maddy/emphasizedparser.h create mode 100644 include/maddy/headlineparser.h create mode 100644 include/maddy/horizontallineparser.h create mode 100644 include/maddy/imageparser.h create mode 100644 include/maddy/inlinecodeparser.h create mode 100644 include/maddy/lineparser.h create mode 100644 include/maddy/linkparser.h create mode 100644 include/maddy/orderedlistparser.h create mode 100644 include/maddy/paragraphparser.h create mode 100644 include/maddy/parser.h create mode 100644 include/maddy/quoteparser.h create mode 100644 include/maddy/strikethroughparser.h create mode 100644 include/maddy/strongparser.h create mode 100644 include/maddy/tableparser.h create mode 100644 include/maddy/unorderedlistparser.h create mode 100644 libs/CMakeLists.txt create mode 160000 libs/gtest create mode 100644 tests/maddy/test_maddy_checklistparser.cpp create mode 100644 tests/maddy/test_maddy_codeblockparser.cpp create mode 100644 tests/maddy/test_maddy_emphasizedparser.cpp create mode 100644 tests/maddy/test_maddy_headlineparser.cpp create mode 100644 tests/maddy/test_maddy_horizontallineparser.cpp create mode 100644 tests/maddy/test_maddy_imageparser.cpp create mode 100644 tests/maddy/test_maddy_inlinecodeparser.cpp create mode 100644 tests/maddy/test_maddy_linkparser.cpp create mode 100644 tests/maddy/test_maddy_orderedlistparser.cpp create mode 100644 tests/maddy/test_maddy_paragraphparser.cpp create mode 100644 tests/maddy/test_maddy_parser.cpp create mode 100644 tests/maddy/test_maddy_parser.h create mode 100644 tests/maddy/test_maddy_quoteparser.cpp create mode 100644 tests/maddy/test_maddy_strikethroughparser.cpp create mode 100644 tests/maddy/test_maddy_strongparser.cpp create mode 100644 tests/maddy/test_maddy_tableparser.cpp create mode 100644 tests/maddy/test_maddy_unorderedlistparser.cpp create mode 100644 tests/main.cpp 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(); +}