+105
-79
@@ -126,16 +126,19 @@ auto navigation_state() -> vamp_zero::app_state {
|
||||
};
|
||||
auto exercise = vamp_zero::practice_exercise{
|
||||
.id = "exercise-1",
|
||||
.practice_type_id = "scale",
|
||||
.practice_type_title = "Scales",
|
||||
.lesson_group_id = "lesson-1",
|
||||
.lesson_group_title = "Major",
|
||||
.title = "C Major",
|
||||
.composer = "Composer",
|
||||
.authored_key_signature = "C",
|
||||
.variants = {variant},
|
||||
};
|
||||
exercise.variants.clear();
|
||||
for (auto key : vamp_zero::practice_key_names()) {
|
||||
variant.id = "exercise-" + std::string{key};
|
||||
variant.key_signature = key;
|
||||
exercise.variants.push_back(variant);
|
||||
}
|
||||
auto practice = vamp_zero::group_practice_exercises({exercise});
|
||||
BOOST_REQUIRE(practice);
|
||||
return vamp_zero::app_state{
|
||||
.catalog = std::make_shared<vamp_zero::catalogue const>(vamp_zero::catalogue{
|
||||
.performance = vamp_zero::group_library_parts({part}),
|
||||
@@ -283,69 +286,97 @@ BOOST_AUTO_TEST_CASE(score_parser_loads_the_generated_catalogue) {
|
||||
BOOST_TEST(count > 0U);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(chord_and_melody_practice_share_key_navigation_and_remote_display) {
|
||||
for (auto type : {"chord", "melody"}) {
|
||||
auto state = navigation_state();
|
||||
auto catalog = std::make_shared<vamp_zero::catalogue>(*state.catalog);
|
||||
auto &exercise = catalog->practice.exercises.front();
|
||||
exercise.practice_type_id = type;
|
||||
auto variant = exercise.variants.front();
|
||||
variant.id = "exercise-d";
|
||||
variant.key_signature = "D";
|
||||
variant.source_path = "exercise-d.json";
|
||||
variant.total_pages = 3U;
|
||||
exercise.variants.push_back(variant);
|
||||
catalog->practice.types.front().id = type;
|
||||
state.catalog = catalog;
|
||||
state.mode = vamp_zero::app_mode::PRACTICE_EXERCISE_MENU;
|
||||
state.selected_practice_type_index = 1U;
|
||||
state.selected_practice_lesson_index = 1U;
|
||||
state.selected_practice_exercise_index = 1U;
|
||||
state.audio.metronome_enabled = true;
|
||||
BOOST_TEST(vamp_zero::supports_key_selection(exercise));
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_KEY_MENU);
|
||||
BOOST_TEST(vamp_zero::practice_key_row_count(state) == 3U);
|
||||
BOOST_AUTO_TEST_CASE(practice_key_navigation_and_remote_display) {
|
||||
auto state = navigation_state();
|
||||
auto catalog = std::make_shared<vamp_zero::catalogue>(*state.catalog);
|
||||
auto &variant = catalog->practice.exercises.front().variants[2];
|
||||
variant.source_path = "exercise-d.json";
|
||||
variant.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);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
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_KEY_MENU);
|
||||
BOOST_TEST(vamp_zero::practice_key_row_count(state) == 13U);
|
||||
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::NEXT);
|
||||
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_variant(state, state.catalog->practice.exercises.front());
|
||||
BOOST_REQUIRE(selected != nullptr);
|
||||
BOOST_TEST(selected->id == "exercise-d");
|
||||
BOOST_TEST(selected->source_path == "exercise-d.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} == "Key: D");
|
||||
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_KEY_MENU);
|
||||
BOOST_TEST(control.snapshot().selected_practice_key_index == 2U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_KEY_MENU);
|
||||
BOOST_TEST(state.selected_practice_key_index == 2U);
|
||||
BOOST_TEST(state.active_practice_id.empty());
|
||||
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::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_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::PRACTICE_SCORE);
|
||||
BOOST_TEST(state.audio.metronome_enabled);
|
||||
auto selected = vamp_zero::selected_practice_variant(state, state.catalog->practice.exercises.front());
|
||||
BOOST_REQUIRE(selected != nullptr);
|
||||
BOOST_TEST(selected->id == "exercise-D");
|
||||
BOOST_TEST(selected->source_path == "exercise-d.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} == "Key: D");
|
||||
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_KEY_MENU);
|
||||
BOOST_TEST(control.snapshot().selected_practice_key_index == 3U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_CHECK(state.mode == vamp_zero::app_mode::PRACTICE_KEY_MENU);
|
||||
BOOST_TEST(state.selected_practice_key_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);
|
||||
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_catalogue_returns_to_main) {
|
||||
auto state = navigation_state();
|
||||
auto catalog = std::make_shared<vamp_zero::catalogue>(*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);
|
||||
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 == "366");
|
||||
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_KEY_MENU);
|
||||
state.catalog = vamp_zero::empty_catalogue();
|
||||
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_keys) {
|
||||
auto root = std::filesystem::temp_directory_path() / ("product-vamp-keys-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::recursive_directory_iterator{std::filesystem::path{VAMP_TEST_SOURCE_DIR} / "data/practice"}) {
|
||||
for (auto const &entry : std::filesystem::directory_iterator{std::filesystem::path{VAMP_TEST_SOURCE_DIR} / "data"}) {
|
||||
if (entry.is_regular_file() && entry.path().extension() == ".xml") {
|
||||
++expected_exercises;
|
||||
}
|
||||
@@ -360,7 +391,6 @@ BOOST_AUTO_TEST_CASE(database_reload_preserves_all_generated_practice_keys) {
|
||||
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(vamp_zero::supports_key_selection(exercise));
|
||||
BOOST_REQUIRE_EQUAL(exercise.variants.size(), 12U);
|
||||
auto keys = vamp_zero::practice_key_names();
|
||||
for (auto index = std::size_t{}; index < keys.size(); ++index) {
|
||||
@@ -394,8 +424,10 @@ BOOST_AUTO_TEST_CASE(numbered_practice_paths_keep_duplicate_titles_separate_and_
|
||||
auto assets = root / "assets";
|
||||
auto config = test_database_config(root / "vamp.db");
|
||||
std::filesystem::create_directories(assets / "songs");
|
||||
for (auto name : {"chord/001_lesson/010-cycles", "chord/001_lesson/002-cycles", "chord/002_lesson/001-cycles", "melody/001_lesson/127-cycles"}) {
|
||||
write_text(assets / "practice" / name / "c.json", score_asset_json("Shared Title"));
|
||||
for (auto name : {"010", "002", "001", "127"}) {
|
||||
for (auto key : vamp_zero::practice_key_names()) {
|
||||
write_text(assets / "practice" / name / (std::string{key} + ".json"), score_asset_json("Shared Title", std::string{key}));
|
||||
}
|
||||
}
|
||||
BOOST_REQUIRE(vamp_test::build_catalogue(assets, config.path));
|
||||
auto io = boost::asio::io_context{};
|
||||
@@ -404,30 +436,24 @@ BOOST_AUTO_TEST_CASE(numbered_practice_paths_keep_duplicate_titles_separate_and_
|
||||
auto library = future.get();
|
||||
BOOST_REQUIRE(library);
|
||||
BOOST_REQUIRE_EQUAL(library->exercises.size(), 4U);
|
||||
BOOST_REQUIRE_EQUAL(library->types.size(), 2U);
|
||||
BOOST_TEST(library->types.front().id == "chord");
|
||||
BOOST_REQUIRE_EQUAL(library->types.front().lesson_groups.size(), 2U);
|
||||
auto const &lesson = library->types.front().lesson_groups.front();
|
||||
BOOST_TEST(lesson.id == "001_lesson");
|
||||
BOOST_REQUIRE_EQUAL(lesson.exercises.size(), 2U);
|
||||
BOOST_TEST(library->exercises[lesson.exercises[0]].id == "chord-001_lesson-002-cycles");
|
||||
BOOST_TEST(library->exercises[lesson.exercises[1]].id == "chord-001_lesson-010-cycles");
|
||||
BOOST_TEST(library->exercises[0].id == "001");
|
||||
BOOST_TEST(library->exercises[1].id == "002");
|
||||
BOOST_TEST(library->exercises[2].id == "010");
|
||||
BOOST_TEST(library->exercises[3].id == "127");
|
||||
for (auto const &exercise : library->exercises) {
|
||||
BOOST_TEST(exercise.title == "Shared Title");
|
||||
}
|
||||
BOOST_REQUIRE(vamp_test::build_catalogue(assets, config.path));
|
||||
std::filesystem::rename(assets / "practice/chord/001_lesson", assets / "practice/chord/003_renamed_lesson");
|
||||
std::filesystem::rename(assets / "practice/chord/003_renamed_lesson/002-cycles", assets / "practice/chord/003_renamed_lesson/099-renamed");
|
||||
std::filesystem::rename(assets / "practice/002", assets / "practice/099");
|
||||
BOOST_REQUIRE(vamp_test::build_catalogue(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(), 4U);
|
||||
BOOST_TEST(!has_value(*rows, 0U, "chord-001_lesson-002-cycles-c"));
|
||||
BOOST_TEST(!has_value(*rows, 0U, "chord-001_lesson-010-cycles-c"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "chord-003_renamed_lesson-099-renamed-c"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "chord-003_renamed_lesson-010-cycles-c"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "chord-002_lesson-001-cycles-c"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "melody-001_lesson-127-cycles-c"));
|
||||
BOOST_REQUIRE_EQUAL(rows->rows.size(), 48U);
|
||||
BOOST_TEST(!has_value(*rows, 0U, "002-C"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "099-C"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "010-C"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "001-C"));
|
||||
BOOST_TEST(has_value(*rows, 0U, "127-C"));
|
||||
std::filesystem::remove_all(root);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user