From 425decdf7e9284d15aa726e3ae96b9942fb0e3ea Mon Sep 17 00:00:00 2001 From: IronClawTrem Date: Sun, 16 Feb 2020 03:40:06 +0000 Subject: create tremded branch --- external/semver/.gitignore | 2 + external/semver/.gitmodules | 6 + external/semver/.travis.yml | 93 +++++++ external/semver/CMakeLists.txt | 100 +++++++ external/semver/LICENSE | 21 ++ external/semver/README.md | 12 + external/semver/appveyor.yml | 35 +++ external/semver/install_libcxx.sh | 13 + external/semver/src/include/semantic_version.h | 189 +++++++++++++ external/semver/src/lib/CMakeLists.txt | 1 + external/semver/src/lib/semantic_version_v1.cpp | 286 ++++++++++++++++++++ external/semver/src/lib/semantic_version_v2.cpp | 272 +++++++++++++++++++ external/semver/src/quickcheck/CMakeLists.txt | 29 ++ external/semver/src/quickcheck/Main.hi | Bin 0 -> 3353 bytes external/semver/src/quickcheck/Main.hs | 80 ++++++ external/semver/src/quickcheck/Main.o | Bin 0 -> 35952 bytes external/semver/src/quickcheck/Semver.hsc | 87 ++++++ .../semver/src/quickcheck/semantic_version_ffi.cpp | 58 ++++ .../semver/src/quickcheck/semantic_version_ffi.h | 27 ++ external/semver/src/test/CMakeLists.txt | 3 + external/semver/src/test/main.cpp | 297 +++++++++++++++++++++ 21 files changed, 1611 insertions(+) create mode 100644 external/semver/.gitignore create mode 100644 external/semver/.gitmodules create mode 100644 external/semver/.travis.yml create mode 100644 external/semver/CMakeLists.txt create mode 100644 external/semver/LICENSE create mode 100644 external/semver/README.md create mode 100644 external/semver/appveyor.yml create mode 100644 external/semver/install_libcxx.sh create mode 100644 external/semver/src/include/semantic_version.h create mode 100644 external/semver/src/lib/CMakeLists.txt create mode 100644 external/semver/src/lib/semantic_version_v1.cpp create mode 100644 external/semver/src/lib/semantic_version_v2.cpp create mode 100644 external/semver/src/quickcheck/CMakeLists.txt create mode 100644 external/semver/src/quickcheck/Main.hi create mode 100644 external/semver/src/quickcheck/Main.hs create mode 100644 external/semver/src/quickcheck/Main.o create mode 100644 external/semver/src/quickcheck/Semver.hsc create mode 100644 external/semver/src/quickcheck/semantic_version_ffi.cpp create mode 100644 external/semver/src/quickcheck/semantic_version_ffi.h create mode 100644 external/semver/src/test/CMakeLists.txt create mode 100644 external/semver/src/test/main.cpp (limited to 'external/semver') diff --git a/external/semver/.gitignore b/external/semver/.gitignore new file mode 100644 index 0000000..d3b8be9 --- /dev/null +++ b/external/semver/.gitignore @@ -0,0 +1,2 @@ +build/ +TAGS diff --git a/external/semver/.gitmodules b/external/semver/.gitmodules new file mode 100644 index 0000000..4a99d01 --- /dev/null +++ b/external/semver/.gitmodules @@ -0,0 +1,6 @@ +[submodule "contrib/testinator"] + path = contrib/testinator + url = https://github.com/elbeno/testinator.git +[submodule "contrib/gsl"] + path = contrib/gsl + url = https://github.com/Microsoft/GSL.git diff --git a/external/semver/.travis.yml b/external/semver/.travis.yml new file mode 100644 index 0000000..e8a599a --- /dev/null +++ b/external/semver/.travis.yml @@ -0,0 +1,93 @@ +# adapted from https://github.com/ericniebler/range-v3 + +language: cpp +script: cmake + +matrix: + include: + - env: CLANG_VERSION=3.4 BUILD_TYPE=Debug CPP=1y SAN=On LIBCXX=On + os: linux + addons: &clang34 + apt: + packages: + - util-linux + - clang-3.4 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.4 + + - env: CLANG_VERSION=3.4 BUILD_TYPE=Release CPP=1y SAN=On LIBCXX=On + os: linux + addons: *clang34 + + - env: CLANG_VERSION=3.7 BUILD_TYPE=Debug CPP=14 SAN=Off LIBCXX=On + os: linux + addons: &clang37 + apt: + packages: + - util-linux + - clang-3.7 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + + - env: CLANG_VERSION=3.7 BUILD_TYPE=Release CPP=14 SAN=Off LIBCXX=On + os: linux + addons: *clang37 + + # - env: GCC_VERSION=4.9 BUILD_TYPE=Debug CPP=14 SAN=Off LIBCXX=Off + # os: linux + # addons: &gcc49 + # apt: + # packages: + # - g++-4.9 + # sources: + # - ubuntu-toolchain-r-test + + # - env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=14 SAN=Off LIBCXX=Off + # os: linux + # addons: *gcc49 + + - env: GCC_VERSION=5 BUILD_TYPE=Debug CPP=14 SAN=Off LIBCXX=Off + os: linux + addons: &gcc5 + apt: + packages: + - g++-5 + sources: + - ubuntu-toolchain-r-test + + - env: GCC_VERSION=5 BUILD_TYPE=Release CPP=14 SAN=Off LIBCXX=Off + os: linux + addons: *gcc5 + +before_install: + - export CHECKOUT_PATH=`pwd`; + - if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi + - if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi + - if [ "$CLANG_VERSION" == "3.4" ]; then export CXX="/usr/local/clang-3.4/bin/clang++" CC="/usr/local/clang-3.4/bin/clang"; fi + - if [ "$LIBCXX" == "On" ]; then sudo CXX=$CXX CC=$CC ./install_libcxx.sh; fi + +install: + - cd $CHECKOUT_PATH + + - if [ ! -d build ]; then mkdir build; fi + - cd build + + - export CXX_FLAGS="" + - export CXX_LINKER_FLAGS="" + + - if [ -z "$BUILD_TYPE" ]; then export BUILD_TYPE=Debug; fi + + - if [ -n "$CLANG_VERSION" ]; then CXX_FLAGS="${CXX_FLAGS} -D__extern_always_inline=inline"; fi + - if [ "$LIBCXX" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -stdlib=libc++ -I/usr/include/c++/v1/"; fi + - if [ "$LIBCXX" == "On" ]; then CXX_LINKER_FLAGS="${CXX_FLAGS} -L/usr/lib/ -lc++"; fi + + - cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${CXX_LINKER_FLAGS}" -DCXX_STD=$CPP -DCI_BUILD=1 + - make VERBOSE=1 + +script: + - if [ "$BUILD_TYPE" == "Debug" ]; then ctest -VV --schedule-random; fi + +notifications: + email: false diff --git a/external/semver/CMakeLists.txt b/external/semver/CMakeLists.txt new file mode 100644 index 0000000..2919ee3 --- /dev/null +++ b/external/semver/CMakeLists.txt @@ -0,0 +1,100 @@ +cmake_minimum_required (VERSION 2.8) +project (semver) + +# Includes for this project +include_directories ("${PROJECT_SOURCE_DIR}/src/include") + +# Include testinator and the GSL +include_directories ("${PROJECT_SOURCE_DIR}/contrib/testinator/src/include") +include_directories ("${PROJECT_SOURCE_DIR}/contrib/gsl/include") + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Default C++ standard: C++14 +if(CXX_STD) +else() + set(CXX_STD 14) +endif() + +# Set up tests +enable_testing() +include(CTest) + +if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + set(MY_CXX_FLAGS_LIST + ) + string(REPLACE ";" " " MY_CXX_FLAGS "${MY_CXX_FLAGS_LIST}") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MY_CXX_FLAGS}") +else() + set(MY_CXX_FLAGS_LIST + -ftemplate-backtrace-limit=0 + -ffunction-sections + -Wall -Wextra -Werror -pedantic-errors + -Wcast-align + -Wcast-qual + -Wctor-dtor-privacy + -Wdisabled-optimization + -Wformat=2 + -Winit-self + -Wmissing-include-dirs + # -Wold-style-cast + -Woverloaded-virtual + -Wredundant-decls + # -Wshadow + # -Wsign-conversion + -Wsign-promo + -Wstrict-overflow=2 + -Wswitch-default + -Wundef + ) + string(REPLACE ";" " " MY_CXX_FLAGS "${MY_CXX_FLAGS_LIST}") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++${CXX_STD} ${MY_CXX_FLAGS}") + + # Debug/Release + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-inline -g3 -fstack-protector-all") + set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -g0 -march=native -mtune=native -DNDEBUG") + set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage") +endif() + +# Clang/GCC specifics +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(SAN) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined,integer -fno-omit-frame-pointer -fno-sanitize=unsigned-integer-overflow") + endif() +elseif(CMAKE_COMPILER_IS_GNUCXX) +endif() + +# Pipe separate tests into ctest +# Adapted from https://github.com/ChaiScript/ChaiScript/blob/develop/CMakeLists.txt +macro(ADD_INDIVIDUAL_TESTS executable type suffix) + set(test_path $ENV{PATH}) + get_target_property(target_files ${executable} SOURCES) + foreach(source ${target_files}) + string(REGEX MATCH .*cpp source "${source}") + if(source) + file(READ "${source}" contents) + string(REGEX MATCHALL "DEF_${type}[ ]*[(][ ]*[^, ]+[ ]*,[ ]*[^,) ]+[ ]*[),]" found_tests ${contents}) + foreach(hit ${found_tests}) + string(REGEX REPLACE "DEF_${type}[ ]*[(][ ]*([^, ]+)[ ]*,[ ]*[^,) ]+[ ]*[),]" "\\1" tname ${hit}) + string(REGEX REPLACE "DEF_${type}[ ]*[(][ ]*[^, ]+[ ]*,[ ]*([^,) ]+)[ ]*[),]" "\\1" sname ${hit}) + set(test_name ${executable}.${sname}.${tname}${suffix}) + add_test(NAME ${test_name} + COMMAND "${executable}" --testName=${tname}${suffix} --suiteName=${sname}) + set_tests_properties(${test_name} PROPERTIES TIMEOUT 30 ENVIRONMENT "PATH=${test_path}") + endforeach() + endif() + endforeach() +endmacro() + +macro(ADD_TESTINATOR_TESTS executable) + ADD_INDIVIDUAL_TESTS(${executable} "TEST" "") + ADD_INDIVIDUAL_TESTS(${executable} "TIMED_TEST" "") + ADD_INDIVIDUAL_TESTS(${executable} "PROPERTY" "Property") + ADD_INDIVIDUAL_TESTS(${executable} "COMPLEXITY_PROPERTY" "ComplexityProperty") +endmacro() + +add_subdirectory (src/lib) +add_subdirectory (src/test) +add_subdirectory (src/quickcheck) diff --git a/external/semver/LICENSE b/external/semver/LICENSE new file mode 100644 index 0000000..58b7258 --- /dev/null +++ b/external/semver/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2016 Ben Deane + +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/external/semver/README.md b/external/semver/README.md new file mode 100644 index 0000000..c2e1cc7 --- /dev/null +++ b/external/semver/README.md @@ -0,0 +1,12 @@ +# Semver + +A C++ class for handling semantic versioning as detailed at http://semver.org/. + +Bonus: experimental testing with Haskell's QuickCheck. + +### Status +[![Build Status](https://travis-ci.org/elbeno/semver.svg?branch=master)](https +://travis-ci.org/elbeno/semver) +[![Build status](https://ci.appveyor.com/api/projects/status/ve1bvyxharcq9gv3?svg=true)](https://ci.appveyor.com/project/elbeno/semver) + +This project is distributed under some license. See LICENSE for details. diff --git a/external/semver/appveyor.yml b/external/semver/appveyor.yml new file mode 100644 index 0000000..70afe93 --- /dev/null +++ b/external/semver/appveyor.yml @@ -0,0 +1,35 @@ +platform: + - x86 + - x64 + +configuration: + - Debug + - Release + +os: Visual Studio 2015 + +clone_folder: c:\projects\semver + +install: + - git submodule update --init --recursive + +build_script: + # show settings + - cmake -version + - echo %platform% + - echo %configuration% + + # generate a solution file + - cd c:\projects\semver + - mkdir build + - cd build + - if "%platform%" == "x64" set cmake_platform=%platform% + - cmake -g "Visual Studio 14 2015" .. -DCMAKE_GENERATOR_PLATFORM=%cmake_platform% + + # build it + - if "%platform%" == "x86" set msbuild_platform=Win32 + - if "%platform%" == "x64" set msbuild_platform=%platform% + - msbuild semver.sln /p:Configuration=%configuration% /toolsversion:14.0 /p:PlatformToolset=v140 /p:Platform=%msbuild_platform% + +test_script: + - if "%configuration%" == "Debug" ctest -VV --schedule-random -C Debug diff --git a/external/semver/install_libcxx.sh b/external/semver/install_libcxx.sh new file mode 100644 index 0000000..dbdb579 --- /dev/null +++ b/external/semver/install_libcxx.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Install libc++ under travis +# Copied from https://github.com/ericniebler/range-v3 + +svn --quiet co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx +mkdir libcxx/build +(cd libcxx/build && cmake .. -DLIBCXX_CXX_ABI=libstdc++ -DLIBCXX_CXX_ABI_INCLUDE_PATHS="/usr/include/c++/4.6;/usr/include/c++/4.6/x86_64-linux-gnu") +make -C libcxx/build cxx -j2 +sudo cp libcxx/build/lib/libc++.so.1.0 /usr/lib/ +sudo cp -r libcxx/build/include/c++/v1 /usr/include/c++/v1/ +sudo ln -sf /usr/lib/libc++.so.1.0 /usr/lib/libc++.so +sudo ln -sf /usr/lib/libc++.so.1.0 /usr/lib/libc++.so.1 diff --git a/external/semver/src/include/semantic_version.h b/external/semver/src/include/semantic_version.h new file mode 100644 index 0000000..a6214f9 --- /dev/null +++ b/external/semver/src/include/semantic_version.h @@ -0,0 +1,189 @@ +#pragma once + +// Semantic version - see http://semver.org/ + +// The major difference between v1::Version and v2::Version is that v1 includes +// the build identifier when calculating precedence of versions (see +// http://semver.org/spec/v2.0.0-rc.1.html points 10,11) while v2 omits the +// build identifier when calculating precedence of versions (see +// http://semver.org/spec/v2.0.0.html points 10,11). + +#include +#include + +namespace semver +{ + namespace v1 + { + + class Version + { + public: + // By-parts (and default) version constructor: no validation. + Version( + unsigned int major = 0, + unsigned int minor = 0, + unsigned int patch = 1, + const std::string& prerelease = std::string{}, + const std::string& build = std::string{}); + + // Parse from a version string: no validation. + explicit Version(const std::string& s); + + // Is a version well-formed according to the spec? + // The semver spec stipulates a few properties of a well-formed version: + // that both the dot-separated prerelease version and the build version + // MUST comprise only [0-9A-Za-z-]; that numerical dot-separated + // identifiers MUST NOT include leading zeroes; and that such identifiers + // MUST NOT be empty. + bool IsWellFormed() const; + + // Parse from a version string, with validation according to the spec. + static Version Parse(const std::string& s, bool& wellformed); + + unsigned int GetMajorVersion() const { return m_majorVersion; } + unsigned int GetMinorVersion() const { return m_minorVersion; } + unsigned int GetPatchVersion() const { return m_patchVersion; } + + // Create a new version by incrementing a part of a version. Other parts + // will be reset to 0, per the spec. + Version NextMajorVersion() const; + Version NextMinorVersion() const; + Version NextPatchVersion() const; + + // A version satisfies another version if it is greater than or equal to + // it in precedence. Additionally, pre-release versions and build versions + // both satisfy their corresponding normal versions, and all pre-release + // or build versions thereof. + bool Satisfies(const Version& other) const; + + // Precedence is calculated by comparing the major, minor, patch, + // pre-release and build parts in that order. Pre-release and build + // strings are considered as lists of dot-separated identifiers, whereby + // if an identifier is numeric, it is compared as such; otherwise + // comparison is based on ASCII sort order. + friend bool operator<(const Version& a, const Version& b); + friend bool operator==(const Version& a, const Version& b); + + // A version is output as X.Y.Z (Major.Minor.Patch) + // A pre-release string (eg alpha.1) may follow immediately, joined by a - + // A build string may follow (eg 123.f83eaa931), joined by a + + friend std::ostream& operator<<(std::ostream& s, const Version& v); + + private: + unsigned int m_majorVersion = 0; + unsigned int m_minorVersion = 0; + unsigned int m_patchVersion = 1; + std::string m_prereleaseVersion; + std::string m_buildVersion; + }; + + inline bool operator!=(const Version& a, const Version& b) + { + return !(a == b); + } + + inline bool operator>=(const Version& a, const Version& b) + { + return !(a < b); + } + + inline bool operator<=(const Version& a, const Version& b) + { + return (a == b) || (a < b); + } + + inline bool operator>(const Version& a, const Version& b) + { + return (a != b) && (a >= b); + } + } + + inline namespace v2 + { + + class Version + { + public: + // By-parts (and default) version constructor: no validation. + Version( + unsigned int major = 0, + unsigned int minor = 0, + unsigned int patch = 1, + const std::string& prerelease = std::string{}, + const std::string& build = std::string{}); + + // Parse from a version string: no validation. + explicit Version(const std::string& s); + + // Is a version well-formed according to the spec? + // The semver spec stipulates a few properties of a well-formed version: + // that both the dot-separated prerelease version and the build version + // MUST comprise only [0-9A-Za-z-]; that numerical dot-separated + // identifiers MUST NOT include leading zeroes; and that such identifiers + // MUST NOT be empty. + bool IsWellFormed() const; + + unsigned int GetMajorVersion() const { return m_majorVersion; } + unsigned int GetMinorVersion() const { return m_minorVersion; } + unsigned int GetPatchVersion() const { return m_patchVersion; } + + // Create a new version by incrementing a part of a version. Other parts + // will be reset to 0, per the spec. + Version NextMajorVersion() const; + Version NextMinorVersion() const; + Version NextPatchVersion() const; + + // A version satisfies another version if it is greater than or equal to + // it in precedence. Additionally, pre-release versions and build versions + // both satisfy their corresponding normal versions, and all pre-release + // or build versions thereof. + bool Satisfies(const Version& other) const; + + // Precedence is calculated by comparing the major, minor, patch, and + // pre-release parts in that order. Pre-release strings are considered as + // lists of dot-separated identifiers, whereby if an identifier is + // numeric, it is compared as such; otherwise comparison is based on ASCII + // sort order. Note: according to semver v2.0.0, build version is NOT + // considered when determining precedence. + friend bool operator<(const Version& a, const Version& b); + friend bool operator==(const Version& a, const Version& b); + + // For exact equality (as opposed to precedence equality) + bool Equals(const Version& other) const; + + // A version is output as X.Y.Z (Major.Minor.Patch) + // A pre-release string (eg alpha.1) may follow immediately, joined by a - + // A build string may follow (eg 123.f83eaa931), joined by a + + friend std::ostream& operator<<(std::ostream& s, const Version& v); + + private: + unsigned int m_majorVersion = 0; + unsigned int m_minorVersion = 0; + unsigned int m_patchVersion = 1; + std::string m_prereleaseVersion; + std::string m_buildVersion; + }; + + inline bool operator!=(const Version& a, const Version& b) + { + return !(a == b); + } + + inline bool operator>=(const Version& a, const Version& b) + { + return !(a < b); + } + + inline bool operator<=(const Version& a, const Version& b) + { + return (a == b) || (a < b); + } + + inline bool operator>(const Version& a, const Version& b) + { + return (a != b) && (a >= b); + } + } +} + diff --git a/external/semver/src/lib/CMakeLists.txt b/external/semver/src/lib/CMakeLists.txt new file mode 100644 index 0000000..ad43505 --- /dev/null +++ b/external/semver/src/lib/CMakeLists.txt @@ -0,0 +1 @@ +add_library (${PROJECT_NAME} semantic_version_v1.cpp semantic_version_v2.cpp) diff --git a/external/semver/src/lib/semantic_version_v1.cpp b/external/semver/src/lib/semantic_version_v1.cpp new file mode 100644 index 0000000..4df8bef --- /dev/null +++ b/external/semver/src/lib/semantic_version_v1.cpp @@ -0,0 +1,286 @@ +#include "semantic_version.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; + +//------------------------------------------------------------------------------ +// From http://semver.org/ - Version 2.0.0 + +// Pre-release versions satisfy but have a lower precedence than the associated +// normal version. + +// Build versions satisfy and have a higher precedence than the associated +// normal version. + +// Precedence MUST be calculated by separating the version into major, minor, +// patch, pre-release, and build identifiers in that order. Major, minor, and +// patch versions are always compared numerically. Pre-release and build version +// precedence MUST be determined by comparing each dot separated identifier as +// follows: identifiers consisting of only digits are compared numerically and +// identifiers with letters or dashes are compared lexically in ASCII sort +// order. Numeric identifiers always have lower precedence than non-numeric +// identifiers. Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 < +// 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 < +// 1.3.7+build < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a. + +namespace +{ + void SplitDottedString(const string& s, vector& v) + { + istringstream ss(s); + for (string part; getline(ss, part, '.'); v.push_back(part)); + } + + int CompareIdentifiers(const string& s1, const string& s2) + { + // We need to split the dotted identifier list into individual identifiers, + // and treat purely numeric identifiers as the numbers they represent. + + vector v1; + SplitDottedString(s1, v1); + + vector v2; + SplitDottedString(s2, v2); + + for (size_t i = 0; ; ++i) + { + // exhausted both vectors: they must be equal + if (i >= v1.size() && i >= v2.size()) + { + return 0; + } + + // exhausted one vector: it's the smaller one + if (i >= v1.size()) + { + return -1; + } + if (i >= v2.size()) + { + return 1; + } + + // is either of v1[i] or v2[i] a number? + const string& id1 = v1[i]; + bool id1IsNumber = all_of(id1.cbegin(), id1.cend(), + [] (char c) { return isdigit(c); }); + const string& id2 = v2[i]; + bool id2IsNumber = all_of(id2.cbegin(), id2.cend(), + [] (char c) { return isdigit(c); }); + + // if both numbers - compare them as such + if (id1IsNumber && id2IsNumber) + { + long num1 = atol(id1.c_str()); + long num2 = atol(id2.c_str()); + if (num1 - num2 != 0) + { + return num1 - num2; + } + else + { + continue; + } + } + // if one is a number - that one is lesser + if (id1IsNumber) + { + return -1; + } + if (id2IsNumber) + { + return 1; + } + // neither are numbers: compare them + int c = id1.compare(id2); + if (c != 0) + { + return c; + } + } + } + + bool IdentifierIsValid(const string& i) + { + vector v; + SplitDottedString(i, v); + + for (const auto& s : v) + { + // Identifiers must not be empty. + if (s.empty()) + { + return false; + } + + // Identifiers must contain only alphanumerics and '-'. + if (any_of(s.cbegin(), s.cend(), + [] (char c) { return !isalnum(c) && c != '-'; })) + { + return false; + } + + // Numeric identifiers must not contain leading zeroes. + bool numeric = all_of(s.cbegin(), s.cend(), + [] (char c) { return isdigit(c); }); + if (numeric && s[0] == '0') + { + return false; + } + } + + return true; + } +} + +namespace semver { + namespace v1 { + +//------------------------------------------------------------------------------ +Version::Version( + unsigned int major, + unsigned int minor, + unsigned int patch, + const std::string& prerelease, + const std::string& build) + : m_majorVersion(major) + , m_minorVersion(minor) + , m_patchVersion(patch) + , m_prereleaseVersion(prerelease) + , m_buildVersion(build) +{ +} + +Version::Version(const string& s) +{ + // major.minor.patch-release+build + + istringstream ss(s); + string part; + + if (!getline(ss, part, '.')) return; + m_majorVersion = static_cast(strtoul(part.c_str(), 0, 0)); + if (!getline(ss, part, '.')) return; + m_minorVersion = static_cast(strtoul(part.c_str(), 0, 0)); + if (!getline(ss, part, '-')) return; + m_patchVersion = static_cast(strtoul(part.c_str(), 0, 0)); + + if (!getline(ss, m_prereleaseVersion, '+')) return; + getline(ss, m_buildVersion, '\0'); +} + +//------------------------------------------------------------------------------ +bool Version::IsWellFormed() const +{ + return IdentifierIsValid(m_prereleaseVersion) + && IdentifierIsValid(m_buildVersion); +} + +//------------------------------------------------------------------------------ +// When incrementing versions, all lower version parts are reset. + +Version Version::NextMajorVersion() const +{ + return Version(m_majorVersion + 1, 0, 0); +} + +Version Version::NextMinorVersion() const +{ + return Version(m_majorVersion, m_minorVersion + 1, 0); +} + +Version Version::NextPatchVersion() const +{ + return Version(m_majorVersion, m_minorVersion, m_patchVersion + 1); +} + + +//------------------------------------------------------------------------------ +bool Version::Satisfies(const Version& other) const +{ + return tie(m_majorVersion, m_minorVersion, m_patchVersion) >= + tie(other.m_majorVersion, other.m_minorVersion, other.m_patchVersion); +} + +//------------------------------------------------------------------------------ +bool operator==(const Version& a, const Version& b) +{ + return + tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion, + a.m_prereleaseVersion, a.m_buildVersion) == + tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion, + b.m_prereleaseVersion, b.m_buildVersion); +} + +//------------------------------------------------------------------------------ +bool operator<(const Version& a, const Version& b) +{ + if (tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion) < + tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion)) + { + return true; + } + + // pre-release version < normal version + if (!a.m_prereleaseVersion.empty() && b.m_prereleaseVersion.empty()) + { + return true; + } + if (a.m_prereleaseVersion.empty() && !b.m_prereleaseVersion.empty()) + { + return false; + } + + int prComp = CompareIdentifiers(a.m_prereleaseVersion, b.m_prereleaseVersion); + if (prComp < 0) + { + return true; + } + else if (prComp == 0) + { + // build version > normal version + if (a.m_buildVersion.empty() && !b.m_buildVersion.empty()) + { + return true; + } + if (!a.m_buildVersion.empty() && b.m_buildVersion.empty()) + { + return false; + } + + int bComp = CompareIdentifiers(a.m_buildVersion, b.m_buildVersion); + if (bComp < 0) + { + return true; + } + } + return false; +} + +//------------------------------------------------------------------------------ +ostream& operator<<(ostream& s, const Version& v) +{ + s << v.m_majorVersion + << '.' << v.m_minorVersion + << '.' << v.m_patchVersion; + + if (!v.m_prereleaseVersion.empty()) + { + s << '-' << v.m_prereleaseVersion; + } + if (!v.m_buildVersion.empty()) + { + s << '+' << v.m_buildVersion; + } + + return s; +} + + } +} diff --git a/external/semver/src/lib/semantic_version_v2.cpp b/external/semver/src/lib/semantic_version_v2.cpp new file mode 100644 index 0000000..7bada17 --- /dev/null +++ b/external/semver/src/lib/semantic_version_v2.cpp @@ -0,0 +1,272 @@ +#include "semantic_version.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; + +//------------------------------------------------------------------------------ +// From http://semver.org/ - Version 2.0.0 + +// Pre-release versions satisfy but have a lower precedence than the associated +// normal version. + +// Build versions satisfy and have a higher precedence than the associated +// normal version. + +// Precedence MUST be calculated by separating the version into major, minor, +// patch, pre-release, and build identifiers in that order. Major, minor, and +// patch versions are always compared numerically. Pre-release and build version +// precedence MUST be determined by comparing each dot separated identifier as +// follows: identifiers consisting of only digits are compared numerically and +// identifiers with letters or dashes are compared lexically in ASCII sort +// order. Numeric identifiers always have lower precedence than non-numeric +// identifiers. Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 < +// 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 < +// 1.3.7+build < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a. + +namespace +{ + void SplitDottedString(const string& s, vector& v) + { + istringstream ss(s); + for (string part; getline(ss, part, '.'); v.push_back(part)); + } + + int CompareIdentifiers(const string& s1, const string& s2) + { + // We need to split the dotted identifier list into individual identifiers, + // and treat purely numeric identifiers as the numbers they represent. + + vector v1; + SplitDottedString(s1, v1); + + vector v2; + SplitDottedString(s2, v2); + + for (size_t i = 0; ; ++i) + { + // exhausted both vectors: they must be equal + if (i >= v1.size() && i >= v2.size()) + { + return 0; + } + + // exhausted one vector: it's the smaller one + if (i >= v1.size()) + { + return -1; + } + if (i >= v2.size()) + { + return 1; + } + + // is either of v1[i] or v2[i] a number? + const string& id1 = v1[i]; + bool id1IsNumber = all_of(id1.cbegin(), id1.cend(), + [] (char c) { return isdigit(c); }); + const string& id2 = v2[i]; + bool id2IsNumber = all_of(id2.cbegin(), id2.cend(), + [] (char c) { return isdigit(c); }); + + // if both numbers - compare them as such + if (id1IsNumber && id2IsNumber) + { + long num1 = atol(id1.c_str()); + long num2 = atol(id2.c_str()); + if (num1 - num2 != 0) + { + return num1 - num2; + } + else + { + continue; + } + } + // if one is a number - that one is lesser + if (id1IsNumber) + { + return -1; + } + if (id2IsNumber) + { + return 1; + } + // neither are numbers: compare them + int c = id1.compare(id2); + if (c != 0) + { + return c; + } + } + } + + bool IdentifierIsValid(const string& i) + { + vector v; + SplitDottedString(i, v); + + for (const auto& s : v) + { + // Identifiers must not be empty. + if (s.empty()) + { + return false; + } + + // Identifiers must contain only alphanumerics and '-'. + if (any_of(s.cbegin(), s.cend(), + [] (char c) { return !isalnum(c) && c != '-' && c != '.'; })) + { + return false; + } + + // Numeric identifiers must not contain leading zeroes. + bool numeric = all_of(s.cbegin(), s.cend(), + [] (char c) { return isdigit(c); }); + if (numeric && s[0] == '0') + { + return false; + } + } + + return true; + } +} + +namespace semver { + inline namespace v2 { + +//------------------------------------------------------------------------------ +Version::Version( + unsigned int major, + unsigned int minor, + unsigned int patch, + const std::string& prerelease, + const std::string& build) + : m_majorVersion(major) + , m_minorVersion(minor) + , m_patchVersion(patch) + , m_prereleaseVersion(prerelease) + , m_buildVersion(build) +{ +} + +Version::Version(const string& s) +{ + // major.minor.patch-release+build + + istringstream ss(s); + string part; + + if (!getline(ss, part, '.')) return; + m_majorVersion = static_cast(strtoul(part.c_str(), 0, 0)); + if (!getline(ss, part, '.')) return; + m_minorVersion = static_cast(strtoul(part.c_str(), 0, 0)); + if (!getline(ss, part, '-')) return; + m_patchVersion = static_cast(strtoul(part.c_str(), 0, 0)); + + if (!getline(ss, m_prereleaseVersion, '+')) return; + getline(ss, m_buildVersion, '\0'); +} + +//------------------------------------------------------------------------------ +bool Version::IsWellFormed() const +{ + return IdentifierIsValid(m_prereleaseVersion) + && IdentifierIsValid(m_buildVersion); +} + +//------------------------------------------------------------------------------ +// When incrementing versions, all lower version parts are reset. + +Version Version::NextMajorVersion() const +{ + return Version(m_majorVersion + 1, 0, 0); +} + +Version Version::NextMinorVersion() const +{ + return Version(m_majorVersion, m_minorVersion + 1, 0); +} + +Version Version::NextPatchVersion() const +{ + return Version(m_majorVersion, m_minorVersion, m_patchVersion + 1); +} + +//------------------------------------------------------------------------------ +bool Version::Satisfies(const Version& other) const +{ + return tie(m_majorVersion, m_minorVersion, m_patchVersion) >= + tie(other.m_majorVersion, other.m_minorVersion, other.m_patchVersion); +} + +//------------------------------------------------------------------------------ +bool operator==(const Version& a, const Version& b) +{ + return + tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion, + a.m_prereleaseVersion) == + tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion, + b.m_prereleaseVersion); +} + +//------------------------------------------------------------------------------ +bool operator<(const Version& a, const Version& b) +{ + const auto ta = tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion); + const auto tb = tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion); + + if (ta < tb) return true; + if (ta > tb) return false; + + // pre-release version < normal version + if (!a.m_prereleaseVersion.empty() && b.m_prereleaseVersion.empty()) + { + return true; + } + if (a.m_prereleaseVersion.empty() && !b.m_prereleaseVersion.empty()) + { + return false; + } + + return CompareIdentifiers(a.m_prereleaseVersion, b.m_prereleaseVersion) <= 0; +} + +//------------------------------------------------------------------------------ +bool Version::Equals(const Version& other) const +{ + return + tie(m_majorVersion, m_minorVersion, m_patchVersion, + m_prereleaseVersion, m_buildVersion) == + tie(other.m_majorVersion, other.m_minorVersion, other.m_patchVersion, + other.m_prereleaseVersion, other.m_buildVersion); +} + +//------------------------------------------------------------------------------ +ostream& operator<<(ostream& s, const Version& v) +{ + s << v.m_majorVersion + << '.' << v.m_minorVersion + << '.' << v.m_patchVersion; + + if (!v.m_prereleaseVersion.empty()) + { + s << '-' << v.m_prereleaseVersion; + } + if (!v.m_buildVersion.empty()) + { + s << '+' << v.m_buildVersion; + } + + return s; +} + + } +} diff --git a/external/semver/src/quickcheck/CMakeLists.txt b/external/semver/src/quickcheck/CMakeLists.txt new file mode 100644 index 0000000..b8bb9b9 --- /dev/null +++ b/external/semver/src/quickcheck/CMakeLists.txt @@ -0,0 +1,29 @@ +find_program(HSC2HS hsc2hs) +find_program(GHC ghc) + +if (HSC2HS AND GHC) + + # the shared lib + add_library(${PROJECT_NAME}_ffi SHARED + ../lib/semantic_version_v1.cpp ../lib/semantic_version_v2.cpp semantic_version_ffi.cpp) + # the ffi bindings + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Semver.hs + MAIN_DEPENDENCY Semver.hsc + DEPENDS semantic_version_ffi.h + COMMAND ${HSC2HS} ${CMAKE_CURRENT_SOURCE_DIR}/Semver.hsc -I ${CMAKE_CURRENT_SOURCE_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/Semver.hs) + # the quickcheck executable + add_custom_command( + OUTPUT quickcheck_${PROJECT_NAME} + MAIN_DEPENDENCY Main.hs + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Semver.hs + DEPENDS ${PROJECT_NAME}_ffi + COMMAND ${GHC} --make ${CMAKE_CURRENT_SOURCE_DIR}/Main -L. -lsemver_ffi -o quickcheck_${PROJECT_NAME}) + add_custom_target(quickcheck ALL + DEPENDS quickcheck_${PROJECT_NAME}) + # pipe to ctest + add_test(NAME quickcheck_${PROJECT_NAME} + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/quickcheck_${PROJECT_NAME}) + set_tests_properties(quickcheck_${PROJECT_NAME} PROPERTIES TIMEOUT 30 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}") + +endif() diff --git a/external/semver/src/quickcheck/Main.hi b/external/semver/src/quickcheck/Main.hi new file mode 100644 index 0000000..0739459 Binary files /dev/null and b/external/semver/src/quickcheck/Main.hi differ diff --git a/external/semver/src/quickcheck/Main.hs b/external/semver/src/quickcheck/Main.hs new file mode 100644 index 0000000..fc1d625 --- /dev/null +++ b/external/semver/src/quickcheck/Main.hs @@ -0,0 +1,80 @@ +module Main where + +import Semver +import Test.QuickCheck + +import System.Environment +import System.Console.GetOpt + +-- command line options +data Options = Options { optVerbose :: Bool + , optNumTests :: Int + } deriving Show + +defaultOptions :: Options +defaultOptions = Options { optVerbose = False + , optNumTests = 100 + } + +options :: [OptDescr (Options -> Options)] +options = + [ Option "v" ["verbose"] (NoArg (\opts -> opts { optVerbose = True })) + "run tests with verbose output" + + , Option "n" ["numtests"] (ReqArg + (\d opts -> opts { optNumTests = read d }) + "") + "number of tests to run" + ] + +parseOpts :: [String] -> IO (Options, [String]) +parseOpts argv = + case getOpt Permute options argv of + (o, n, []) -> return (foldl (flip id) defaultOpts o, n) + where defaultOpts = defaultOptions + (_, _, errs) -> ioError (userError (concat errs ++ usageInfo header options)) + where header = "Usage: test [options]" + +-- generate arbitrary Senvers +instance Arbitrary Semver where + arbitrary = do + r1 <- arbitrary + r2 <- arbitrary + r3 <- arbitrary + return (Semver r1 r2 r3 "" "") + +-- properties +-- a version always satisfies itself +prop_satisfies :: Property +prop_satisfies = + property $ + \s -> satisfies s s + +-- a version is always less than its next {major, minor, patch} version +prop_lessThanNext :: (Semver -> Semver) -> Property +prop_lessThanNext f = + property $ + \s -> let s' = f s in s `lessThan` s' + +prop_lessThanNextMajor :: Property +prop_lessThanNextMajor = prop_lessThanNext nextMajor + +prop_lessThanNextMinor :: Property +prop_lessThanNextMinor = prop_lessThanNext nextMinor + +prop_lessThanNextPatch :: Property +prop_lessThanNextPatch = prop_lessThanNext nextPatch + +-- drive quickcheck +main :: IO () +main = do + args <- getArgs + (o, _) <- parseOpts args + let numCheck = quickCheckWith stdArgs { maxSuccess = optNumTests o } + checker = if optVerbose o + then numCheck . verbose + else numCheck + in do checker prop_satisfies + checker prop_lessThanNextMajor + checker prop_lessThanNextMinor + checker prop_lessThanNextPatch diff --git a/external/semver/src/quickcheck/Main.o b/external/semver/src/quickcheck/Main.o new file mode 100644 index 0000000..3775e7b Binary files /dev/null and b/external/semver/src/quickcheck/Main.o differ diff --git a/external/semver/src/quickcheck/Semver.hsc b/external/semver/src/quickcheck/Semver.hsc new file mode 100644 index 0000000..c96eb00 --- /dev/null +++ b/external/semver/src/quickcheck/Semver.hsc @@ -0,0 +1,87 @@ +{-# LANGUAGE ForeignFunctionInterface #-} +module Semver where + +#include "semantic_version_ffi.h" + +import Foreign hiding (unsafePerformIO) +import Foreign.C.String +import Foreign.Storable +import System.IO.Unsafe (unsafePerformIO) + +data Semver = Semver + { vMajor :: #{type unsigned int} + , vMinor :: #{type unsigned int} + , vPatch :: #{type unsigned int} + , vPrerelease :: String + , vBuild :: String + } deriving (Eq, Show) + +-- don't bother with the strings for now + +instance Storable Semver where + sizeOf _ = #{size semver_t} + alignment _ = alignment (undefined :: Word32) + + peek ptr = do + r1 <- #{peek semver_t, major} ptr + r2 <- #{peek semver_t, minor} ptr + r3 <- #{peek semver_t, patch} ptr + return (Semver r1 r2 r3 "" "") + + poke ptr (Semver r1 r2 r3 _ _) = do + #{poke semver_t, major} ptr r1 + #{poke semver_t, minor} ptr r2 + #{poke semver_t, patch} ptr r3 + +-- c functions + +foreign import ccall "semantic_version_ffi.h satisfies" + c_satisfies :: Ptr Semver -> Ptr Semver -> IO Int +foreign import ccall "semantic_version_ffi.h lessThan" + c_lessThan :: Ptr Semver -> Ptr Semver -> IO Int +foreign import ccall "semantic_version_ffi.h nextMajor" + c_nextMajor :: Ptr Semver -> Ptr Semver -> IO () +foreign import ccall "semantic_version_ffi.h nextMinor" + c_nextMinor :: Ptr Semver -> Ptr Semver -> IO () +foreign import ccall "semantic_version_ffi.h nextPatch" + c_nextPatch :: Ptr Semver -> Ptr Semver -> IO () + +-- haskell wrappers + +satisfies :: Semver -> Semver -> Bool +satisfies a b = + unsafePerformIO $ + alloca $ \a_ptr -> + alloca $ \b_ptr -> do + poke a_ptr a + poke b_ptr b + r <- c_satisfies a_ptr b_ptr + return $ if (r == 1) then True else False + +lessThan :: Semver -> Semver -> Bool +lessThan a b = + unsafePerformIO $ + alloca $ \a_ptr -> + alloca $ \b_ptr -> do + poke a_ptr a + poke b_ptr b + r <- c_lessThan a_ptr b_ptr + return $ if (r == 1) then True else False + +nextFunc :: (Ptr Semver -> Ptr Semver -> IO ()) -> Semver -> Semver +nextFunc f a = + unsafePerformIO $ + alloca $ \a_ptr -> + alloca $ \b_ptr -> do + poke a_ptr a + f a_ptr b_ptr + peek b_ptr + +nextMajor :: Semver -> Semver +nextMajor = nextFunc c_nextMajor + +nextMinor :: Semver -> Semver +nextMinor = nextFunc c_nextMinor + +nextPatch :: Semver -> Semver +nextPatch = nextFunc c_nextPatch diff --git a/external/semver/src/quickcheck/semantic_version_ffi.cpp b/external/semver/src/quickcheck/semantic_version_ffi.cpp new file mode 100644 index 0000000..3c7d8fc --- /dev/null +++ b/external/semver/src/quickcheck/semantic_version_ffi.cpp @@ -0,0 +1,58 @@ +#include "semantic_version_ffi.h" +#include "semantic_version.h" + +using namespace semver; + +//------------------------------------------------------------------------------ + +int satisfies(const semver_t* a, const semver_t* b) +{ + Version va(a->major, a->minor, a->patch, + a->prerelease, a->build); + + Version vb(b->major, b->minor, b->patch, + b->prerelease, b->build); + + return va.Satisfies(vb) ? 1 : 0; +} + +int lessThan(const semver_t* a, const semver_t* b) +{ + Version va(a->major, a->minor, a->patch, + a->prerelease, a->build); + + Version vb(b->major, b->minor, b->patch, + b->prerelease, b->build); + + return (va < vb) ? 1 : 0; +} + +void nextMajor(const semver_t* a, semver_t* b) +{ + Version va(a->major, a->minor, a->patch, + a->prerelease, a->build); + Version vb = va.NextMajorVersion(); + b->major = vb.GetMajorVersion(); + b->minor = vb.GetMinorVersion(); + b->patch = vb.GetPatchVersion(); +} + +void nextMinor(const semver_t* a, semver_t* b) +{ + Version va(a->major, a->minor, a->patch, + a->prerelease, a->build); + Version vb = va.NextMinorVersion(); + b->major = vb.GetMajorVersion(); + b->minor = vb.GetMinorVersion(); + b->patch = vb.GetPatchVersion(); +} + +void nextPatch(const semver_t* a, semver_t* b) +{ + Version va(a->major, a->minor, a->patch, + a->prerelease, a->build); + Version vb = va.NextPatchVersion(); + b->major = vb.GetMajorVersion(); + b->minor = vb.GetMinorVersion(); + b->patch = vb.GetPatchVersion(); +} diff --git a/external/semver/src/quickcheck/semantic_version_ffi.h b/external/semver/src/quickcheck/semantic_version_ffi.h new file mode 100644 index 0000000..5a734af --- /dev/null +++ b/external/semver/src/quickcheck/semantic_version_ffi.h @@ -0,0 +1,27 @@ +#pragma once + +// FFI for semantic version + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct Semver +{ + unsigned int major; + unsigned int minor; + unsigned int patch; + char prerelease[32]; + char build[32]; +} semver_t; + +int satisfies(const semver_t* a, const semver_t* b); +int lessThan(const semver_t* a, const semver_t* b); +void nextMajor(const semver_t* a, semver_t* b); +void nextMinor(const semver_t* a, semver_t* b); +void nextPatch(const semver_t* a, semver_t* b); + +#ifdef __cplusplus +} +#endif diff --git a/external/semver/src/test/CMakeLists.txt b/external/semver/src/test/CMakeLists.txt new file mode 100644 index 0000000..ea04671 --- /dev/null +++ b/external/semver/src/test/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable (test_${PROJECT_NAME} main.cpp) +target_link_libraries(test_${PROJECT_NAME} ${PROJECT_NAME}) +ADD_TESTINATOR_TESTS (test_${PROJECT_NAME}) diff --git a/external/semver/src/test/main.cpp b/external/semver/src/test/main.cpp new file mode 100644 index 0000000..47a48c5 --- /dev/null +++ b/external/semver/src/test/main.cpp @@ -0,0 +1,297 @@ +#include + +using namespace semver; + +#define TESTINATOR_MAIN +#include + +#include +#include + +using namespace std; + +DEF_TEST(Init, SemanticVersion) +{ + Version v; + return v.GetMajorVersion() == 0 + && v.GetMinorVersion() == 0 + && v.GetPatchVersion() == 1; +} + +DEF_TEST(NextMajor, SemanticVersion) +{ + Version v1(1, 2, 3); + Version v2(v1.NextMajorVersion()); + return v2.GetMajorVersion() == 2 + && v2.GetMinorVersion() == 0 + && v2.GetPatchVersion() == 0; +} + +DEF_TEST(NextMinor, SemanticVersion) +{ + Version v1(1, 2, 3); + Version v2(v1.NextMinorVersion()); + return v2.GetMajorVersion() == 1 + && v2.GetMinorVersion() == 3 + && v2.GetPatchVersion() == 0; +} + +DEF_TEST(NextPatch, SemanticVersion) +{ + Version v1(1, 2, 3); + Version v2(v1.NextPatchVersion()); + return v2.GetMajorVersion() == 1 + && v2.GetMinorVersion() == 2 + && v2.GetPatchVersion() == 4; +} + +DEF_TEST(LessThanMajor, SemanticVersion) +{ + Version v1(1, 2, 3); + Version v2(v1.NextMajorVersion()); + return v1 < v2; +} + +DEF_TEST(LessThanMinor, SemanticVersion) +{ + Version v1(1, 2, 3); + Version v2(v1.NextMinorVersion()); + return v1 < v2; +} + +DEF_TEST(LessThanPatch, SemanticVersion) +{ + Version v1(1, 2, 3); + Version v2(v1.NextPatchVersion()); + return v1 < v2; +} + +DEF_TEST(LessThanNumericString, SemanticVersion) +{ + Version v1(1, 2, 3, "alpha.2"); + Version v2(1, 2, 3, "alpha.11"); + return v1 < v2; +} + +DEF_TEST(LessThanPrerelease, SemanticVersion) +{ + Version v1(1, 2, 3, "alpha"); + Version v2(1, 2, 3, "beta"); + return v1 < v2; +} + +DEF_TEST(LessThanBuild, SemanticVersion) +{ + Version v1(1, 2, 3, "", "1"); + Version v2(1, 2, 3, "", "2"); + return v1 < v2; +} + +DEF_TEST(PrereleaseLessThanNormal, SemanticVersion) +{ + Version v1(1, 2, 3, "alpha"); + Version v2(1, 2, 3); + return v1 < v2; +} + +DEF_TEST(NormalLessThanBuild, SemanticVersion) +{ + Version v1(1, 2, 3); + Version v2(1, 2, 3, "", "1"); + return v1 < v2; +} + +DEF_TEST(PrereleaseLessThanBuild, SemanticVersion) +{ + Version v1(1, 2, 3, "alpha"); + Version v2(1, 2, 3, "", "1234"); + return v1 < v2; +} + +DEF_TEST(Output, SemanticVersion) +{ + Version v(1, 2, 3, "alpha.2", "1234"); + ostringstream s; + s << v; + return s.str() == "1.2.3-alpha.2+1234"; +} + +DEF_TEST(SameSatisfy, SemanticVersion) +{ + Version v1(1, 2, 3); + Version v2(1, 2, 3); + return v1.Satisfies(v2); +} + +DEF_TEST(GreaterMajorSatisfy, SemanticVersion) +{ + Version v1(2, 0, 0); + Version v2(1, 2, 3); + return v1.Satisfies(v2); +} + +DEF_TEST(GreaterMinorSatisfy, SemanticVersion) +{ + Version v1(1, 3, 0); + Version v2(1, 2, 3); + return v1.Satisfies(v2); +} + +DEF_TEST(GreaterPatchSatisfy, SemanticVersion) +{ + Version v1(1, 2, 4); + Version v2(1, 2, 3); + return v1.Satisfies(v2); +} + +DEF_TEST(PrereleaseSatisfy, SemanticVersion) +{ + Version v1(1, 2, 3, "alpha"); + Version v2(1, 2, 3); + return v1.Satisfies(v2); +} + +DEF_TEST(BuildSatisfy, SemanticVersion) +{ + Version v1(1, 2, 3, "", "1234"); + Version v2(1, 2, 3); + return v1.Satisfies(v2); +} + +const vector s_precedences_v1 = +{ + semver::v1::Version(1, 0, 0, "alpha"), + semver::v1::Version(1, 0, 0, "alpha.1"), + semver::v1::Version(1, 0, 0, "alpha.beta"), + semver::v1::Version(1, 0, 0, "beta"), + semver::v1::Version(1, 0, 0, "beta.2"), + semver::v1::Version(1, 0, 0, "beta.11"), + semver::v1::Version(1, 0, 0, "rc.1"), + semver::v1::Version(1, 0, 0, "rc.1", "build.1"), + semver::v1::Version(1, 0, 0), + semver::v1::Version(1, 0, 0, "", "0.3.7"), + semver::v1::Version(1, 0, 0, "", "build"), + semver::v1::Version(1, 0, 0, "", "build.2.b8f12d7"), + semver::v1::Version(1, 0, 0, "", "build.11.e0f985a") +}; + +DEF_TEST(Precedences_v1, SemanticVersion) +{ + return adjacent_find( + s_precedences_v1.cbegin(), s_precedences_v1.cend(), + [] (const auto& a, const auto& b) { return a >= b; }) + == s_precedences_v1.end(); +} + +DEF_TEST(Satisfies_v1, SemanticVersion) +{ + return adjacent_find( + s_precedences_v1.cbegin(), s_precedences_v1.cend(), + [] (const auto& a, const auto& b) { return !b.Satisfies(a) ; }) + == s_precedences_v1.end(); +} + +const vector s_precedences_v2 = +{ + semver::v2::Version(1, 0, 0, "alpha"), + semver::v2::Version(1, 0, 0, "alpha.1"), + semver::v2::Version(1, 0, 0, "alpha.beta"), + semver::v2::Version(1, 0, 0, "beta"), + semver::v2::Version(1, 0, 0, "beta.2"), + semver::v2::Version(1, 0, 0, "beta.11"), + semver::v2::Version(1, 0, 0, "rc.1"), + semver::v2::Version(1, 0, 0) +}; + +DEF_TEST(Precedences_v2, SemanticVersion) +{ + return adjacent_find( + s_precedences_v2.cbegin(), s_precedences_v2.cend(), + [] (const auto& a, const auto& b) { return a >= b; }) + == s_precedences_v2.end(); +} + +DEF_TEST(Satisfies_v2, SemanticVersion) +{ + return adjacent_find( + s_precedences_v2.cbegin(), s_precedences_v2.cend(), + [] (const auto& a, const auto& b) { return !b.Satisfies(a) ; }) + == s_precedences_v2.end(); +} + +DEF_TEST(PrecedenceIncludesBuild_v1, SemanticVersion) +{ + semver::v1::Version a(1,0,0, "", "1"); + semver::v1::Version b(1,0,0, "", "2"); + return a < b; +} + +DEF_TEST(PrecedenceOmitsBuild_v2, SemanticVersion) +{ + semver::v2::Version a(1,0,0, "", "1"); + semver::v2::Version b(1,0,0, "", "2"); + return a == b; +} + +DEF_TEST(ConstructFromString, SemanticVersion) +{ + Version v("1.2.3-alpha.2+build.1234"); + ostringstream s; + s << v; + return s.str() == "1.2.3-alpha.2+build.1234"; +} + +DEF_TEST(WellFormed, SemanticVersion) +{ + Version v("1.2.3-alpha.2+build.1234"); + return v.IsWellFormed(); +} + +DEF_TEST(ParseIllFormed, SemanticVersion) +{ + Version v("1.2.3-alpha-2+build+1234"); + return !v.IsWellFormed(); +} + +namespace testinator +{ + template <> + struct Arbitrary + { + using Version = semver::v2::Version; + + static Version generate(std::size_t g, unsigned long int s) + { + // prerelease part shouldn't contain a + + string pre = Arbitrary::generate(g, s); + replace(pre.begin(), pre.end(), '+', '_'); + + return Version { + Arbitrary::generate(g, s), + Arbitrary::generate(g, s>>1), + Arbitrary::generate(g, s>>2), + pre, + Arbitrary::generate(g, s>>1) + }; + } + static vector shrink(const Version&) + { + return vector{}; + } + }; +} + +DEF_PROPERTY(Roundtrip, SemanticVersion, const semver::v2::Version& before) +{ + ostringstream s; + s << before; + Version after(s.str()); + return after.Equals(before); +} + +DEF_TEST(LessThan_Issue2, SemanticVersion) +{ + Version a("4.5.6"); + Version b("1.2.3"); + return !(a < b); +} -- cgit