mirror of
https://gitlab.com/square-game-liberation-front/F.E.I.S.git
synced 2025-02-28 07:20:26 +01:00
Tests with rapidcheck !
This commit is contained in:
parent
f5d6199f27
commit
be1eeaf21e
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
In other words, how to create a new F.E.I.S. executable from the source code.
|
In other words, how to create a new F.E.I.S. executable from the source code.
|
||||||
|
|
||||||
0. (If not done already) Set up you work environment by following [this page](docs/Setup.md)
|
0. (If not done already) Set up you work environment by following
|
||||||
|
[the Setup Steps](docs/Setup.md)
|
||||||
0. `cd` into the root of your local copy of F.E.I.S.'s source code
|
0. `cd` into the root of your local copy of F.E.I.S.'s source code
|
||||||
|
|
||||||
```console
|
```console
|
||||||
@ -15,6 +16,13 @@ In other words, how to create a new F.E.I.S. executable from the source code.
|
|||||||
$ meson setup build
|
$ meson setup build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you want to compile the unit tests as well, pass in `-D tests=true`.
|
||||||
|
You can also set this option later by doing :
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ meson configure build -D tests=true
|
||||||
|
```
|
||||||
|
|
||||||
0. Compile in that directory
|
0. Compile in that directory
|
||||||
|
|
||||||
```console
|
```console
|
||||||
|
@ -17,7 +17,8 @@ get a more up-to-date version than what your distro packages might have
|
|||||||
$ pip install meson
|
$ pip install meson
|
||||||
```
|
```
|
||||||
|
|
||||||
Unfortunately this also means meson will not come with ninja so we need to install it ourselves :
|
Unfortunately this also means meson will not come with ninja so we need to
|
||||||
|
install it ourselves :
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ sudo apt install ninja-build
|
$ sudo apt install ninja-build
|
||||||
@ -46,9 +47,9 @@ $ sudo apt install clang-format
|
|||||||
#### MSYS2
|
#### MSYS2
|
||||||
|
|
||||||
MSYS2 is not the *usual* way to compile things for windows but it's the only
|
MSYS2 is not the *usual* way to compile things for windows but it's the only
|
||||||
thing I know for now. If you know better, you're very welcome to do better
|
thing I know for now. If you know better, by all means, do what you think is
|
||||||
(and to also shower me with some of your knowledge, I absolutely *suck* at
|
best (and also please share some of your knowledge with me, I absolutely *suck*
|
||||||
build systems and would be delighted to hear from you)
|
at build systems and would be delighted to learn from an expert)
|
||||||
|
|
||||||
Installing MSYS2 is pretty simple. [Follow their instructions](https://www.msys2.org/)
|
Installing MSYS2 is pretty simple. [Follow their instructions](https://www.msys2.org/)
|
||||||
|
|
||||||
@ -65,4 +66,4 @@ $ pacman -S \
|
|||||||
```
|
```
|
||||||
|
|
||||||
Once this is done, open a new `MSYS2 MinGW x64` terminal and follow the
|
Once this is done, open a new `MSYS2 MinGW x64` terminal and follow the
|
||||||
[instructions on how to compile](docs/Compiling.md)
|
[compilation instructions](docs/Compiling.md)
|
||||||
|
6
meson_options.txt
Normal file
6
meson_options.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
option(
|
||||||
|
'tests',
|
||||||
|
type: 'boolean',
|
||||||
|
value: false,
|
||||||
|
description: 'Build F.E.I.S\'s unit tests'
|
||||||
|
)
|
@ -15,7 +15,7 @@ bool is_expressible_as_240th(const Fraction& beat) {
|
|||||||
nlohmann::ordered_json beat_to_best_form(const Fraction& beat) {
|
nlohmann::ordered_json beat_to_best_form(const Fraction& beat) {
|
||||||
if (is_expressible_as_240th(beat)) {
|
if (is_expressible_as_240th(beat)) {
|
||||||
return nlohmann::ordered_json(
|
return nlohmann::ordered_json(
|
||||||
(240 * convert_to_u64(beat.numerator()) / convert_to_u64(beat.denominator())
|
(240 * convert_to_u64(beat.numerator())) / convert_to_u64(beat.denominator())
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return beat_to_fraction_tuple(beat);
|
return beat_to_fraction_tuple(beat);
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include "better_beats.hpp"
|
#include "better_beats.hpp"
|
||||||
|
|
||||||
namespace better {
|
namespace better {
|
||||||
@ -14,10 +16,10 @@ namespace better {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Position::Position(std::uint64_t x, std::uint64_t y) : x(x), y(y) {
|
Position::Position(std::uint64_t x, std::uint64_t y) : x(x), y(y) {
|
||||||
if (x > 3 or y > 3) {
|
if (x > 3 or y > 2) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Attempted to create Position from invalid coordinates : ";
|
ss << "Attempted to create Position from invalid coordinates : ";
|
||||||
ss << this;
|
ss << *this;
|
||||||
throw std::invalid_argument(ss.str());
|
throw std::invalid_argument(ss.str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -35,7 +37,7 @@ namespace better {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<< (std::ostream& out, const Position& pos) {
|
std::ostream& operator<< (std::ostream& out, const Position& pos) {
|
||||||
out << "(x: " << pos.get_x() << ", y: " << pos.get_y() << ")";
|
out << fmt::format("(x: {}, y: {})", pos.x, pos.y);
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ namespace better {
|
|||||||
if (duration < 0) {
|
if (duration < 0) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Attempted to create a LongNote with negative duration : ";
|
ss << "Attempted to create a LongNote with negative duration : ";
|
||||||
ss << duration.get_str();
|
ss << duration;
|
||||||
throw std::invalid_argument(ss.str());
|
throw std::invalid_argument(ss.str());
|
||||||
}
|
}
|
||||||
if (tail_tip == position) {
|
if (tail_tip == position) {
|
||||||
@ -232,7 +234,7 @@ namespace better {
|
|||||||
return std::visit([](const auto& n){return n.dump_to_memon_1_0_0();}, this->note);
|
return std::visit([](const auto& n){return n.dump_to_memon_1_0_0();}, this->note);
|
||||||
}
|
}
|
||||||
|
|
||||||
Note Note::load_from_memon_0_1_0(const nlohmann::json& json, std::uint64_t resolution) {
|
Note Note::load_from_memon_1_0_0(const nlohmann::json& json, std::uint64_t resolution) {
|
||||||
const auto position = Position{json["n"].get<std::uint64_t>()};
|
const auto position = Position{json["n"].get<std::uint64_t>()};
|
||||||
const auto time = load_memon_1_0_0_beat(json["t"], resolution);
|
const auto time = load_memon_1_0_0_beat(json["t"], resolution);
|
||||||
if (not json.contains("l")) {
|
if (not json.contains("l")) {
|
||||||
|
@ -32,14 +32,13 @@ namespace better {
|
|||||||
std::uint64_t get_y() const;
|
std::uint64_t get_y() const;
|
||||||
|
|
||||||
auto operator<=>(const Position&) const = default;
|
auto operator<=>(const Position&) const = default;
|
||||||
|
friend std::ostream& operator<<(std::ostream& out, const Position& pos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::uint64_t x;
|
std::uint64_t x;
|
||||||
std::uint64_t y;
|
std::uint64_t y;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, const Position& pos);
|
|
||||||
|
|
||||||
class TapNote {
|
class TapNote {
|
||||||
public:
|
public:
|
||||||
TapNote(Fraction time, Position position);
|
TapNote(Fraction time, Position position);
|
||||||
@ -96,9 +95,9 @@ namespace better {
|
|||||||
|
|
||||||
nlohmann::ordered_json dump_to_memon_1_0_0() const;
|
nlohmann::ordered_json dump_to_memon_1_0_0() const;
|
||||||
|
|
||||||
static Note load_from_memon_0_1_0(
|
static Note load_from_memon_1_0_0(
|
||||||
const nlohmann::json& json,
|
const nlohmann::json& json,
|
||||||
std::uint64_t resolution
|
std::uint64_t resolution = 240
|
||||||
);
|
);
|
||||||
|
|
||||||
static Note load_from_memon_legacy(
|
static Note load_from_memon_legacy(
|
||||||
|
@ -32,4 +32,6 @@ sources += files(
|
|||||||
|
|
||||||
subdir('widgets')
|
subdir('widgets')
|
||||||
|
|
||||||
subdir('tests')
|
if get_option('tests')
|
||||||
|
subdir('tests')
|
||||||
|
endif
|
83
src/tests/rapidcheck/generators.hpp
Normal file
83
src/tests/rapidcheck/generators.hpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include <rapidcheck.h>
|
||||||
|
|
||||||
|
#include "../../better_note.hpp"
|
||||||
|
#include "../../special_numeric_types.hpp"
|
||||||
|
#include "rapidcheck/gen/Arbitrary.h"
|
||||||
|
#include "rapidcheck/gen/Numeric.h"
|
||||||
|
|
||||||
|
namespace rc {
|
||||||
|
template<>
|
||||||
|
struct Arbitrary<better::Position> {
|
||||||
|
static Gen<better::Position> arbitrary() {
|
||||||
|
return gen::construct<better::Position>(
|
||||||
|
gen::inRange<unsigned int>(0, 16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Arbitrary<Fraction> {
|
||||||
|
static Gen<Fraction> arbitrary() {
|
||||||
|
return gen::apply([](const Fraction& a, const Fraction& b) {
|
||||||
|
return a + b;
|
||||||
|
},
|
||||||
|
gen::cast<Fraction>(
|
||||||
|
gen::nonNegative<unsigned>()
|
||||||
|
),
|
||||||
|
gen::construct<Fraction>(
|
||||||
|
gen::nonNegative<unsigned>(),
|
||||||
|
gen::positive<unsigned>()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Gen<Fraction> positive() {
|
||||||
|
return gen::apply([](const Fraction& a, const Fraction& b) {
|
||||||
|
return a + b;
|
||||||
|
},
|
||||||
|
gen::cast<Fraction>(
|
||||||
|
gen::nonNegative<unsigned>()
|
||||||
|
),
|
||||||
|
gen::construct<Fraction>(
|
||||||
|
gen::positive<unsigned>(),
|
||||||
|
gen::positive<unsigned>()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Arbitrary<better::TapNote> {
|
||||||
|
static Gen<better::TapNote> arbitrary() {
|
||||||
|
return gen::construct<better::TapNote>(
|
||||||
|
gen::arbitrary<Fraction>(),
|
||||||
|
gen::arbitrary<better::Position>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Arbitrary<better::LongNote> {
|
||||||
|
static Gen<better::LongNote> arbitrary() {
|
||||||
|
const auto pos = *gen::arbitrary<better::Position>();
|
||||||
|
const auto tail_6_notation = *gen::inRange<unsigned int>(0, 6);
|
||||||
|
const auto tail_pos = better::convert_6_notation_to_position(pos, tail_6_notation);
|
||||||
|
return gen::construct<better::LongNote>(
|
||||||
|
gen::arbitrary<Fraction>(),
|
||||||
|
gen::just(pos),
|
||||||
|
gen::positive<Fraction>(),
|
||||||
|
gen::just(tail_pos)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Arbitrary<better::Note> {
|
||||||
|
static Gen<better::Note> arbitrary() {
|
||||||
|
return gen::oneOf(
|
||||||
|
gen::construct<better::Note>(gen::arbitrary<better::TapNote>()),
|
||||||
|
gen::construct<better::Note>(gen::arbitrary<better::LongNote>())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
17
src/tests/rapidcheck/main.cpp
Normal file
17
src/tests/rapidcheck/main.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <rapidcheck.h>
|
||||||
|
|
||||||
|
#include "generators.hpp"
|
||||||
|
|
||||||
|
#include "../../better_note.hpp"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
rc::check(
|
||||||
|
"Notes survive being converted to json and back",
|
||||||
|
[](const better::Note& n) {
|
||||||
|
const auto j = n.dump_to_memon_1_0_0();
|
||||||
|
const auto n_recovered = better::Note::load_from_memon_1_0_0(j);
|
||||||
|
RC_ASSERT(n_recovered == n);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
rapidcheck_tests = executable(
|
rapidcheck_tests = executable(
|
||||||
'rapidcheck_tests',
|
'rapidcheck_tests',
|
||||||
'rapidcheck_main.cpp',
|
'main.cpp',
|
||||||
'test_fractions.cpp',
|
'../../better_note.cpp',
|
||||||
|
'../../better_beats.cpp',
|
||||||
'../../special_numeric_types.cpp',
|
'../../special_numeric_types.cpp',
|
||||||
include_sources['fmt'],
|
include_sources['fmt'],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#include <rapidcheck.h>
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
71
subprojects/packagefiles/rapidcheck/meson.build
Normal file
71
subprojects/packagefiles/rapidcheck/meson.build
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
project(
|
||||||
|
'rapidcheck',
|
||||||
|
'cpp',
|
||||||
|
version: '0.1.0',
|
||||||
|
license: 'BSD-2-Clause',
|
||||||
|
default_options : [
|
||||||
|
'cpp_std=c++11',
|
||||||
|
'warning_level=3',
|
||||||
|
],
|
||||||
|
meson_version : '>=0.62.0',
|
||||||
|
)
|
||||||
|
|
||||||
|
sources = []
|
||||||
|
|
||||||
|
subdir('src') # fills in 'sources'
|
||||||
|
|
||||||
|
includes = include_directories('include')
|
||||||
|
|
||||||
|
add_project_arguments(
|
||||||
|
'-Wno-missing-braces',
|
||||||
|
'-Wno-unused-command-line-argument',
|
||||||
|
language: 'cpp'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Random is used a LOT so it should preferably be really fast
|
||||||
|
rapidcheck_random_lib = static_library(
|
||||||
|
'rapidcheck_random',
|
||||||
|
'src/Random.cpp',
|
||||||
|
include_directories: includes,
|
||||||
|
cpp_args: '-O3',
|
||||||
|
)
|
||||||
|
|
||||||
|
# On Windows under MinGW, random_device provides no entropy,
|
||||||
|
# so it will always return the same value.
|
||||||
|
# Seed using system time instead.
|
||||||
|
# See: https://stackoverflow.com/questions/18880654/why-do-i-get-the-same-sequence-for-every-run-with-stdrandom-device-with-mingw
|
||||||
|
if host_machine.system() == 'cygwin'
|
||||||
|
add_project_arguments('-DRC_SEED_SYSTEM_TIME', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if not get_option('rtti')
|
||||||
|
add_project_arguments('-DRC_DONT_USE_RTTI', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
|
# if get_option('tests')
|
||||||
|
# subdir('ext')
|
||||||
|
# subdir('test')
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if get_option('examples')
|
||||||
|
# ... more unfun stuff
|
||||||
|
# endif
|
||||||
|
|
||||||
|
rapidcheck_lib = static_library(
|
||||||
|
'rapidcheck',
|
||||||
|
sources,
|
||||||
|
include_directories: includes,
|
||||||
|
link_with: rapidcheck_random_lib,
|
||||||
|
cpp_args: [
|
||||||
|
'-Wall',
|
||||||
|
'-Wno-missing-braces',
|
||||||
|
'-Wno-unused-command-line-argument',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
rapidcheck_dep = declare_dependency(
|
||||||
|
include_directories: includes,
|
||||||
|
link_with: rapidcheck_lib,
|
||||||
|
)
|
||||||
|
|
||||||
|
meson.override_dependency('rapidcheck', rapidcheck_dep)
|
20
subprojects/packagefiles/rapidcheck/meson_options.txt
Normal file
20
subprojects/packagefiles/rapidcheck/meson_options.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
option(
|
||||||
|
'rtti',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true,
|
||||||
|
description: 'Build RapidCheck with Run-Time Type Inspection'
|
||||||
|
)
|
||||||
|
|
||||||
|
# option(
|
||||||
|
# 'tests',
|
||||||
|
# type: 'boolean',
|
||||||
|
# value: false,
|
||||||
|
# description: 'Build RapidCheck tests'
|
||||||
|
# )
|
||||||
|
|
||||||
|
# option(
|
||||||
|
# 'examples',
|
||||||
|
# type: 'boolean',
|
||||||
|
# value: true,
|
||||||
|
# description: 'Build RapidCheck examples'
|
||||||
|
# )
|
23
subprojects/packagefiles/rapidcheck/src/detail/meson.build
Normal file
23
subprojects/packagefiles/rapidcheck/src/detail/meson.build
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
sources += files(
|
||||||
|
'Any.cpp',
|
||||||
|
'Assertions.cpp',
|
||||||
|
'Base64.cpp',
|
||||||
|
'Configuration.cpp',
|
||||||
|
'DefaultTestListener.cpp',
|
||||||
|
'FrequencyMap.cpp',
|
||||||
|
'ImplicitParam.cpp',
|
||||||
|
'LogTestListener.cpp',
|
||||||
|
'MapParser.cpp',
|
||||||
|
'MulticastTestListener.cpp',
|
||||||
|
'ParseException.cpp',
|
||||||
|
'Platform.cpp',
|
||||||
|
'Property.cpp',
|
||||||
|
'PropertyContext.cpp',
|
||||||
|
'ReproduceListener.cpp',
|
||||||
|
'Results.cpp',
|
||||||
|
'Serialization.cpp',
|
||||||
|
'StringSerialization.cpp',
|
||||||
|
'TestMetadata.cpp',
|
||||||
|
'TestParams.cpp',
|
||||||
|
'Testing.cpp',
|
||||||
|
)
|
@ -0,0 +1,6 @@
|
|||||||
|
sources += files(
|
||||||
|
'ExecHandler.cpp',
|
||||||
|
'GenerationHandler.cpp',
|
||||||
|
'Recipe.cpp',
|
||||||
|
'ScaleInteger.cpp',
|
||||||
|
)
|
6
subprojects/packagefiles/rapidcheck/src/gen/meson.build
Normal file
6
subprojects/packagefiles/rapidcheck/src/gen/meson.build
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
sources += files(
|
||||||
|
'Numeric.cpp',
|
||||||
|
'Text.cpp',
|
||||||
|
)
|
||||||
|
|
||||||
|
subdir('detail')
|
13
subprojects/packagefiles/rapidcheck/src/meson.build
Normal file
13
subprojects/packagefiles/rapidcheck/src/meson.build
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
sources += files(
|
||||||
|
'BeforeMinimalTestCase.cpp',
|
||||||
|
'Check.cpp',
|
||||||
|
'Classify.cpp',
|
||||||
|
'GenerationFailure.cpp',
|
||||||
|
'Log.cpp',
|
||||||
|
# Leave this one out because it needs to be compiled spearately
|
||||||
|
# 'Random.cpp',
|
||||||
|
'Show.cpp',
|
||||||
|
)
|
||||||
|
|
||||||
|
subdir('detail')
|
||||||
|
subdir('gen')
|
24
utils/save_meson_wrap.py
Normal file
24
utils/save_meson_wrap.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
"""implement the missing --save option of meson subprojects packagefiles
|
||||||
|
for wrap-git packages"""
|
||||||
|
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from path import Path
|
||||||
|
|
||||||
|
parser = ArgumentParser()
|
||||||
|
parser.add_argument("wrap", type=Path)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
subprojects = Path("subprojects")
|
||||||
|
if not subprojects.exists():
|
||||||
|
print(f"{subprojects} folder doesn't exist, are you in the right directory ?")
|
||||||
|
|
||||||
|
subproject = subprojects / args.wrap
|
||||||
|
patch = subprojects / "packagefiles" / args.wrap
|
||||||
|
if not patch.exists():
|
||||||
|
print(f"subproject folder doesn't exist ({subproject}), is the name correct ?")
|
||||||
|
|
||||||
|
for absolute in subproject.walkfiles("*meson*"):
|
||||||
|
relative = absolute.relpath(subproject)
|
||||||
|
(patch / relative).parent.makedirs_p()
|
||||||
|
absolute.copy(patch / relative)
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user