Merge branch 'cli/unit-test'

This commit is contained in:
2022-11-23 13:04:36 +01:00
10 changed files with 178 additions and 24 deletions

View File

@@ -8,10 +8,18 @@ trigger:
branch:
- main
- feature/ci
- cli/*
steps:
- name: build-cli
image: gcc:12
image: hub.codefirst.iut.uca.fr/clement.freville2/oki-build-image:latest
commands:
- apt-get update && apt-get install -y nlohmann-json3-dev libcurl4-openssl-dev libminizip-dev
- cd cli && ./configure.sh -d && make
- cd cli && make
- name: test-cli
image: hub.codefirst.iut.uca.fr/clement.freville2/oki-build-image:latest
commands:
- cd cli && make oki-test
- ./oki-test
depends_on:
- build-cli

2
.gitignore vendored
View File

@@ -9,9 +9,11 @@
# Compilation
build
doc
coverage.html
# Executables
oki
oki-test
# Dependencies
third-party

View File

@@ -22,8 +22,8 @@ Depending on the database you have chosen, the appropriate PDO extensions are al
On Debian (versions may vary): `apt install php7.4-cli php7.4-pgsql php7.4-sqlite3`
### Command Line Interface
A C++ 17 compiler like GCC is needed, with the [nlohmann/json](https://github.com/nlohmann/json), [curl](https://github.com/curl/curl) and [minizip](https://github.com/madler/zlib/tree/master/contrib/minizip) libraries.
On Debian: `apt install build-essential nlohmann-json3-dev libcurl4-openssl-dev libminizip-dev`
A C++ 17 compiler like GCC is needed, with the [nlohmann/json](https://github.com/nlohmann/json), [curl](https://github.com/curl/curl) and [minizip](https://github.com/madler/zlib/tree/master/contrib/minizip) libraries. Unit tests are using [doctest](https://github.com/doctest/doctest).
On Debian: `apt install build-essential nlohmann-json3-dev libcurl4-openssl-dev libminizip-dev doctest-dev`
Some commands also use some clang tools like [`clang-format`](https://clang.llvm.org/docs/ClangFormat.html).
On Debian: `apt install clang-format`

View File

@@ -1,46 +1,60 @@
# Profil par défaut
BUILD := debug
# Arguments pour la compilation
CXX := g++
CXXFLAGS_debug := -g -DDEBUG
CXXFLAGS_test := -fprofile-arcs -ftest-coverage
CXXFLAGS_release := -O3
CXXFLAGS := -std=c++20 \
-Wall -Wextra \
-Wno-redundant-move \
-Wnon-virtual-dtor \
-Wsuggest-override \
-Wconversion \
-pedantic \
-g -MMD -MP \
-fdiagnostics-color=always
-MMD -MP \
$(CXXFLAGS_$(BUILD))
LDLIBS := -lcurl -lminizip # Bibliothèques utilisées pour l'édition des liens
# Nom de l'exécutable final
TARGET_EXE := oki
TARGET_EXE := oki
# Répertoires des fichiers compilés et de sources
BUILD_DIR := build
SRC_DIR := src src/cli src/config src/io src/package src/repository
BUILD_DIR := build/$(BUILD)
SRC_DIR := src src/cli src/config src/io src/package src/repository src/semver
TEST_DIR := test test/semver
# Répertoires où rechercher les fichiers header
CPPFLAGS=-Ithird-party
CPPFLAGS=-isystemthird-party -Isrc
# Liste tous les fichiers sources .cpp
sources := $(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.cpp))
tests := $(foreach dir,$(TEST_DIR),$(wildcard $(dir)/*.cpp))
# Déduit tous les fichiers objets .o à partir du nom des fichiers sources
objets := $(sources:src/%.cpp=$(BUILD_DIR)/%.o)
objets := $(sources:%.cpp=$(BUILD_DIR)/%.o)
objetsTest := $(tests:%.cpp=$(BUILD_DIR)/%.o)
# Déduit tous les fichiers dépendances .o à partir des fichiers objets
dependances := $(objets:.o=.d)
dependances := $(objets:.o=.d) $(objetsTest:.o=.d)
all: $(TARGET_EXE)
# Créé l'exécutable final avec tous les fichiers objets
$(TARGET_EXE): $(objets)
$(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(TARGET_EXE)-test: $(filter-out $(BUILD_DIR)/src/main.o, $(objets)) $(objetsTest)
$(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) -lgcov
# Définit la compilation des fichiers C++
# Le dossier de build est créé s'il n'existe pas encore
$(BUILD_DIR)/%.o: src/%.cpp | $(BUILD_DIR)
$(BUILD_DIR)/src/%.o: src/%.cpp | $(BUILD_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
$(BUILD_DIR)/test/%.o: test/%.cpp | $(BUILD_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -Isrc -c $< -o $@
# Créé le répertoire de build
$(BUILD_DIR):
mkdir -p $(subst src,$(BUILD_DIR),$(SRC_DIR))
mkdir -p $(addprefix $(BUILD_DIR)/,$(SRC_DIR)) $(addprefix $(BUILD_DIR)/,$(TEST_DIR))
# Génère la documentation avec Doxygen
doc/html/index.html: Doxyfile $(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.h))
@@ -48,13 +62,17 @@ doc/html/index.html: Doxyfile $(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.h))
# Supprime tous les fichiers issus de la compilation
clean:
rm -rf $(BUILD_DIR) $(TARGET_EXE) doc
rm -rf build $(TARGET_EXE) doc
doc: doc/html/index.html
# Formate les sources
format:
find src/ \( -name '*.cpp' -o -name '*.h' \) -exec clang-format -i {} \;
find src/ test/ \( -name '*.cpp' -o -name '*.h' \) -exec clang-format -i {} \;
# Couverture des tests
coverage.html: $(TARGET_EXE)-test build/test/test/main.o
./$(TARGET_EXE)-test && gcovr -r src -d build --html coverage.html
.PHONY: all clean doc format

View File

@@ -39,12 +39,27 @@ detectTomlPlusPlus() {
wget 'https://raw.githubusercontent.com/marzer/tomlplusplus/master/toml.hpp' -O third-party/toml.hpp
}
detectDoctest() {
if [ -f /usr/include/doctest/doctest.h ]; then
echo 'Using existing doctest/doctest installation.'
return
fi
if [ -f third-party/doctest/doctest.hpp ]; then
return
fi
mkdir -p third-party/doctest
exitIfCantDownload 'doctest/doctest'
echo 'Downloading doctest/doctest from GitHub.'
wget 'https://raw.githubusercontent.com/doctest/doctest/v2.4.9/doctest/doctest.h' -O third-party/doctest/doctest.hpp
}
detectNlohmannJson
detectTomlPlusPlus
detectDoctest
for lib in nlohmann_json libcurl minizip; do
pkg-config --exists --print-errors "$lib"
done
echo 'Found all necessary libraries.'

View File

@@ -3,6 +3,13 @@
set -eu
VDN_SYSTEM=bigboss
FILES=oki
for target; do
if [ "$target" == 'coverage.html' ] || [ "$target" == 'oki-test' ]; then
FILES="$FILES $target"
fi
done
vdn-set-network-dir ~vdn/vdn/networks/demo
if ! vdn-alive $VDN_SYSTEM; then
@@ -15,18 +22,20 @@ fi
currentDate=$(date -u +'%F %H:%M:%S')
vdn-ssh root@$VDN_SYSTEM "date -s '$currentDate' &> /dev/null"
rsync -av src -e vdn-ssh root@$VDN_SYSTEM:
rsync -av src test -e vdn-ssh root@$VDN_SYSTEM:
vdn-scp configure.sh root@$VDN_SYSTEM:
vdn-scp Makefile root@$VDN_SYSTEM:
vdn-ssh root@$VDN_SYSTEM << EOF
route del default gw 192.168.2.1
route add default gw 10.0.2.2
export http_proxy=http://193.49.118.36:8080/
./configure.sh -d
if ! pkg-config nlohmann_json --exists || ! pkg-config libcurl --exists || ! pkg-config minizip --exists; then
apt-get install -y nlohmann-json3-dev libcurl4-openssl-dev libminizip-dev
if ! pkg-config nlohmann_json --exists || ! pkg-config libcurl --exists || ! pkg-config minizip --exists || ! command -v gcovr &> /dev/null || ! [ -f /usr/include/doctest/doctest.h ]; then
apt-get install -y nlohmann-json3-dev libcurl4-openssl-dev libminizip-dev doctest-dev gcovr
fi
make
./configure.sh -d
make $*
EOF
vdn-scp root@$VDN_SYSTEM:oki .
for file in $FILES; do
vdn-scp root@$VDN_SYSTEM:"$file" . 2> /dev/null
done

View File

@@ -0,0 +1,41 @@
#include "Version.h"
#include <charconv>
namespace semver {
Version::Version(Value major, Value minor, Value patch)
: major{major}, minor{minor}, patch{patch} {}
Version Version::parse(std::string_view s) {
const char *ptr = s.data();
const char *begin = s.end();
const char *end = s.cend();
Version ret{};
std::from_chars_result result = std::from_chars(ptr, end, ret.major);
auto isError = [&]() { return result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range; };
auto isEnd = [&]() { return result.ptr == end || *result.ptr != '.'; };
if (isError() || isEnd()) {
throw InvalidVersionException{s, ptr - begin};
}
ptr = result.ptr + 1;
result = std::from_chars(ptr, end, ret.minor);
if (isError() || isEnd()) {
throw InvalidVersionException{s, ptr - begin};
}
ptr = result.ptr + 1;
result = std::from_chars(ptr, end, ret.patch);
if (isError()) {
throw InvalidVersionException{s, ptr - begin};
}
if (result.ptr != end) {
throw InvalidVersionException{s, result.ptr - begin};
}
return ret;
}
InvalidVersionException::InvalidVersionException(std::string_view string, std::ptrdiff_t offset)
: runtime_error{"Invalid semantic version: " + std::string{string}}, string{string}, offset{offset} {}
}

33
cli/src/semver/Version.h Normal file
View File

@@ -0,0 +1,33 @@
#pragma once
#include <array>
#include <compare>
#include <stdexcept>
#include <string_view>
namespace semver {
/**
* https://semver.org/lang/fr
*/
class Version {
private:
using Value = unsigned int;
Value major, minor, patch;
public:
Version() = default;
Version(Value major, Value minor, Value patch);
std::strong_ordering operator<=>(const Version &) const = default;
static Version parse(std::string_view s);
};
class InvalidVersionException : std::runtime_error {
private:
std::string string;
std::ptrdiff_t offset = 0;
public:
InvalidVersionException(std::string_view string, std::ptrdiff_t offset);
};
}

2
cli/test/main.cpp Normal file
View File

@@ -0,0 +1,2 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

View File

@@ -0,0 +1,26 @@
#include <doctest/doctest.h>
#include "semver/Version.h"
using namespace semver;
TEST_CASE("parsing valid versions") {
CHECK(Version::parse("0.4.0") == Version(0, 4, 0));
CHECK(Version::parse("1.0.0") == Version(1, 0, 0));
CHECK(Version::parse("5.9.11") == Version(5, 9, 11));
}
TEST_CASE("parsing invalid versions") {
CHECK_THROWS_AS(Version::parse("a.b.c"), InvalidVersionException);
CHECK_THROWS_AS(Version::parse("5.2"), InvalidVersionException);
CHECK_THROWS_AS(Version::parse("0.-1.6"), InvalidVersionException);
CHECK_THROWS_AS(Version::parse("1.3.a5"), InvalidVersionException);
CHECK_THROWS_AS(Version::parse("2 9 3"), InvalidVersionException);
CHECK_THROWS_AS(Version::parse("4.2.3beta"), InvalidVersionException);
}
TEST_CASE("comparing versions") {
CHECK((Version(1, 0, 4) <=> Version(1, 0, 3)) == std::strong_ordering::greater);
CHECK((Version(0, 4, 2) <=> Version(0, 5, 0)) == std::strong_ordering::less);
CHECK((Version(1, 10, 2) <=> Version(2, 4, 1)) == std::strong_ordering::less);
}