Introducing unit tests

master
Melroy van den Berg 2022-01-27 22:25:48 +00:00
parent 77dd246544
commit 3b7505fb4e
24 changed files with 563 additions and 93 deletions

View File

@ -1,4 +1,4 @@
image: danger89/gtk3-docker-cmake-ninja:2.5
image: danger89/gtk3-docker-cmake-ninja:3.0
stages:
- build
#- upload
@ -41,10 +41,9 @@ code_style_guidelines:
stage: build
script: "./scripts/check-format.sh"
# TODO: Testing!
#unit_test:
# stage: test
# script :
unit_test:
stage: test
script: "./scripts/build-run-tests.sh"
sast:
stage: test

40
.vscode/cmake-variants.json vendored Normal file
View File

@ -0,0 +1,40 @@
{
"buildType": {
"default": "debug",
"choices": {
"debug": {
"short": "Debug",
"long": "Emit debug information without performing optimizations",
"buildType": "Debug",
"settings": {
"UNITTEST": false
}
},
"release": {
"short": "Release",
"long": "Enable optimizations, omit debug info",
"buildType": "Release",
"settings": {
"UNITTEST": false
}
},
"reldeb": {
"short": "RelWithDebInfo",
"long": "Perform optimizations AND include debugging information",
"buildType": "RelWithDebInfo",
"settings": {
"UNITTEST": false
}
},
"test": {
"short": "UnitTests",
"long": "Build + run unit tests",
"buildType": "Debug",
"settings": {
"UNITTEST": true,
"DOXYGEN": false
}
}
}
}
}

View File

@ -80,6 +80,7 @@
"node.h": "c",
"*.in": "cpp",
"superscript.h": "c",
"cmark-gfm.h": "c"
"cmark-gfm.h": "c",
"any": "cpp"
}
}

View File

@ -1,6 +1,7 @@
cmake_minimum_required (VERSION 3.16.0)
option(DOXYGEN "Build Doxygen documentation" ON)
option(UNITTEST "Build unit tests")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
@ -13,6 +14,9 @@ project(libreweb-browser
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
message(STATUS "PROJECT_VERSION: ${PROJECT_VERSION}")
if(UNITTEST)
message(STATUS "Building the unit tests")
endif()
# Build docs using Doxygen
if(DOXYGEN)
@ -38,7 +42,7 @@ if(WIN32)
set(WINDOWS_FLAGS -mwindows)
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -pedantic -Werror=incompatible-pointer-types")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror")
@ -55,6 +59,10 @@ add_subdirectory (lib/ipfs-http-client)
add_subdirectory (lib/whereami)
add_subdirectory (src)
if(UNITTEST)
add_subdirectory(tst)
endif()
# Additional install files
if(WIN32)
# Windows specific

View File

@ -79,9 +79,13 @@ For the GNU/Linux build you need at least:
* Libcurl (Package: `libcurl4-openssl-dev`)
* GTK & Pango (including C++ bindings):
* Package: `libgtkmm-3.0-dev` under Debian based distros
Depedencies for tests:
* X virtual framebuffer (Package: `xvfb`)
* Clang-format (Package: `clang-format`)
*Note:* For cross-compiling towards Windows, see the cross-compile section below.
*Note:* For cross-compiling towards Windows, see the cross-compile section down below.
### Build
@ -99,9 +103,23 @@ Start the Linux build, which is using CMake and Ninja build system, using the wr
Optionally, use the VSCode `CMake Tools` extension to start the build or build with debug targets.
Build a release target, including packaging under GNU/Linux, using: `./scripts/build-lnx-prod.sh`
#### Linux Packaging
*Note:* Root access is required for Linux packaging; add `/opt/mxe/usr/bin` to the secure_path using: `sudo visudo`.
*Note:* (Linux) Packages are already [available under releases](https://gitlab.melroy.org/libreweb/browser/-/releases).
To build a release target yourself including packaging under GNU/Linux, use: `./scripts/build-lnx-prod.sh`
Root access is required when building Linux packages; add `/opt/mxe/usr/bin` to the secure_path using: `sudo visudo`.
### Unit testing
To execute the **unit tests** you can configure with `cmake -DUNITTEST:BOOL=TRUE` and build. Execute: `ctest` command in the `tst` target directory.
Or just use script:
```sh
./scripts/build-run-tests.sh
```
### C++ Coding Style Guidelines

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# By: Melroy van den Berg
# Descriptiopn: Only build the documentation (used in CI/CD)
# Description: Only build the documentation (used in CI/CD)
mkdir build_docs
cd build_docs

18
scripts/build-lnx-no-docs.sh Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
# By: Melroy van den Berg
# Description: Development build for Linux, same as build-lnx.sh but without Doxygen
if [ ! -d "build" ]; then
echo "Creating build directory..."
mkdir build
fi
if [ -z "$(ls build)" ]; then
echo "INFO: Run cmake & ninja"
cd build
cmake -G Ninja -DDOXYGEN:BOOL=FALSE ..
else
echo "INFO: Only run ninja..."
cd build
fi
ninja

19
scripts/build-run-tests.sh Executable file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env bash
# By: Melroy van den Berg
# Description: Build & run unit-tests
if [ ! -d "build_test" ]; then
echo "Creating test build directory..."
mkdir build_test
fi
if [ -z "$(ls build_test)" ]; then
echo "INFO: Run cmake & ninja"
cd build_test
cmake -G Ninja -DDOXYGEN:BOOL=FALSE -DUNITTEST:BOOL=TRUE ..
else
echo "INFO: Only run ninja..."
cd build_test
fi
# Build & run unit tests
ninja tests

View File

@ -1,3 +1,3 @@
#!/usr/bin/env bash
# Description: Check the coding style guidelines (only dry-run)
find src/ -iname *.h -o -iname *.cc -o -iname *.h.in | xargs clang-format --dry-run -Werror -style=file -fallback-style=LLVM
find src/ tst/ -iname *.h -o -iname *.cc -o -iname *.h.in | xargs clang-format --dry-run -Werror -style=file -fallback-style=LLVM

View File

@ -1,3 +1,3 @@
#!/usr/bin/env bash
# TODO: add to following flag to the cppcheck: --addon=cert
cppcheck --enable=all --suppressions-list=suppressions.txt --error-exitcode=1 "$@" -I lib/commonmarker/src/ -I lib/commonmarker/extensions/ ./src
cppcheck --enable=all --library=googletest --suppressions-list=suppressions.txt --error-exitcode=1 "$@" -I lib/commonmarker/src/ -I lib/commonmarker/extensions/ ./src ./tst

View File

@ -1,3 +1,3 @@
#!/usr/bin/env bash
# Description: Check the coding style guidelines & fix them automatically
find src/ -iname *.h -o -iname *.cc -o -iname *.h.in | xargs clang-format -i -style=file -fallback-style=LLVM -assume-filename=../.clang-format
find src/ tst/ -iname *.h -o -iname *.cc -o -iname *.h.in | xargs clang-format -i -style=file -fallback-style=LLVM -assume-filename=../.clang-format

View File

@ -1,6 +1,7 @@
include(${CMAKE_SOURCE_DIR}/cmake/GSettings.cmake)
set(PROJECT_TARGET libreweb-browser)
set(PROJECT_TARGET_LIB ${PROJECT_TARGET}-lib)
set(THREADS_PREFER_PTHREAD_FLAG ON)
# Find required dependencies
@ -11,7 +12,7 @@ pkg_check_modules(GTKMM REQUIRED gtkmm-3.0)
# Generate Project version header file
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/project_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/project_config.h)
# In order to find project_config.h
# Include the binary dir, in order to find project_config.h
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Source code
@ -20,6 +21,7 @@ set(HEADERS
draw.h
file.h
ipfs.h
middleware-i.h
middleware.h
toolbar-button.h
mainwindow.h
@ -76,52 +78,83 @@ if(WIN32)
set_source_files_properties(${WINDOWS_RES} PROPERTIES LANGUAGE RC)
endif()
add_executable(${PROJECT_TARGET} ${GSCHEMA_RING} ${WINDOWS_RES} ${SOURCES})
## Definitions just in case
# Define _WIN32 for Windows platforms
if(WIN32)
target_compile_definitions(${PROJECT_TARGET} PRIVATE _WIN32)
endif()
# Define __linux__ for Unix platforms
if (UNIX)
target_compile_definitions(${PROJECT_TARGET} PRIVATE __linux__)
endif()
# Add fallback for std filesystem in older GCC versions
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.4)
message(FATAL_ERROR "You are on an extremely old version of GCC. Please update your compiler to at least GCC 8.0, preferably latest")
elseif (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
message(WARNING "Old Version of GCC detected. Using Legacy C++ support")
# Add stdc++fs library in older GCC compiler versions
set(CXX_FILESYSTEM_LIBRARIES "stdc++fs")
target_compile_definitions(${PROJECT_TARGET} PUBLIC LEGACY_CXX)
endif()
endif()
# Get include list the cmark binary directory for the generated config.h, .._version.h & .._export.h files
# Get include list the cmark extensions binary directory for the generated ..._export.h file
get_property(CMAKE_BINARY_DIR GLOBAL PROPERTY COMMONMARKER_BINARY_DIR)
get_property(CMAKE_EXTENSIONS_BINARY_DIR GLOBAL PROPERTY COMMONMARKER_EXTENSIONS_BINARY_DIR)
get_property(CMARK_BINARY_DIR GLOBAL PROPERTY COMMONMARKER_BINARY_DIR)
get_property(CMARK_EXTENSIONS_BINARY_DIR GLOBAL PROPERTY COMMONMARKER_EXTENSIONS_BINARY_DIR)
target_include_directories(${PROJECT_TARGET} PRIVATE
${CMAKE_BINARY_DIR}
${CMAKE_EXTENSIONS_BINARY_DIR}
${GTKMM_INCLUDE_DIRS}
)
target_link_directories(${PROJECT_TARGET} PRIVATE ${GTKMM_LIBRARY_DIRS})
target_link_libraries(${PROJECT_TARGET} PRIVATE
LibCommonMarker
LibCommonMarkerExtensions
ipfs-http-client
whereami
Threads::Threads
${CXX_FILESYSTEM_LIBRARIES}
${GTKMM_LIBRARIES}
nlohmann_json::nlohmann_json
)
target_compile_options(${PROJECT_TARGET} PRIVATE ${GTKMM_CFLAGS_OTHER})
if(NOT UNITTEST)
# LibreWeb binary
add_executable(${PROJECT_TARGET} ${GSCHEMA_RING} ${WINDOWS_RES} ${SOURCES})
# Install browser binary
install(TARGETS ${PROJECT_TARGET} RUNTIME DESTINATION bin)
## Definitions just in case
# Define _WIN32 for Windows platforms
if(WIN32)
target_compile_definitions(${PROJECT_TARGET} PRIVATE _WIN32)
endif()
# Define __linux__ for Unix platforms
if (UNIX)
target_compile_definitions(${PROJECT_TARGET} PRIVATE __linux__)
endif()
# Add fallback for std filesystem in older GCC versions
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.4)
message(FATAL_ERROR "You are on an extremely old version of GCC. Please update your compiler to at least GCC 8.0, preferably latest")
elseif (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
message(WARNING "Old Version of GCC detected. Using Legacy C++ support")
# Add stdc++fs library in older GCC compiler versions
set(CXX_FILESYSTEM_LIBRARIES "stdc++fs")
target_compile_definitions(${PROJECT_TARGET} PUBLIC LEGACY_CXX)
endif()
endif()
target_include_directories(${PROJECT_TARGET} PRIVATE
${CMARK_BINARY_DIR}
${CMARK_EXTENSIONS_BINARY_DIR}
${GTKMM_INCLUDE_DIRS}
)
target_link_directories(${PROJECT_TARGET} PRIVATE ${GTKMM_LIBRARY_DIRS})
target_link_libraries(${PROJECT_TARGET} PRIVATE
LibCommonMarker
LibCommonMarkerExtensions
ipfs-http-client
whereami
Threads::Threads
${CXX_FILESYSTEM_LIBRARIES}
${GTKMM_LIBRARIES}
nlohmann_json::nlohmann_json
)
target_compile_options(${PROJECT_TARGET} PRIVATE ${GTKMM_CFLAGS_OTHER})
# Install browser binary
install(TARGETS ${PROJECT_TARGET} RUNTIME DESTINATION bin)
else()
# Build libraries for unit testing
add_library(${PROJECT_TARGET_LIB}-file STATIC file.h file.cc)
add_library(${PROJECT_TARGET_LIB}-draw STATIC draw.h draw.cc md-parser.h md-parser.cc)
add_library(${PROJECT_TARGET_LIB}-parser STATIC md-parser.h md-parser.cc)
# Only link/include external libs we really need for the unittest libaries
target_include_directories(${PROJECT_TARGET_LIB}-draw PRIVATE
${CMARK_BINARY_DIR}
${CMARK_EXTENSIONS_BINARY_DIR}
${GTKMM_INCLUDE_DIRS}
)
target_link_libraries(${PROJECT_TARGET_LIB}-draw PRIVATE
LibCommonMarker
LibCommonMarkerExtensions
${GTKMM_LIBRARIES}
)
target_compile_options(${PROJECT_TARGET_LIB}-draw PRIVATE ${GTKMM_CFLAGS_OTHER})
target_include_directories(${PROJECT_TARGET_LIB}-parser PRIVATE
${CMARK_BINARY_DIR}
${CMARK_EXTENSIONS_BINARY_DIR}
${GTKMM_INCLUDE_DIRS}
)
target_link_directories(${PROJECT_TARGET_LIB}-parser PRIVATE ${GTKMM_LIBRARY_DIRS})
target_link_libraries(${PROJECT_TARGET_LIB}-parser PRIVATE
LibCommonMarker
LibCommonMarkerExtensions
)
endif()

View File

@ -1,7 +1,6 @@
#include "draw.h"
#include "middleware.h"
#include "middleware-i.h"
#include "node.h"
#include "strikethrough.h"
#include "syntax_extension.h"
#include <cmark-gfm.h>
#include <gdkmm/window.h>
@ -11,7 +10,7 @@
#include <regex>
#include <stdexcept>
Draw::Draw(Middleware& middleware)
Draw::Draw(MiddlewareInterface& middleware)
: middleware(middleware),
buffer(Glib::unwrap(this->get_buffer())),
addViewSourceMenuItem(true),
@ -351,7 +350,7 @@ void Draw::newDocument()
*/
Glib::ustring Draw::getText() const
{
return get_buffer().get()->get_text();
return get_buffer()->get_text();
}
/**

View File

@ -8,7 +8,7 @@
#include <gtkmm/tooltip.h>
#include <pangomm/layout.h>
class Middleware;
class MiddlewareInterface;
/**
* \struct UndoRedoData
@ -37,7 +37,7 @@ public:
CODE_TYPE_CODE_BLOCK
};
explicit Draw(Middleware& middleware);
explicit Draw(MiddlewareInterface& middleware);
void setMessage(const Glib::ustring& message, const Glib::ustring& details = "");
void showStartPage();
void setDocument(cmark_node* rootNode);
@ -81,7 +81,7 @@ protected:
void populate_popup(Gtk::Menu* menu);
private:
Middleware& middleware;
MiddlewareInterface& middleware;
GtkTextBuffer* buffer;
bool addViewSourceMenuItem;
int headingLevel;

View File

@ -1,6 +1,5 @@
#include "file.h"
#include <fstream>
#include <ipfs/client.h>
#include <stdexcept>
#ifdef LEGACY_CXX

View File

@ -15,7 +15,7 @@ IPFS::IPFS(const std::string& host, int port, const std::string& timeout)
}
/**
* \brief Get the number of IPFS peers. Does not throw errors.
* \brief Get the number of IPFS peers.
* \return number of peers as size_t
*/
std::size_t IPFS::getNrPeers()
@ -26,7 +26,7 @@ std::size_t IPFS::getNrPeers()
}
/**
* \brief Retrieve your IPFS client ID. Does not throw errors.
* \brief Retrieve your IPFS client ID.
* \return ID as string
*/
std::string IPFS::getClientID()
@ -37,7 +37,7 @@ std::string IPFS::getClientID()
}
/**
* \brief Retrieve your IPFS Public Key. Does not throw errors.
* \brief Retrieve your IPFS Public Key.
* \return Public key string
*/
std::string IPFS::getClientPublicKey()
@ -48,7 +48,7 @@ std::string IPFS::getClientPublicKey()
}
/**
* \brief Retrieve the Go IPFS daemon version. Does not throw errors.
* \brief Retrieve the Go IPFS daemon version.
* \return Version string
*/
std::string IPFS::getVersion()
@ -59,7 +59,7 @@ std::string IPFS::getVersion()
}
/**
* \brief Get the number of IPFS peers. Does not throw errors.
* \brief Get the number of IPFS peers.
* \return Map with bandwidth information (with keys: 'in' and 'out')
*/
std::map<std::string, float> IPFS::getBandwidthRates()
@ -75,7 +75,7 @@ std::map<std::string, float> IPFS::getBandwidthRates()
}
/**
* \brief Get the stats of the current Repo. Does not throw errors.
* \brief Get the stats of the current Repo.
* \return Map with repo stats (with keys: 'repo-size' and 'path')
*/
std::map<std::string, std::variant<int, std::string>> IPFS::getRepoStats()

41
src/middleware-i.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef MIDDLEWARE_INTERFACE_H
#define MIDDLEWARE_INTERFACE_H
#include <glibmm/ustring.h>
#include <string>
/* Forward declarations */
struct cmark_node;
/**
* \class MiddlewareInterface
* \brief Pure Middleware interface
*/
class MiddlewareInterface
{
public:
virtual ~MiddlewareInterface()
{
}
virtual void doRequest(const std::string& path = std::string(),
bool isSetAddressBar = true,
bool isHistoryRequest = false,
bool isDisableEditor = true,
bool isParseContent = true) = 0;
virtual std::string doAdd(const std::string& path) = 0;
virtual void doWrite(const std::string& path, bool isSetAddressAndTitle = true) = 0;
virtual void setContent(const Glib::ustring& content) = 0;
virtual Glib::ustring getContent() const = 0;
virtual cmark_node* parseContent() const = 0;
virtual void resetContentAndPath() = 0;
virtual std::size_t getIPFSNumberOfPeers() const = 0;
virtual int getIPFSRepoSize() const = 0;
virtual std::string getIPFSRepoPath() const = 0;
virtual std::string getIPFSIncomingRate() const = 0;
virtual std::string getIPFSOutcomingRate() const = 0;
virtual std::string getIPFSVersion() const = 0;
virtual std::string getIPFSClientId() const = 0;
virtual std::string getIPFSClientPublicKey() const = 0;
};
#endif

View File

@ -130,7 +130,8 @@ Glib::ustring Middleware::getContent() const
}
/**
* \brief Current content parser middleware
* \brief Current content parser middleware.
* Note: Do not forget to free the document: cmark_node_free(root_node;
* \return AST structure (of type cmark_node)
*/
cmark_node* Middleware::parseContent() const

View File

@ -2,15 +2,14 @@
#define MIDDLEWARE_H
#include "ipfs.h"
#include "middleware-i.h"
#include <atomic>
#include <glibmm/dispatcher.h>
#include <glibmm/ustring.h>
#include <map>
#include <mutex>
#include <sigc++/connection.h>
#include <string>
#include <thread>
#include <variant>
/* Forward declarations */
struct cmark_node;
@ -20,7 +19,7 @@ class MainWindow;
* \class Middleware
* \brief Handles (IPFS) network requests and File IO from disk towards the GUI
*/
class Middleware
class Middleware : public MiddlewareInterface
{
public:
explicit Middleware(MainWindow& mainWindow, const std::string& timeout);
@ -29,21 +28,21 @@ public:
bool isSetAddressBar = true,
bool isHistoryRequest = false,
bool isDisableEditor = true,
bool isParseContent = true);
std::string doAdd(const std::string& path);
void doWrite(const std::string& path, bool isSetAddressAndTitle = true);
void setContent(const Glib::ustring& content);
Glib::ustring getContent() const;
cmark_node* parseContent() const;
void resetContentAndPath();
std::size_t getIPFSNumberOfPeers() const;
int getIPFSRepoSize() const;
std::string getIPFSRepoPath() const;
std::string getIPFSIncomingRate() const;
std::string getIPFSOutcomingRate() const;
std::string getIPFSVersion() const;
std::string getIPFSClientId() const;
std::string getIPFSClientPublicKey() const;
bool isParseContent = true) override;
std::string doAdd(const std::string& path) override;
void doWrite(const std::string& path, bool isSetAddressAndTitle = true) override;
void setContent(const Glib::ustring& content) override;
Glib::ustring getContent() const override;
cmark_node* parseContent() const override;
void resetContentAndPath() override;
std::size_t getIPFSNumberOfPeers() const override;
int getIPFSRepoSize() const override;
std::string getIPFSRepoPath() const override;
std::string getIPFSIncomingRate() const override;
std::string getIPFSOutcomingRate() const override;
std::string getIPFSVersion() const override;
std::string getIPFSClientId() const override;
std::string getIPFSClientPublicKey() const override;
private:
MainWindow& mainWindow;

41
tst/CMakeLists.txt Normal file
View File

@ -0,0 +1,41 @@
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTKMM REQUIRED gtkmm-3.0)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/e2239ee6043f73722e7aa812a459f54a28552929.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
get_property(CMARK_BINARY_DIR GLOBAL PROPERTY COMMONMARKER_BINARY_DIR)
enable_testing()
add_executable(draw draw_test.cc mock-middleware.h)
target_include_directories(draw PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMARK_BINARY_DIR} ${GTKMM_INCLUDE_DIRS})
target_link_libraries(draw PRIVATE libreweb-browser-lib-draw ${GTKMM_LIBRARIES} LibCommonMarker gtest_main gmock_main)
add_test(NAME draw_test COMMAND draw)
add_executable(file file_test.cc)
target_include_directories(file PRIVATE ${CMAKE_SOURCE_DIR}/src)
target_link_libraries(file PRIVATE libreweb-browser-lib-file gtest_main)
add_test(NAME file_test COMMAND file)
add_executable(parser parser_test.cc)
target_include_directories(parser PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMARK_BINARY_DIR} ${GTKMM_INCLUDE_DIRS})
target_link_libraries(parser PRIVATE libreweb-browser-lib-parser ${GTKMM_LIBRARIES} LibCommonMarker gtest_main)
add_test(NAME parser_test COMMAND parser)
# Add target that runs all unit-tests
# The unit tests are running in xvfb (virtual frame buffer), allowing us
# to use GTK widgets.
add_custom_target(tests ALL
COMMAND xvfb-run env GTEST_COLOR=1 ${CMAKE_CTEST_COMMAND} --verbose --output-on-failure
DEPENDS draw file parser
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tst
COMMENT "Execute all unit-tests"
VERBATIM
)

160
tst/draw_test.cc Normal file
View File

@ -0,0 +1,160 @@
#include "draw.h"
#include "md-parser.h"
#include "mock-middleware.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <gtkmm/application.h>
#include <string>
namespace
{
class DrawFixture : public testing::Test
{
protected:
void SetUp() override
{
Gtk::Application::create();
}
};
TEST_F(DrawFixture, TestDrawSetText)
{
// Given
std::string text = "Hello world!";
MockMiddleware middleware;
Draw draw(middleware);
// When
draw.setText(text);
// Then
ASSERT_EQ(draw.getText(), text);
}
TEST_F(DrawFixture, TestDrawDocument)
{
// Given
std::string markdown = "**Hello** *world*";
cmark_node* doc = Parser::parseContent(markdown);
MockMiddleware middleware;
Draw draw(middleware);
// When
draw.setDocument(doc);
// Then
std::string result = draw.getText();
ASSERT_EQ(result, "Hello world\n\n");
}
TEST_F(DrawFixture, TestDrawTextTags)
{
// Given
std::string italicTagName = "italic";
std::string boldTagName = "bold";
std::string heading1TagName = "heading1";
std::string heading2TagName = "heading2";
std::string heading3TagName = "heading3";
std::string heading4TagName = "heading4";
std::string heading5TagName = "heading5";
std::string heading6TagName = "heading6";
std::string strikethroughTagName = "strikethrough";
std::string superscriptTagName = "superscript";
std::string subscriptTagName = "subscript";
std::string codeTagName = "code";
std::string quoteTagName = "quote";
std::string highlightTagName = "highlight";
MockMiddleware middleware;
Draw draw(middleware);
// When
auto tagTable = draw.get_buffer()->get_tag_table();
auto properyItalic = tagTable->lookup(italicTagName);
auto properyBold = tagTable->lookup(boldTagName);
auto properyHeading1 = tagTable->lookup(heading1TagName);
auto properyHeading2 = tagTable->lookup(heading2TagName);
auto properyHeading3 = tagTable->lookup(heading3TagName);
auto properyHeading4 = tagTable->lookup(heading4TagName);
auto properyHeading5 = tagTable->lookup(heading5TagName);
auto properyHeading6 = tagTable->lookup(heading6TagName);
auto properyStrikethrough = tagTable->lookup(strikethroughTagName);
auto properySuperscript = tagTable->lookup(superscriptTagName);
auto properySubscript = tagTable->lookup(subscriptTagName);
auto properyCode = tagTable->lookup(codeTagName);
auto properyQuote = tagTable->lookup(quoteTagName);
auto properyHighlight = tagTable->lookup(highlightTagName);
// Then
ASSERT_NE(properyItalic.get(), nullptr);
ASSERT_EQ(properyItalic->property_name().get_value(), italicTagName);
ASSERT_NE(properyBold.get(), nullptr);
ASSERT_EQ(properyBold->property_name().get_value(), boldTagName);
ASSERT_NE(properyHeading1.get(), nullptr);
ASSERT_EQ(properyHeading1->property_name().get_value(), heading1TagName);
ASSERT_NE(properyHeading2.get(), nullptr);
ASSERT_EQ(properyHeading2->property_name().get_value(), heading2TagName);
ASSERT_NE(properyHeading3.get(), nullptr);
ASSERT_EQ(properyHeading3->property_name().get_value(), heading3TagName);
ASSERT_NE(properyHeading4.get(), nullptr);
ASSERT_EQ(properyHeading4->property_name().get_value(), heading4TagName);
ASSERT_NE(properyHeading5.get(), nullptr);
ASSERT_EQ(properyHeading5->property_name().get_value(), heading5TagName);
ASSERT_NE(properyHeading6.get(), nullptr);
ASSERT_EQ(properyHeading6->property_name().get_value(), heading6TagName);
ASSERT_NE(properyStrikethrough.get(), nullptr);
ASSERT_EQ(properyStrikethrough->property_name().get_value(), strikethroughTagName);
ASSERT_NE(properySuperscript.get(), nullptr);
ASSERT_EQ(properySuperscript->property_name().get_value(), superscriptTagName);
ASSERT_NE(properySubscript.get(), nullptr);
ASSERT_EQ(properySubscript->property_name().get_value(), subscriptTagName);
ASSERT_NE(properyCode.get(), nullptr);
ASSERT_EQ(properyCode->property_name().get_value(), codeTagName);
ASSERT_NE(properyQuote.get(), nullptr);
ASSERT_EQ(properyQuote->property_name().get_value(), quoteTagName);
ASSERT_NE(properyHighlight.get(), nullptr);
ASSERT_EQ(properyHighlight->property_name().get_value(), highlightTagName);
}
TEST_F(DrawFixture, TestDrawTextAttributes)
{
// Given
std::string markdown = "**bold**~~strikethrough~~^up^%down%`code`";
gsize length = 0;
cmark_node* doc = Parser::parseContent(markdown);
MockMiddleware middleware;
Draw draw(middleware);
// When
draw.setDocument(doc);
auto buffer = draw.get_buffer();
// Using the built-in formatter
guint8* data = buffer->serialize(buffer, "application/x-gtk-text-buffer-rich-text", buffer->begin(), buffer->end(), length);
// Convert data to string
std::string stringData(data, data + length);
// Then
// Bold attribute
std::string expectAttr1 = "<attr name=\"weight\" type=\"gint\" value=\"700\" />";
// Strikethrough attribute
std::string expectAttr2 = "<attr name=\"strikethrough\" type=\"gboolean\" value=\"TRUE\" />";
// Super-/subcript attribute
std::string expectAttr3 =
"<attr name=\"scale\" type=\"gdouble\" value="; // Depending on platform the value could be in UK or US format (so we removed the value)
// Superscript attributes
std::string expectAttr4 = "<attr name=\"rise\" type=\"gint\" value=\"-6144\" />";
// Subscript attributes
std::string expectAttr5 = "<attr name=\"rise\" type=\"gint\" value=\"6144\" />";
// Code attributes
std::string expectAttr6 = "<attr name=\"background-gdk\" type=\"GdkColor\" value=\"e0e0:e0e0:e0e0\" />";
std::string expectAttr7 = "<attr name=\"foreground-gdk\" type=\"GdkColor\" value=\"3232:3232:3232\" />";
std::string expectAttr8 = "<attr name=\"family\" type=\"gchararray\" value=\"monospace\" />";
EXPECT_THAT(stringData, testing::HasSubstr(expectAttr1));
EXPECT_THAT(stringData, testing::HasSubstr(expectAttr2));
EXPECT_THAT(stringData, testing::HasSubstr(expectAttr3));
EXPECT_THAT(stringData, testing::HasSubstr(expectAttr4));
EXPECT_THAT(stringData, testing::HasSubstr(expectAttr5));
EXPECT_THAT(stringData, testing::HasSubstr(expectAttr6));
EXPECT_THAT(stringData, testing::HasSubstr(expectAttr7));
EXPECT_THAT(stringData, testing::HasSubstr(expectAttr8));
}
} // namespace

16
tst/file_test.cc Normal file
View File

@ -0,0 +1,16 @@
#include "file.h"
#include "gtest/gtest.h"
#include <string>
namespace
{
TEST(LibreWebTest, TestGetFilename)
{
// Given
std::string path = "/path/to/a/filename.sh";
std::string expectedFilename = "filename.sh";
// When
std::string filename = File::getFilename(path);
// Then
ASSERT_EQ(filename, expectedFilename);
}
} // namespace

28
tst/mock-middleware.h Normal file
View File

@ -0,0 +1,28 @@
#include "middleware-i.h"
#include "gmock/gmock.h"
#include <string>
struct cmark_node;
class MockMiddleware : public MiddlewareInterface
{
public:
MOCK_METHOD(void,
doRequest,
(const std::string& path, bool isSetAddressBar, bool isHistoryRequest, bool isDisableEditor, bool isParseContent),
(override));
MOCK_METHOD(std::string, doAdd, (const std::string& path), (override));
MOCK_METHOD(void, doWrite, (const std::string& path, bool isSetAddressAndTitle), (override));
MOCK_METHOD(void, setContent, (const Glib::ustring& content), (override));
MOCK_METHOD(Glib::ustring, getContent, (), (const, override));
MOCK_METHOD(cmark_node*, parseContent, (), (const, override));
MOCK_METHOD(void, resetContentAndPath, (), (override));
MOCK_METHOD(std::size_t, getIPFSNumberOfPeers, (), (const, override));
MOCK_METHOD(int, getIPFSRepoSize, (), (const, override));
MOCK_METHOD(std::string, getIPFSRepoPath, (), (const, override));
MOCK_METHOD(std::string, getIPFSIncomingRate, (), (const, override));
MOCK_METHOD(std::string, getIPFSOutcomingRate, (), (const, override));
MOCK_METHOD(std::string, getIPFSVersion, (), (const, override));
MOCK_METHOD(std::string, getIPFSClientId, (), (const, override));
MOCK_METHOD(std::string, getIPFSClientPublicKey, (), (const, override));
};

50
tst/parser_test.cc Normal file
View File

@ -0,0 +1,50 @@
#include "md-parser.h"
#include "gtest/gtest.h"
#include <cmark-gfm.h>
#include <node.h>
#include <string>
namespace
{
TEST(LibreWebTest, TestContentParser)
{
// Given
std::string markdown = "Jaja";
uint16_t expectedDocument = CMARK_NODE_DOCUMENT;
// When
cmark_node* doc = Parser::parseContent(markdown);
// Then
ASSERT_EQ(doc->type, expectedDocument);
cmark_node_free(doc);
}
TEST(LibreWebTest, TestHTMLRender)
{
// Given
std::string markdown = "_Italic_ **BOLD** ~~strike~~";
std::string expectedHtml = "<p><em>Italic</em> <strong>BOLD</strong> <del>strike</del></p>\n";
// When
cmark_node* doc = Parser::parseContent(markdown);
std::string html = Parser::renderHTML(doc);
cmark_node_free(doc);
// Then
ASSERT_EQ(html, expectedHtml);
}
TEST(LibreWebTest, TestMarkdownRender)
{
// Given
std::string markdown = "**HOLA**";
// When
cmark_node* doc = Parser::parseContent(markdown);
std::string markdownAgain = Parser::renderMarkdown(doc);
cmark_node_free(doc);
// Then
ASSERT_EQ(markdownAgain, markdown + "\n");
}
} // namespace