+74
-227
@@ -16,7 +16,6 @@
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/asio/co_spawn.hpp>
|
||||
@@ -27,8 +26,6 @@
|
||||
#include <boost/json/serialize.hpp>
|
||||
#include <boost/json/array.hpp>
|
||||
|
||||
#include <noto.hpp>
|
||||
|
||||
#include <vamp_protocol/page_control.hpp>
|
||||
#include <vamp_zero/config.hpp>
|
||||
#include <vamp_pico/http_client.hpp>
|
||||
@@ -42,7 +39,6 @@
|
||||
#include <vamp_zero/score.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
#include "catalog_fixture.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -52,47 +48,6 @@ auto test_database_config(std::filesystem::path const &path) -> vamp_zero::datab
|
||||
};
|
||||
}
|
||||
|
||||
auto query_database(std::filesystem::path const &path,
|
||||
std::string sql,
|
||||
std::vector<noto::sqlite_value> params = {}) -> std::expected<noto::query_result, modulus::error> {
|
||||
auto io = boost::asio::io_context{};
|
||||
auto future = boost::asio::co_spawn(
|
||||
io,
|
||||
[executor = io.get_executor(), path = path.string(), sql = std::move(sql), params = std::move(params)]() mutable
|
||||
-> boost::asio::awaitable<std::expected<noto::query_result, modulus::error>> {
|
||||
auto config = noto::file_connection_config(path, "product-vamp-test");
|
||||
config.foreign_keys = true;
|
||||
auto connection = noto::connection{executor, std::move(config)};
|
||||
auto connected = co_await connection.async_connect();
|
||||
if (!connected) {
|
||||
co_return std::unexpected(connected.error());
|
||||
}
|
||||
auto selected = co_await connection.async_execute(std::move(sql), std::move(params));
|
||||
auto closed = co_await connection.async_close();
|
||||
if (!selected) {
|
||||
co_return std::unexpected(selected.error());
|
||||
}
|
||||
if (!closed) {
|
||||
co_return std::unexpected(closed.error());
|
||||
}
|
||||
co_return selected;
|
||||
},
|
||||
boost::asio::use_future);
|
||||
io.run();
|
||||
return future.get();
|
||||
}
|
||||
|
||||
auto text_value(noto::sqlite_value const &value) -> std::string {
|
||||
auto text = std::get_if<std::string>(&value.value);
|
||||
return text == nullptr ? std::string{} : *text;
|
||||
}
|
||||
|
||||
auto has_value(noto::query_result const &result, std::size_t column, std::string_view expected) -> std::bool_t {
|
||||
return std::any_of(result.rows.begin(), result.rows.end(), [&](auto const &row) {
|
||||
return row.size() > column && text_value(row[column]) == expected;
|
||||
});
|
||||
}
|
||||
|
||||
auto score_asset_json(std::string title, std::string key = "C", std::string part = "Lead") -> std::string {
|
||||
auto value = boost::json::parse(R"json({
|
||||
"music":{"metadata":{"title":"Fixture","composer":"Composer","key_signature":"C","time_signature":"4/4"},
|
||||
@@ -118,38 +73,11 @@ auto navigation_state() -> vamp_zero::app_state {
|
||||
.measure_count = 1,
|
||||
.total_pages = 2,
|
||||
};
|
||||
auto practice_part = vamp_zero::library_part{
|
||||
.key_signature = "C",
|
||||
.source_path = "exercise.json",
|
||||
.measure_count = 1,
|
||||
.total_pages = 1,
|
||||
};
|
||||
auto exercise = vamp_zero::practice_exercise{
|
||||
.id = "exercise-1",
|
||||
.title = "C Major",
|
||||
.composer = "Composer",
|
||||
};
|
||||
for (auto part_name : vamp_zero::practice_part_names()) {
|
||||
practice_part.id = "exercise-" + std::string{part_name};
|
||||
practice_part.part = part_name;
|
||||
exercise.parts.push_back(practice_part);
|
||||
}
|
||||
auto practice = vamp_zero::group_practice_exercises({exercise});
|
||||
BOOST_REQUIRE(practice);
|
||||
return vamp_zero::app_state{
|
||||
.catalog = std::make_shared<vamp_zero::catalog const>(vamp_zero::catalog{
|
||||
.performance = vamp_zero::group_library_parts({part}),
|
||||
.practice = std::move(*practice),
|
||||
}),
|
||||
.catalog = std::make_shared<vamp_zero::catalog const>(vamp_zero::group_ordered_parts({part})),
|
||||
};
|
||||
}
|
||||
|
||||
void write_text(std::filesystem::path const &path, std::string const &text) {
|
||||
std::filesystem::create_directories(path.parent_path());
|
||||
auto output = std::ofstream{path, std::ios::binary | std::ios::trunc};
|
||||
output << text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(build_identification_uses_git_without_an_application_release_label) {
|
||||
@@ -230,18 +158,17 @@ BOOST_AUTO_TEST_CASE(product_vamp_audio_config_rejects_invalid_tempo_range) {
|
||||
BOOST_AUTO_TEST_CASE(main_menu_toggles_audio_settings_and_edits_tempo) {
|
||||
auto state = navigation_state();
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.selected_main_menu_index == 2U);
|
||||
BOOST_TEST(state.selected_main_menu_index == 1U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_TEST(state.audio.playback_enabled);
|
||||
BOOST_TEST(static_cast<std::int32_t>(state.mode) == static_cast<std::int32_t>(vamp_zero::app_mode::MAIN_MENU));
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.selected_main_menu_index == 3U);
|
||||
BOOST_TEST(state.selected_main_menu_index == 2U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_TEST(state.audio.metronome_enabled);
|
||||
BOOST_TEST(static_cast<std::int32_t>(state.mode) == static_cast<std::int32_t>(vamp_zero::app_mode::MAIN_MENU));
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.selected_main_menu_index == 4U);
|
||||
BOOST_TEST(state.selected_main_menu_index == 3U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_TEST(state.audio.tempo_editing);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
@@ -310,177 +237,97 @@ BOOST_AUTO_TEST_CASE(score_parser_loads_the_generated_catalog) {
|
||||
BOOST_TEST(count > 0U);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(practice_part_navigation_and_remote_display) {
|
||||
auto state = navigation_state();
|
||||
auto catalog = std::make_shared<vamp_zero::catalog>(*state.catalog);
|
||||
auto &practice_part = catalog->practice.exercises.front().parts[2];
|
||||
practice_part.source_path = "exercise-vocal.json";
|
||||
practice_part.total_pages = 3U;
|
||||
state.catalog = catalog;
|
||||
state.selected_main_menu_index = 1U;
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_EXERCISE_MENU);
|
||||
BOOST_AUTO_TEST_CASE(empty_catalog_navigation_and_main_menu_wrap) {
|
||||
auto state = vamp_zero::app_state{};
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::PREVIOUS);
|
||||
BOOST_TEST(state.selected_main_menu_index == 3U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.selected_main_menu_index == 0U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PERFORMANCE_SONG_MENU);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.selected_song_index == 0U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::MAIN_MENU);
|
||||
BOOST_REQUIRE(vamp_zero::validate_app_state(state));
|
||||
BOOST_TEST(!vamp_zero::app_status_json(state).as_object().contains("practice"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(song_part_navigation_preserves_selection_and_remote_display) {
|
||||
auto parts = std::vector<vamp_zero::library_part>{};
|
||||
for (auto name : {"Acoustic", "Electric", "Vocal"}) {
|
||||
parts.push_back({.id = name, .title = "Song", .composer = "Composer", .part = name, .total_pages = 3});
|
||||
}
|
||||
auto state = vamp_zero::app_state{
|
||||
.catalog = std::make_shared<vamp_zero::catalog const>(vamp_zero::group_ordered_parts(std::move(parts))),
|
||||
};
|
||||
state.audio.metronome_enabled = true;
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_PART_MENU);
|
||||
BOOST_TEST(vamp_zero::practice_part_row_count(state) == 4U);
|
||||
for (auto index = std::uint32_t{}; index < 3U; ++index) {
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
for (auto name : {"Acoustic", "Electric", "Vocal"}) {
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
auto selection = state.selected_part_index;
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
||||
BOOST_TEST(state.active_part_id == name);
|
||||
auto remote = vamp_pico::remote_display_state{};
|
||||
BOOST_REQUIRE(vamp_pico::parse_remote_display_body(vamp_zero::remote_display_text(state), remote));
|
||||
BOOST_TEST(remote.active);
|
||||
BOOST_TEST(std::string{remote.part} == name);
|
||||
BOOST_TEST(remote.pages == 3U);
|
||||
for (auto index = std::uint32_t{}; index < 4U; ++index) {
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
}
|
||||
BOOST_TEST(state.page_index == 2U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PERFORMANCE_PART_MENU);
|
||||
BOOST_TEST(state.selected_part_index == selection);
|
||||
BOOST_TEST(state.active_part_id.empty());
|
||||
BOOST_TEST(state.audio.metronome_enabled);
|
||||
}
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_SCORE);
|
||||
BOOST_TEST(state.audio.metronome_enabled);
|
||||
auto selected = vamp_zero::selected_practice_part(state, state.catalog->practice.exercises.front());
|
||||
BOOST_REQUIRE(selected != nullptr);
|
||||
BOOST_TEST(selected->id == "exercise-Vocal");
|
||||
BOOST_TEST(selected->source_path == "exercise-vocal.json");
|
||||
BOOST_TEST(vamp_zero::active_pages(state) == 3U);
|
||||
auto remote = vamp_pico::remote_display_state{};
|
||||
BOOST_REQUIRE(vamp_pico::parse_remote_display_body(vamp_zero::remote_display_text(state), remote));
|
||||
BOOST_TEST(remote.active);
|
||||
BOOST_TEST(std::string{remote.part} == "Vocal");
|
||||
BOOST_TEST(remote.pages == 3U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.page_index == 1U);
|
||||
auto playing = state;
|
||||
playing.audio.playback_enabled = true;
|
||||
auto control = vamp_zero::control_state{{}, playing};
|
||||
control.finish_playback(playing.score_session);
|
||||
BOOST_CHECK(control.snapshot().mode == vamp_zero::app_mode::PRACTICE_PART_MENU);
|
||||
BOOST_TEST(control.snapshot().selected_practice_part_index == 3U);
|
||||
BOOST_TEST(state.selected_part_index == 0U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_PART_MENU);
|
||||
BOOST_TEST(state.selected_practice_part_index == 3U);
|
||||
BOOST_TEST(state.active_practice_id.empty());
|
||||
for (auto index = std::uint32_t{}; index < 3U; ++index) {
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::PREVIOUS);
|
||||
}
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_EXERCISE_MENU);
|
||||
BOOST_TEST(state.selected_practice_exercise_index == 1U);
|
||||
auto status = vamp_zero::app_status_json(state).as_object().at("practice").as_object();
|
||||
BOOST_TEST(!status.contains("types"));
|
||||
BOOST_TEST(status.at("exercises").as_array().size() == 1U);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PERFORMANCE_SONG_MENU);
|
||||
BOOST_TEST(state.selected_song_index == 1U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::PREVIOUS);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::MAIN_MENU);
|
||||
BOOST_REQUIRE(vamp_zero::validate_app_state(state));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(flat_practice_wraps_and_empty_catalog_returns_to_main) {
|
||||
auto state = navigation_state();
|
||||
auto catalog = std::make_shared<vamp_zero::catalog>(*state.catalog);
|
||||
auto first = catalog->practice.exercises.front();
|
||||
for (auto index = std::uint32_t{2}; index <= 366U; ++index) {
|
||||
auto exercise = first;
|
||||
exercise.id = std::to_string(index);
|
||||
exercise.id.insert(0U, 4U - exercise.id.size(), '0');
|
||||
catalog->practice.exercises.push_back(std::move(exercise));
|
||||
}
|
||||
state.catalog = catalog;
|
||||
state.mode = vamp_zero::app_mode::PRACTICE_EXERCISE_MENU;
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::PREVIOUS);
|
||||
BOOST_TEST(state.selected_practice_exercise_index == 366U);
|
||||
BOOST_TEST(vamp_zero::selected_practice_exercise(state)->id == "0366");
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.selected_practice_exercise_index == 0U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::PREVIOUS);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_PART_MENU);
|
||||
state.catalog = vamp_zero::empty_catalog();
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_EXERCISE_MENU);
|
||||
BOOST_TEST(state.selected_practice_exercise_index == 0U);
|
||||
BOOST_REQUIRE(vamp_zero::validate_app_state(state));
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::MAIN_MENU);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(database_reload_preserves_all_generated_practice_parts) {
|
||||
auto root = std::filesystem::temp_directory_path() / ("product-vamp-parts-test-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
|
||||
auto config = test_database_config(root / "vamp.db");
|
||||
auto expected_exercises = std::size_t{};
|
||||
for (auto const &entry : std::filesystem::directory_iterator{std::filesystem::path{VAMP_TEST_SOURCE_DIR} / "data" / "practice"}) {
|
||||
BOOST_AUTO_TEST_CASE(database_reload_preserves_all_generated_song_parts) {
|
||||
auto config = test_database_config(std::filesystem::path{VAMP_TEST_ASSETS_DIR} / "catalog.db");
|
||||
auto expected = std::size_t{};
|
||||
for (auto const &entry : std::filesystem::directory_iterator{std::filesystem::path{VAMP_TEST_SOURCE_DIR} / "data/songs"}) {
|
||||
if (entry.is_regular_file() && entry.path().extension() == ".xml") {
|
||||
++expected_exercises;
|
||||
expected += 3U;
|
||||
}
|
||||
}
|
||||
BOOST_REQUIRE(expected_exercises > 0U);
|
||||
BOOST_REQUIRE(expected > 0U);
|
||||
for (auto iteration = std::uint32_t{}; iteration < 2U; ++iteration) {
|
||||
config.path = (std::filesystem::path{VAMP_TEST_ASSETS_DIR} / "catalog.db").string();
|
||||
auto io = boost::asio::io_context{};
|
||||
auto future = boost::asio::co_spawn(io, vamp_zero::async_load_practice_library(io.get_executor(), config, VAMP_TEST_ASSETS_DIR), boost::asio::use_future);
|
||||
auto future = boost::asio::co_spawn(io, vamp_zero::async_load_catalog(io.get_executor(), config, VAMP_TEST_ASSETS_DIR), boost::asio::use_future);
|
||||
io.run();
|
||||
auto library = future.get();
|
||||
BOOST_REQUIRE_MESSAGE(library.has_value(), (library ? "" : library.error().describe()));
|
||||
BOOST_TEST(library->exercises.size() == expected_exercises);
|
||||
for (auto const &exercise : library->exercises) {
|
||||
BOOST_TEST(exercise.id.size() == 4U);
|
||||
BOOST_TEST(exercise.id.find_first_not_of("0123456789") == std::string::npos);
|
||||
BOOST_REQUIRE_EQUAL(exercise.parts.size(), 3U);
|
||||
auto parts = vamp_zero::practice_part_names();
|
||||
for (auto index = std::size_t{}; index < parts.size(); ++index) {
|
||||
BOOST_TEST(exercise.parts[index].part == parts[index]);
|
||||
BOOST_TEST(exercise.parts[index].total_pages > 0U);
|
||||
BOOST_TEST(exercise.parts[index].measure_count > 0U);
|
||||
if (iteration == 0U) {
|
||||
auto const &practice_part = exercise.parts[index];
|
||||
io.restart();
|
||||
auto loaded = boost::asio::co_spawn(io, vamp_zero::async_load_score(io.get_executor(), config, {vamp_zero::score_category::PRACTICE, practice_part.id}, VAMP_TEST_ASSETS_DIR), boost::asio::use_future);
|
||||
io.run();
|
||||
auto score = loaded.get();
|
||||
BOOST_REQUIRE_MESSAGE(score, (score ? "" : score.error().describe()));
|
||||
BOOST_TEST(score->title == exercise.title);
|
||||
BOOST_TEST(score->composer == exercise.composer);
|
||||
BOOST_TEST(score->key_signature == practice_part.key_signature);
|
||||
BOOST_TEST(score->part == practice_part.part);
|
||||
BOOST_TEST(score->measure_count == practice_part.measure_count);
|
||||
BOOST_TEST(score->pages.size() == practice_part.total_pages);
|
||||
BOOST_TEST(score->source_path == practice_part.source_path);
|
||||
}
|
||||
}
|
||||
auto catalog = future.get();
|
||||
BOOST_REQUIRE_MESSAGE(catalog, (catalog ? "" : catalog.error().describe()));
|
||||
BOOST_REQUIRE_EQUAL(catalog->parts.size(), expected);
|
||||
for (auto const &part : catalog->parts) {
|
||||
io.restart();
|
||||
auto loaded = boost::asio::co_spawn(io, vamp_zero::async_load_score(io.get_executor(), config, {part.id}, VAMP_TEST_ASSETS_DIR), boost::asio::use_future);
|
||||
io.run();
|
||||
auto score = loaded.get();
|
||||
BOOST_REQUIRE_MESSAGE(score, (score ? "" : score.error().describe()));
|
||||
BOOST_TEST(score->title == part.title);
|
||||
BOOST_TEST(score->composer == part.composer);
|
||||
BOOST_TEST(score->key_signature == part.key_signature);
|
||||
BOOST_TEST(score->part == part.part);
|
||||
BOOST_TEST(score->measure_count == part.measure_count);
|
||||
BOOST_TEST(score->pages.size() == part.total_pages);
|
||||
BOOST_TEST(score->source_path == part.source_path);
|
||||
}
|
||||
}
|
||||
std::filesystem::remove_all(root);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(numbered_practice_paths_keep_duplicate_titles_separate_and_refresh_after_rename) {
|
||||
auto root = std::filesystem::temp_directory_path() / ("product-vamp-paths-test-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
|
||||
auto assets = root / "assets";
|
||||
auto config = test_database_config(root / "vamp.db");
|
||||
std::filesystem::create_directories(assets / "songs");
|
||||
for (auto name : {"0010", "0002", "0001", "0127"}) {
|
||||
for (auto part_name : vamp_zero::practice_part_names()) {
|
||||
write_text(assets / "practice" / name / vamp_test::part_filename(part_name), score_asset_json("Shared Title", "C", std::string{part_name}));
|
||||
}
|
||||
}
|
||||
BOOST_REQUIRE(vamp_test::build_catalog(assets, config.path));
|
||||
auto io = boost::asio::io_context{};
|
||||
auto future = boost::asio::co_spawn(io, vamp_zero::async_load_practice_library(io.get_executor(), config, assets.string()), boost::asio::use_future);
|
||||
io.run();
|
||||
auto library = future.get();
|
||||
BOOST_REQUIRE(library);
|
||||
BOOST_REQUIRE_EQUAL(library->exercises.size(), 4U);
|
||||
BOOST_TEST(library->exercises[0].id == "0001");
|
||||
BOOST_TEST(library->exercises[1].id == "0002");
|
||||
BOOST_TEST(library->exercises[2].id == "0010");
|
||||
BOOST_TEST(library->exercises[3].id == "0127");
|
||||
for (auto const &exercise : library->exercises) {
|
||||
BOOST_TEST(exercise.title == "Shared Title");
|
||||
}
|
||||
BOOST_REQUIRE(vamp_test::build_catalog(assets, config.path));
|
||||
std::filesystem::rename(assets / "practice/0002", assets / "practice/0099");
|
||||
BOOST_REQUIRE(vamp_test::build_catalog(assets, config.path));
|
||||
auto rows = query_database(root / "vamp.db", "SELECT id FROM practice_exercises ORDER BY id");
|
||||
BOOST_REQUIRE(rows);
|
||||
BOOST_REQUIRE_EQUAL(rows->rows.size(), 12U);
|
||||
BOOST_TEST(!has_value(*rows, 0U, "0002-acoustic"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "0099-acoustic"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "0010-acoustic"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "0001-acoustic"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "0127-acoustic"));
|
||||
std::filesystem::remove_all(root);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(keyless_scores_keep_their_authored_key) {
|
||||
|
||||
Reference in New Issue
Block a user