Merge branch 'cli/unit-test'
This commit is contained in:
14
.drone.yml
14
.drone.yml
@@ -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
2
.gitignore
vendored
@@ -9,9 +9,11 @@
|
||||
# Compilation
|
||||
build
|
||||
doc
|
||||
coverage.html
|
||||
|
||||
# Executables
|
||||
oki
|
||||
oki-test
|
||||
|
||||
# Dependencies
|
||||
third-party
|
||||
|
@@ -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`
|
||||
|
40
cli/Makefile
40
cli/Makefile
@@ -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
|
||||
|
||||
# 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
|
||||
|
||||
|
@@ -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.'
|
||||
|
||||
|
@@ -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
|
||||
|
41
cli/src/semver/Version.cpp
Normal file
41
cli/src/semver/Version.cpp
Normal 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
33
cli/src/semver/Version.h
Normal 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
2
cli/test/main.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include <doctest/doctest.h>
|
26
cli/test/semver/Version.test.cpp
Normal file
26
cli/test/semver/Version.test.cpp
Normal 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);
|
||||
}
|
Reference in New Issue
Block a user