@@ -3,7 +3,7 @@ add_executable(product-vamp-test
|
||||
../src/vamp_pico/input.cpp
|
||||
../src/vamp_pico/remote_display.cpp
|
||||
test.cpp
|
||||
test_catalogue_runtime.cpp
|
||||
test_catalog_runtime.cpp
|
||||
test_health.cpp
|
||||
test_pico.cpp
|
||||
test_playback.cpp
|
||||
|
||||
@@ -21,13 +21,13 @@ inline auto part_filename(std::string_view part) -> std::string {
|
||||
return result + ".json";
|
||||
}
|
||||
|
||||
inline auto build_catalogue(std::filesystem::path const &assets, std::filesystem::path const &database) -> std::bool_t {
|
||||
inline auto build_catalog(std::filesystem::path const &assets, std::filesystem::path const &database) -> std::bool_t {
|
||||
auto source = assets.string();
|
||||
auto destination = database.string();
|
||||
auto child = ::fork();
|
||||
BOOST_REQUIRE(child >= 0);
|
||||
if (child == 0) {
|
||||
::execl(VAMP_TEST_PYTHON, VAMP_TEST_PYTHON, VAMP_TEST_SOURCE_DIR "/generator/catalogue.py", source.c_str(), destination.c_str(), nullptr);
|
||||
::execl(VAMP_TEST_PYTHON, VAMP_TEST_PYTHON, VAMP_TEST_SOURCE_DIR "/generator/catalog.py", source.c_str(), destination.c_str(), nullptr);
|
||||
::_exit(127);
|
||||
}
|
||||
auto status = std::int32_t{};
|
||||
+12
-11
@@ -41,7 +41,7 @@
|
||||
#include <vamp_zero/score.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
#include "catalogue_fixture.hpp"
|
||||
#include "catalog_fixture.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -137,7 +137,7 @@ auto navigation_state() -> vamp_zero::app_state {
|
||||
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{
|
||||
.catalog = std::make_shared<vamp_zero::catalog const>(vamp_zero::catalog{
|
||||
.performance = vamp_zero::group_library_parts({part}),
|
||||
.practice = std::move(*practice),
|
||||
}),
|
||||
@@ -157,6 +157,7 @@ BOOST_AUTO_TEST_CASE(runtime_config_uses_headless_and_ignores_unknown_fields) {
|
||||
BOOST_REQUIRE(parsed);
|
||||
BOOST_TEST(parsed->runtime.headless);
|
||||
BOOST_TEST(!parsed->audio.enabled);
|
||||
BOOST_TEST(parsed->database.path == "/usr/share/product-vamp/catalog.db");
|
||||
auto invalid = vamp_zero::parse_config(boost::json::parse(R"json({"runtime":{"headless":"yes"}})json"));
|
||||
BOOST_TEST(!invalid);
|
||||
}
|
||||
@@ -274,7 +275,7 @@ BOOST_AUTO_TEST_CASE(main_menu_metronome_setting_survives_score_selection) {
|
||||
BOOST_TEST(!state.audio.tempo_editing);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(score_parser_loads_the_generated_catalogue) {
|
||||
BOOST_AUTO_TEST_CASE(score_parser_loads_the_generated_catalog) {
|
||||
auto count = std::size_t{};
|
||||
for (auto const &entry : std::filesystem::recursive_directory_iterator{VAMP_TEST_ASSETS_DIR}) {
|
||||
if (entry.path().extension() != ".json") {
|
||||
@@ -294,7 +295,7 @@ BOOST_AUTO_TEST_CASE(score_parser_loads_the_generated_catalogue) {
|
||||
|
||||
BOOST_AUTO_TEST_CASE(practice_part_navigation_and_remote_display) {
|
||||
auto state = navigation_state();
|
||||
auto catalog = std::make_shared<vamp_zero::catalogue>(*state.catalog);
|
||||
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;
|
||||
@@ -350,9 +351,9 @@ BOOST_AUTO_TEST_CASE(practice_part_navigation_and_remote_display) {
|
||||
BOOST_REQUIRE(vamp_zero::validate_app_state(state));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(flat_practice_wraps_and_empty_catalogue_returns_to_main) {
|
||||
BOOST_AUTO_TEST_CASE(flat_practice_wraps_and_empty_catalog_returns_to_main) {
|
||||
auto state = navigation_state();
|
||||
auto catalog = std::make_shared<vamp_zero::catalogue>(*state.catalog);
|
||||
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;
|
||||
@@ -369,7 +370,7 @@ BOOST_AUTO_TEST_CASE(flat_practice_wraps_and_empty_catalogue_returns_to_main) {
|
||||
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_catalogue();
|
||||
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);
|
||||
@@ -389,7 +390,7 @@ BOOST_AUTO_TEST_CASE(database_reload_preserves_all_generated_practice_parts) {
|
||||
}
|
||||
BOOST_REQUIRE(expected_exercises > 0U);
|
||||
for (auto iteration = std::uint32_t{}; iteration < 2U; ++iteration) {
|
||||
config.path = (std::filesystem::path{VAMP_TEST_ASSETS_DIR} / "catalogue.db").string();
|
||||
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);
|
||||
io.run();
|
||||
@@ -434,7 +435,7 @@ BOOST_AUTO_TEST_CASE(numbered_practice_paths_keep_duplicate_titles_separate_and_
|
||||
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_catalogue(assets, config.path));
|
||||
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();
|
||||
@@ -448,9 +449,9 @@ BOOST_AUTO_TEST_CASE(numbered_practice_paths_keep_duplicate_titles_separate_and_
|
||||
for (auto const &exercise : library->exercises) {
|
||||
BOOST_TEST(exercise.title == "Shared Title");
|
||||
}
|
||||
BOOST_REQUIRE(vamp_test::build_catalogue(assets, config.path));
|
||||
BOOST_REQUIRE(vamp_test::build_catalog(assets, config.path));
|
||||
std::filesystem::rename(assets / "practice/002", assets / "practice/099");
|
||||
BOOST_REQUIRE(vamp_test::build_catalogue(assets, config.path));
|
||||
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);
|
||||
|
||||
@@ -11,7 +11,7 @@ from generator.parts import PART_TYPES
|
||||
from unittest.mock import patch
|
||||
from tests.test_musicxml import xml_note, xml_score
|
||||
|
||||
class CatalogueTests(unittest.TestCase):
|
||||
class CatalogTests(unittest.TestCase):
|
||||
def test_every_numbered_source_is_wired_to_three_part_paths(self):
|
||||
source = Path('data/practice')
|
||||
sources = sorted(source.glob('*.xml'))
|
||||
@@ -5,7 +5,7 @@ import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from generator.catalogue import APPLICATION_ID, SCHEMA_VERSION, build_catalogue
|
||||
from generator.catalog import APPLICATION_ID, SCHEMA_VERSION, build_catalog
|
||||
|
||||
def bundle(title='Fixture', key='C', part='Lead'):
|
||||
return {
|
||||
@@ -21,14 +21,14 @@ def write_score(root, relative, document=None):
|
||||
path.write_text(json.dumps(document or bundle()), encoding='utf-8')
|
||||
return path
|
||||
|
||||
class CatalogueTests(unittest.TestCase):
|
||||
class CatalogTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temporary = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temporary.cleanup)
|
||||
self.root = Path(self.temporary.name)
|
||||
(self.root / 'songs').mkdir()
|
||||
def rows(self, table):
|
||||
with closing(sqlite3.connect(self.root / 'catalogue.db')) as connection:
|
||||
with closing(sqlite3.connect(self.root / 'catalog.db')) as connection:
|
||||
connection.row_factory = sqlite3.Row
|
||||
return [dict(row) for row in connection.execute(f'SELECT * FROM {table} ORDER BY id')]
|
||||
def test_metadata_relative_paths_and_complete_documents(self):
|
||||
@@ -36,7 +36,8 @@ class CatalogueTests(unittest.TestCase):
|
||||
write_score(self.root, 'songs/tune.json', document)
|
||||
for part in ('Acoustic', 'Electric', 'Vocal'):
|
||||
write_score(self.root, f'practice/001/{part.lower()}.json', bundle('Exercise', 'Eb', part))
|
||||
database = build_catalogue(self.root)
|
||||
database = build_catalog(self.root)
|
||||
self.assertEqual(database, self.root / 'catalog.db')
|
||||
song = self.rows('songs')[0]
|
||||
self.assertEqual(json.loads(song['source_json']), document)
|
||||
self.assertEqual((song['id'], song['part'], song['source_path']), ('tune', 'Lead', 'songs/tune.json'))
|
||||
@@ -57,62 +58,65 @@ class CatalogueTests(unittest.TestCase):
|
||||
self.assertFalse(Path(str(database) + '-journal').exists())
|
||||
def test_rebuild_is_deterministic_relocatable_and_replaces_deleted_rows(self):
|
||||
score = write_score(self.root, 'songs/tune.json')
|
||||
database = build_catalogue(self.root)
|
||||
database = build_catalog(self.root)
|
||||
previous = database.read_bytes()
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
self.assertEqual(database.read_bytes(), previous)
|
||||
with tempfile.TemporaryDirectory() as other:
|
||||
root = Path(other)
|
||||
write_score(root, 'songs/tune.json')
|
||||
self.assertEqual(build_catalogue(root).read_bytes(), previous)
|
||||
self.assertEqual(build_catalog(root).read_bytes(), previous)
|
||||
score.rename(score.with_name('renamed.json'))
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
self.assertEqual([row['id'] for row in self.rows('songs')], ['renamed'])
|
||||
score.with_name('renamed.json').unlink()
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
self.assertEqual(self.rows('songs'), [])
|
||||
def test_invalid_input_preserves_existing_database(self):
|
||||
score = write_score(self.root, 'songs/tune.json')
|
||||
database = build_catalogue(self.root)
|
||||
database = build_catalog(self.root)
|
||||
previous = database.read_bytes()
|
||||
for document in ({}, bundle(title=''), bundle(key=None)):
|
||||
score.write_text(json.dumps(document))
|
||||
with self.assertRaises(ValueError):
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
self.assertEqual(database.read_bytes(), previous)
|
||||
self.assertFalse(list(self.root.glob('.vamp-catalogue-*')))
|
||||
self.assertFalse(list(self.root.glob('.vamp-catalog-*')))
|
||||
def test_missing_parts_and_metadata_disagreement_fail(self):
|
||||
for part in ('Acoustic', 'Electric'):
|
||||
write_score(self.root, f'practice/001/{part.lower()}.json', bundle(part=part))
|
||||
with self.assertRaisesRegex(ValueError, 'all three parts'):
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
write_score(self.root, 'practice/001/vocal.json', bundle(key='F', part='Vocal'))
|
||||
with self.assertRaisesRegex(ValueError, 'disagree'):
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
def test_keyless_parts_preserve_their_original_key(self):
|
||||
for part in ('Acoustic', 'Electric', 'Vocal'):
|
||||
write_score(self.root, f'practice/001/{part.lower()}.json', bundle(key='No key', part=part))
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
self.assertTrue(all(row['key_signature'] == 'No key' for row in self.rows('practice_exercises')))
|
||||
def test_invalid_layout_and_escaping_source_fail(self):
|
||||
with self.assertRaisesRegex(ValueError, 'directory not found'):
|
||||
build_catalogue(self.root / 'missing')
|
||||
build_catalog(self.root / 'missing')
|
||||
self.assertFalse((self.root / 'missing').exists())
|
||||
score = write_score(self.root, 'songs/nested/tune.json')
|
||||
with self.assertRaisesRegex(ValueError, 'unexpected songs'):
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
score.unlink()
|
||||
(self.root / 'songs/escape.json').symlink_to('/etc/passwd')
|
||||
with self.assertRaises(ValueError):
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
def test_runtime_asset_packaging_excludes_score_json(self):
|
||||
import subprocess
|
||||
write_score(self.root, 'songs/tune.json')
|
||||
build_catalogue(self.root)
|
||||
build_catalog(self.root)
|
||||
(self.root / 'songs/tune.png').write_bytes(b'page')
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
destination = Path(temporary)
|
||||
subprocess.run(['cmake', f'-DSOURCE={self.root}', f'-DDESTINATION={destination}', '-P', 'cmake/runtime_assets.cmake'], check=True, capture_output=True)
|
||||
self.assertTrue((destination / 'catalogue.db').exists())
|
||||
self.assertTrue((destination / 'catalog.db').exists())
|
||||
for name in ('vamp.example.json', 'vamp.development.json'):
|
||||
config = json.loads((Path('package/config') / name).read_text())
|
||||
self.assertEqual(Path(config['database']['path']).name, 'catalog.db')
|
||||
self.assertTrue((destination / 'songs/tune.png').exists())
|
||||
self.assertFalse(list(destination.rglob('*.json')))
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <vamp_zero/navigation.hpp>
|
||||
#include <vamp_zero/portal.hpp>
|
||||
|
||||
#include "catalogue_fixture.hpp"
|
||||
#include "catalog_fixture.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -40,30 +40,30 @@ static_assert(!retains_score_json<vamp_zero::library_part>);
|
||||
static_assert(!retains_score_json<vamp_zero::practice_exercise>);
|
||||
static_assert(!retains_score_json<vamp_zero::library_part>);
|
||||
|
||||
struct catalogue_directory {
|
||||
struct catalog_directory {
|
||||
std::filesystem::path path;
|
||||
catalogue_directory() {
|
||||
auto pattern = (std::filesystem::temp_directory_path() / "vamp-catalogue-XXXXXX").string();
|
||||
catalog_directory() {
|
||||
auto pattern = (std::filesystem::temp_directory_path() / "vamp-catalog-XXXXXX").string();
|
||||
BOOST_REQUIRE(::mkdtemp(pattern.data()) != nullptr);
|
||||
path = pattern;
|
||||
}
|
||||
~catalogue_directory() {
|
||||
~catalog_directory() {
|
||||
auto ignored = std::error_code{};
|
||||
std::filesystem::remove_all(path, ignored);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Function, typename... Arguments>
|
||||
auto run_catalogue_operation(Function function, Arguments... arguments) {
|
||||
auto run_catalog_operation(Function function, Arguments... arguments) {
|
||||
auto io = boost::asio::io_context{};
|
||||
auto future = boost::asio::co_spawn(io, function(io.get_executor(), std::move(arguments)...), boost::asio::use_future);
|
||||
io.run();
|
||||
return future.get();
|
||||
}
|
||||
|
||||
auto catalogue_query(boost::asio::any_io_executor executor, vamp_zero::database_config config, std::string sql, std::vector<noto::sqlite_value> params)
|
||||
auto catalog_query(boost::asio::any_io_executor executor, vamp_zero::database_config config, std::string sql, std::vector<noto::sqlite_value> params)
|
||||
-> boost::asio::awaitable<std::expected<noto::query_result, modulus::error>> {
|
||||
auto connection = noto::connection{executor, noto::file_connection_config(config.path, "vamp-catalogue-test")};
|
||||
auto connection = noto::connection{executor, noto::file_connection_config(config.path, "vamp-catalog-test")};
|
||||
auto connected = co_await connection.async_connect();
|
||||
if (!connected) {
|
||||
co_return std::unexpected(connected.error());
|
||||
@@ -79,7 +79,7 @@ auto catalogue_query(boost::asio::any_io_executor executor, vamp_zero::database_
|
||||
co_return result;
|
||||
}
|
||||
|
||||
auto catalogue_bundle(std::string_view title, std::string_view key = "C", std::string_view part = "Lead") -> std::string {
|
||||
auto catalog_bundle(std::string_view title, std::string_view key = "C", std::string_view part = "Lead") -> std::string {
|
||||
auto value = boost::json::parse(R"json({
|
||||
"schema_version":3,
|
||||
"music":{"metadata":{"title":"Fixture","composer":"Composer","key_signature":"C","time_signature":"4/4"},
|
||||
@@ -95,15 +95,15 @@ auto catalogue_bundle(std::string_view title, std::string_view key = "C", std::s
|
||||
return boost::json::serialize(value);
|
||||
}
|
||||
|
||||
struct catalogue_database {
|
||||
catalogue_directory directory;
|
||||
struct catalog_database {
|
||||
catalog_directory directory;
|
||||
std::filesystem::path assets{directory.path / "assets"};
|
||||
vamp_zero::database_config config{.path = (directory.path / "catalogue.db").string()};
|
||||
catalogue_database() {
|
||||
vamp_zero::database_config config{.path = (directory.path / "catalog.db").string()};
|
||||
catalog_database() {
|
||||
std::filesystem::create_directories(assets / "songs");
|
||||
}
|
||||
auto query(std::string sql, std::vector<noto::sqlite_value> params = {}) const -> noto::query_result {
|
||||
auto result = run_catalogue_operation(catalogue_query, config, std::move(sql), std::move(params));
|
||||
auto result = run_catalog_operation(catalog_query, config, std::move(sql), std::move(params));
|
||||
BOOST_REQUIRE_MESSAGE(result, (result ? "" : result.error().describe()));
|
||||
return std::move(*result);
|
||||
}
|
||||
@@ -126,20 +126,20 @@ struct catalogue_database {
|
||||
BOOST_REQUIRE(output.good());
|
||||
}
|
||||
auto build() const -> std::bool_t {
|
||||
return vamp_test::build_catalogue(assets, config.path);
|
||||
return vamp_test::build_catalog(assets, config.path);
|
||||
}
|
||||
auto performance() const -> std::expected<vamp_zero::library_state, modulus::error> {
|
||||
return run_catalogue_operation(vamp_zero::async_load_performance_library, config, assets.string());
|
||||
return run_catalog_operation(vamp_zero::async_load_performance_library, config, assets.string());
|
||||
}
|
||||
auto practice() const -> std::expected<vamp_zero::practice_library, modulus::error> {
|
||||
return run_catalogue_operation(vamp_zero::async_load_practice_library, config, assets.string());
|
||||
return run_catalog_operation(vamp_zero::async_load_practice_library, config, assets.string());
|
||||
}
|
||||
auto score(vamp_zero::score_category category, std::string id) const -> std::expected<vamp_zero::score_document, modulus::error> {
|
||||
return run_catalogue_operation(vamp_zero::async_load_score, config, vamp_zero::score_reference{category, std::move(id)}, assets.string());
|
||||
return run_catalog_operation(vamp_zero::async_load_score, config, vamp_zero::score_reference{category, std::move(id)}, assets.string());
|
||||
}
|
||||
};
|
||||
|
||||
auto catalogue_exercise(std::string authored = "Eb", std::string id = "001") -> vamp_zero::practice_exercise {
|
||||
auto catalog_exercise(std::string authored = "Eb", std::string id = "001") -> vamp_zero::practice_exercise {
|
||||
auto result = vamp_zero::practice_exercise{
|
||||
.id = std::move(id),
|
||||
.title = "Exercise",
|
||||
@@ -153,14 +153,14 @@ auto catalogue_exercise(std::string authored = "Eb", std::string id = "001") ->
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(catalogue_snapshots_heartbeat_and_navigation_share_immutable_metadata) {
|
||||
BOOST_AUTO_TEST_CASE(catalog_snapshots_heartbeat_and_navigation_share_immutable_metadata) {
|
||||
auto performance = vamp_zero::group_library_parts({
|
||||
{.id = "other", .title = "A Tune", .composer = "Composer", .part = "Lead", .total_pages = 1},
|
||||
{.id = "chosen", .title = "B Tune", .composer = "Composer", .part = "Lead", .total_pages = 2},
|
||||
});
|
||||
auto practice = vamp_zero::group_practice_exercises({catalogue_exercise("Eb", "002"), catalogue_exercise("Eb", "001")});
|
||||
auto practice = vamp_zero::group_practice_exercises({catalog_exercise("Eb", "002"), catalog_exercise("Eb", "001")});
|
||||
BOOST_REQUIRE(practice);
|
||||
auto catalog = std::make_shared<vamp_zero::catalogue const>(vamp_zero::catalogue{std::move(performance), std::move(*practice)});
|
||||
auto catalog = std::make_shared<vamp_zero::catalog const>(vamp_zero::catalog{std::move(performance), std::move(*practice)});
|
||||
auto original = vamp_zero::app_state{
|
||||
.catalog = catalog,
|
||||
.mode = vamp_zero::app_mode::PERFORMANCE_PART_MENU,
|
||||
@@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE(catalogue_snapshots_heartbeat_and_navigation_share_immutabl
|
||||
BOOST_TEST(parts.selected_practice_part_index == 0U);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(catalogue_performance_groups_use_title_and_composer_with_part_indices) {
|
||||
BOOST_AUTO_TEST_CASE(catalog_performance_groups_use_title_and_composer_with_part_indices) {
|
||||
auto library = vamp_zero::group_library_parts({
|
||||
{.id = "other-composer", .title = "Shared Title", .composer = "Bea", .part = "Lead"},
|
||||
{.id = "vocal", .title = "Shared Title", .composer = "Ada", .part = "Vocal"},
|
||||
@@ -242,15 +242,15 @@ BOOST_AUTO_TEST_CASE(catalogue_performance_groups_use_title_and_composer_with_pa
|
||||
BOOST_TEST(library.parts[library.groups[1].parts[1]].id == "vocal");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(catalogue_practice_requires_complete_ordered_parts_and_key_agreement) {
|
||||
BOOST_AUTO_TEST_CASE(catalog_practice_requires_complete_ordered_parts_and_key_agreement) {
|
||||
for (auto authored : {"Eb", "C dorian", "No key", ""}) {
|
||||
auto first = catalogue_exercise(authored);
|
||||
auto first = catalog_exercise(authored);
|
||||
std::reverse(first.parts.begin(), first.parts.end());
|
||||
auto last = first.parts.back();
|
||||
first.parts.pop_back();
|
||||
auto fragment = catalogue_exercise(authored);
|
||||
auto fragment = catalog_exercise(authored);
|
||||
fragment.parts = {last};
|
||||
auto grouped = vamp_zero::group_practice_exercises({catalogue_exercise("F", "002"), first, fragment});
|
||||
auto grouped = vamp_zero::group_practice_exercises({catalog_exercise("F", "002"), first, fragment});
|
||||
BOOST_REQUIRE(grouped);
|
||||
BOOST_REQUIRE_EQUAL(grouped->exercises.size(), 2U);
|
||||
auto const &exercise = grouped->exercises[0];
|
||||
@@ -262,8 +262,8 @@ BOOST_AUTO_TEST_CASE(catalogue_practice_requires_complete_ordered_parts_and_key_
|
||||
}
|
||||
}
|
||||
for (auto conflict : {"F", ""}) {
|
||||
auto first = catalogue_exercise();
|
||||
auto second = catalogue_exercise(conflict);
|
||||
auto first = catalog_exercise();
|
||||
auto second = catalog_exercise(conflict);
|
||||
second.parts = {second.parts.back()};
|
||||
first.parts.pop_back();
|
||||
auto grouped = vamp_zero::group_practice_exercises({first, second});
|
||||
@@ -271,21 +271,21 @@ BOOST_AUTO_TEST_CASE(catalogue_practice_requires_complete_ordered_parts_and_key_
|
||||
BOOST_TEST(grouped.error().code() == static_cast<std::int32_t>(vamp_zero::error_code::INVALID_ARGUMENT));
|
||||
BOOST_TEST(grouped.error().message().find("disagree on key") != std::string_view::npos);
|
||||
}
|
||||
auto missing = catalogue_exercise();
|
||||
auto missing = catalog_exercise();
|
||||
missing.parts.pop_back();
|
||||
BOOST_TEST(!vamp_zero::group_practice_exercises({missing}));
|
||||
auto duplicate = catalogue_exercise();
|
||||
auto duplicate = catalog_exercise();
|
||||
duplicate.parts.back().part = "Acoustic";
|
||||
BOOST_TEST(!vamp_zero::group_practice_exercises({duplicate}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(catalogue_individual_score_lookup_uses_category_and_reports_missing_or_invalid) {
|
||||
auto db = catalogue_database{};
|
||||
auto song = catalogue_bundle("Song", "F");
|
||||
auto exercise = catalogue_bundle("Exercise", "D", "Electric");
|
||||
BOOST_AUTO_TEST_CASE(catalog_individual_score_lookup_uses_category_and_reports_missing_or_invalid) {
|
||||
auto db = catalog_database{};
|
||||
auto song = catalog_bundle("Song", "F");
|
||||
auto exercise = catalog_bundle("Exercise", "D", "Electric");
|
||||
db.write("songs/shared.json", song);
|
||||
for (auto part : vamp_zero::practice_part_names()) {
|
||||
db.write(std::filesystem::path{"practice/001"} / vamp_test::part_filename(part), catalogue_bundle("Exercise", "D", part));
|
||||
db.write(std::filesystem::path{"practice/001"} / vamp_test::part_filename(part), catalog_bundle("Exercise", "D", part));
|
||||
}
|
||||
BOOST_REQUIRE(db.build());
|
||||
db.query("UPDATE practice_exercises SET id = 'shared' WHERE part = 'Electric'");
|
||||
@@ -317,9 +317,9 @@ BOOST_AUTO_TEST_CASE(catalogue_individual_score_lookup_uses_category_and_reports
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(catalogue_sequential_score_loads_keep_executor_stack_bounded) {
|
||||
auto db = catalogue_database{};
|
||||
db.write("songs/repeated.json", catalogue_bundle("Repeated"));
|
||||
BOOST_AUTO_TEST_CASE(catalog_sequential_score_loads_keep_executor_stack_bounded) {
|
||||
auto db = catalog_database{};
|
||||
db.write("songs/repeated.json", catalog_bundle("Repeated"));
|
||||
BOOST_REQUIRE(db.build());
|
||||
auto repeated_loads = [](boost::asio::any_io_executor executor, vamp_zero::database_config config, std::string assets)
|
||||
-> boost::asio::awaitable<std::expected<std::uint32_t, modulus::error>> {
|
||||
@@ -332,13 +332,13 @@ BOOST_AUTO_TEST_CASE(catalogue_sequential_score_loads_keep_executor_stack_bounde
|
||||
}
|
||||
co_return 4096U;
|
||||
};
|
||||
auto result = run_catalogue_operation(repeated_loads, db.config, db.assets.string());
|
||||
auto result = run_catalog_operation(repeated_loads, db.config, db.assets.string());
|
||||
BOOST_REQUIRE_MESSAGE(result, (result ? "" : result.error().describe()));
|
||||
BOOST_TEST(*result == 4096U);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(catalogue_reload_uses_cached_metadata_without_parsing_score_json) {
|
||||
auto db = catalogue_database{};
|
||||
BOOST_AUTO_TEST_CASE(catalog_reload_uses_cached_metadata_without_parsing_score_json) {
|
||||
auto db = catalog_database{};
|
||||
BOOST_REQUIRE(db.build());
|
||||
// Complete cached metadata must not require parsing or retaining the score body.
|
||||
db.query("INSERT INTO songs(id, title, composer, source_json, part, source_path, "
|
||||
@@ -388,9 +388,9 @@ BOOST_AUTO_TEST_CASE(catalogue_reload_uses_cached_metadata_without_parsing_score
|
||||
BOOST_TEST(disagreement.error().message().find("disagree on key") != std::string_view::npos);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(catalogue_validation_rejects_missing_legacy_and_corrupt_files_without_repair) {
|
||||
auto db = catalogue_database{};
|
||||
auto validate = [&] { return run_catalogue_operation(vamp_zero::async_validate_database, db.config, true); };
|
||||
BOOST_AUTO_TEST_CASE(catalog_validation_rejects_missing_legacy_and_corrupt_files_without_repair) {
|
||||
auto db = catalog_database{};
|
||||
auto validate = [&] { return run_catalog_operation(vamp_zero::async_validate_database, db.config, true); };
|
||||
BOOST_TEST(!validate());
|
||||
BOOST_TEST(!std::filesystem::exists(db.config.path));
|
||||
BOOST_REQUIRE(db.build());
|
||||
@@ -419,11 +419,11 @@ BOOST_AUTO_TEST_CASE(catalogue_validation_rejects_missing_legacy_and_corrupt_fil
|
||||
BOOST_TEST(!std::filesystem::exists(db.config.path + "-journal"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(catalogue_reads_readonly_database_without_json_and_resolves_relocated_assets) {
|
||||
auto db = catalogue_database{};
|
||||
db.write("songs/tune.json", catalogue_bundle("Relocated"));
|
||||
BOOST_AUTO_TEST_CASE(catalog_reads_readonly_database_without_json_and_resolves_relocated_assets) {
|
||||
auto db = catalog_database{};
|
||||
db.write("songs/tune.json", catalog_bundle("Relocated"));
|
||||
for (auto part_name : vamp_zero::practice_part_names()) {
|
||||
db.write(std::filesystem::path{"practice/001"} / vamp_test::part_filename(part_name), catalogue_bundle("Exercise", "Eb", part_name));
|
||||
db.write(std::filesystem::path{"practice/001"} / vamp_test::part_filename(part_name), catalog_bundle("Exercise", "Eb", part_name));
|
||||
}
|
||||
BOOST_REQUIRE(db.build());
|
||||
std::filesystem::remove(db.assets / "songs/tune.json");
|
||||
@@ -433,7 +433,7 @@ BOOST_AUTO_TEST_CASE(catalogue_reads_readonly_database_without_json_and_resolves
|
||||
db.assets = moved;
|
||||
auto timestamp = std::filesystem::last_write_time(db.config.path);
|
||||
std::filesystem::permissions(db.config.path, std::filesystem::perms::owner_read);
|
||||
BOOST_REQUIRE(run_catalogue_operation(vamp_zero::async_validate_database, db.config, true));
|
||||
BOOST_REQUIRE(run_catalog_operation(vamp_zero::async_validate_database, db.config, true));
|
||||
auto songs = db.performance();
|
||||
auto practice = db.practice();
|
||||
auto score = db.score(vamp_zero::score_category::PERFORMANCE, "tune");
|
||||
@@ -449,9 +449,9 @@ BOOST_AUTO_TEST_CASE(catalogue_reads_readonly_database_without_json_and_resolves
|
||||
BOOST_TEST(!std::filesystem::exists(db.config.path + "-journal"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(catalogue_rejects_paths_outside_the_asset_root) {
|
||||
auto db = catalogue_database{};
|
||||
db.write("songs/tune.json", catalogue_bundle("Fixture"));
|
||||
BOOST_AUTO_TEST_CASE(catalog_rejects_paths_outside_the_asset_root) {
|
||||
auto db = catalog_database{};
|
||||
db.write("songs/tune.json", catalog_bundle("Fixture"));
|
||||
BOOST_REQUIRE(db.build());
|
||||
for (auto path : {"/tmp/tune.json", "../tune.json", "songs/../../tune.json", "songs/./tune.json", "songs\\tune.json", ""}) {
|
||||
if (std::string_view{path}.empty()) {
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <vamp_zero/health.hpp>
|
||||
#include <vamp_zero/portal.hpp>
|
||||
|
||||
#include "catalogue_fixture.hpp"
|
||||
#include "catalog_fixture.hpp"
|
||||
|
||||
|
||||
namespace {
|
||||
@@ -189,7 +189,7 @@ auto make_assets(vamp_zero::config const &config) -> void {
|
||||
name.front() = static_cast<std::char_t>(name.front() - 'A' + 'a');
|
||||
write_score(root / "practice" / "001" / (name + ".json"), std::string{part_name});
|
||||
}
|
||||
BOOST_REQUIRE(vamp_test::build_catalogue(root, config.database.path));
|
||||
BOOST_REQUIRE(vamp_test::build_catalog(root, config.database.path));
|
||||
}
|
||||
|
||||
auto run_once(std::filesystem::path const &root, vamp_zero::config const &config) -> std::expected<void, modulus::error> {
|
||||
@@ -336,7 +336,7 @@ BOOST_AUTO_TEST_CASE(portal_remote_commands_refresh_connection_without_backgroun
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(readiness_reads_packaged_catalogue_without_hardware_or_heartbeat) {
|
||||
BOOST_AUTO_TEST_CASE(readiness_reads_packaged_catalog_without_hardware_or_heartbeat) {
|
||||
auto root = temporary_directory{};
|
||||
auto config = fixture_config(root.path);
|
||||
make_assets(config);
|
||||
@@ -399,7 +399,7 @@ BOOST_AUTO_TEST_CASE(readiness_validates_generated_audio_using_configured_asset_
|
||||
auto score = boost::json::parse(read_file(path));
|
||||
score.as_object()["playback"] = boost::json::parse(read_file(fixture / "score.json")).at("playback");
|
||||
write_file(path, boost::json::serialize(score));
|
||||
BOOST_REQUIRE(vamp_test::build_catalogue(assets, config.database.path));
|
||||
BOOST_REQUIRE(vamp_test::build_catalog(assets, config.database.path));
|
||||
auto ready = run_once(root.path, config);
|
||||
BOOST_REQUIRE_MESSAGE(ready, (ready ? "" : ready.error().describe()));
|
||||
auto &sample = score.at("playback").at("samples").as_array().front().as_object();
|
||||
@@ -409,7 +409,7 @@ BOOST_AUTO_TEST_CASE(readiness_validates_generated_audio_using_configured_asset_
|
||||
sample["sha256"] = checksum(corrupt);
|
||||
write_file(audio, corrupt);
|
||||
write_file(path, boost::json::serialize(score));
|
||||
BOOST_REQUIRE(vamp_test::build_catalogue(assets, config.database.path));
|
||||
BOOST_REQUIRE(vamp_test::build_catalog(assets, config.database.path));
|
||||
ready = run_once(root.path, config);
|
||||
BOOST_REQUIRE(!ready);
|
||||
BOOST_TEST(std::string{ready.error().message()}.find("PCM16 WAV") != std::string::npos);
|
||||
@@ -437,7 +437,7 @@ BOOST_AUTO_TEST_CASE(readiness_rejects_corrupt_checksums_and_escaping_pages) {
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(readiness_rejects_missing_or_malformed_catalogues) {
|
||||
BOOST_AUTO_TEST_CASE(readiness_rejects_missing_or_malformed_catalogs) {
|
||||
auto root = temporary_directory{};
|
||||
auto config = fixture_config(root.path);
|
||||
BOOST_TEST(!run_once(root.path, config));
|
||||
@@ -479,7 +479,7 @@ BOOST_AUTO_TEST_CASE(readiness_decodes_pages_even_when_checksums_match) {
|
||||
write_file(score_path.parent_path() / std::string{page.at("path").as_string()}, bytes);
|
||||
page["sha256"] = checksum(bytes);
|
||||
write_file(score_path, boost::json::serialize(score));
|
||||
BOOST_REQUIRE(vamp_test::build_catalogue(config.runtime.assets_path, config.database.path));
|
||||
BOOST_REQUIRE(vamp_test::build_catalog(config.runtime.assets_path, config.database.path));
|
||||
auto ready = run_once(root.path, config);
|
||||
BOOST_REQUIRE_MESSAGE(!ready, kind);
|
||||
BOOST_TEST(ready.error().describe().find("first.pages/1.png") != std::string::npos);
|
||||
|
||||
@@ -22,9 +22,9 @@ class MusicModelTests(unittest.TestCase):
|
||||
engraving = patch('generator.__main__.engrave_tree')
|
||||
engraving.start()
|
||||
self.addCleanup(engraving.stop)
|
||||
catalogue = patch('generator.__main__.build_catalogue')
|
||||
catalogue.start()
|
||||
self.addCleanup(catalogue.stop)
|
||||
catalog = patch('generator.__main__.build_catalog')
|
||||
catalog.start()
|
||||
self.addCleanup(catalog.stop)
|
||||
def test_chord_semantics_are_not_voicing_heuristics(self):
|
||||
cases = {'C': {0, 4, 7}, 'Cdim': {0, 3, 6}, 'Cdim7': {0, 3, 6, 9}, 'Csus2': {0, 2, 7},
|
||||
'C7b5': {0, 4, 6, 10}, 'G7b9': {7, 11, 2, 5, 8}, 'Fmaj7#11': {5, 9, 0, 4, 11}}
|
||||
@@ -35,7 +35,7 @@ class MusicModelTests(unittest.TestCase):
|
||||
pitches = chord_pitches(definition, chord_positions(*chord_requirements(definition))[0])
|
||||
self.assertTrue(essentials.issubset({pitch_number(p) % 12 for p in pitches}), label)
|
||||
with self.assertRaises(ValueError):
|
||||
harmony.parse_symbol('Cunrecognised')
|
||||
harmony.parse_symbol('Cunrecognized')
|
||||
def test_transposition_preserves_spelling_octaves_modes(self):
|
||||
for p in ({'letter': 'b', 'alter': 1, 'octave': 4}, {'letter': 'c', 'alter': -1, 'octave': 4}, {'letter': 'f', 'alter': 2, 'octave': 4}):
|
||||
p['alter'] = rational(p['alter'])
|
||||
@@ -101,7 +101,7 @@ class MusicModelTests(unittest.TestCase):
|
||||
for text in ('Med.', 'Med. Swing', 'Medium', 'Medium Swing'):
|
||||
self.assertEqual(canonical_style(text), 'Medium Swing')
|
||||
with self.assertRaises(ValueError):
|
||||
canonical_style('Unrecognised style')
|
||||
canonical_style('Unrecognized style')
|
||||
def test_failure_preserves_generated_assets(self):
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
root = Path(temp)
|
||||
|
||||
@@ -43,7 +43,7 @@ class MusicXMLTests(unittest.TestCase):
|
||||
score = load_musicxml(Path('tests/fixtures/notation.xml'))
|
||||
self.assertEqual(len(score['staves'][0]['measures']), 4)
|
||||
self.assertEqual(len(score['staves'][0]['octave_shifts']), 1)
|
||||
def test_catalogue_imports(self):
|
||||
def test_catalog_imports(self):
|
||||
sources = sorted(Path('data').rglob('*.xml'))
|
||||
self.assertTrue(sources)
|
||||
for path in sources:
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ class PartGenerationTests(unittest.TestCase):
|
||||
(root / 'data' / category).mkdir(parents=True)
|
||||
(root / 'data' / category / (name + '.xml')).write_text(xml_score(xml_harmony() + xml_note()))
|
||||
args = argparse.Namespace(data_dir=root / 'data', output_dir=root / 'output', static_assets_dir=Path('package/assets'), check=False)
|
||||
with patch('generator.arrange.generate.load_musicxml', wraps=load_musicxml) as song_load, patch('generator.practice.generate.load_musicxml', wraps=load_musicxml) as practice_load, patch('generator.parts.concert_document', wraps=concert_document) as normalize, patch('generator.__main__.engrave_tree'), patch('generator.__main__.build_catalogue'), patch('generator.__main__.compile_tree'):
|
||||
with patch('generator.arrange.generate.load_musicxml', wraps=load_musicxml) as song_load, patch('generator.practice.generate.load_musicxml', wraps=load_musicxml) as practice_load, patch('generator.parts.concert_document', wraps=concert_document) as normalize, patch('generator.__main__.engrave_tree'), patch('generator.__main__.build_catalog'), patch('generator.__main__.compile_tree'):
|
||||
generate_assets(args)
|
||||
song_load.assert_called_once()
|
||||
practice_load.assert_called_once()
|
||||
|
||||
@@ -22,7 +22,7 @@ auto playback_score() -> vamp_zero::score_document {
|
||||
}
|
||||
|
||||
auto performance_state() -> vamp_zero::app_state {
|
||||
auto catalog = std::make_shared<vamp_zero::catalogue>();
|
||||
auto catalog = std::make_shared<vamp_zero::catalog>();
|
||||
catalog->performance.parts.push_back({.id = "part", .title = "Song", .part = "Vocal", .total_pages = 2U});
|
||||
catalog->performance.groups.push_back({.title = "Song", .parts = {0U}});
|
||||
auto state = vamp_zero::app_state{};
|
||||
@@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(playback_completion_is_session_guarded) {
|
||||
auto state = vamp_zero::control_state{{}, performance_state()};
|
||||
state.finish_playback(41U);
|
||||
BOOST_CHECK(state.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
||||
state.finish_playback(42U, {}, std::make_shared<vamp_zero::catalogue const>());
|
||||
state.finish_playback(42U, {}, std::make_shared<vamp_zero::catalog const>());
|
||||
BOOST_CHECK(state.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
||||
state.finish_playback(42U, "sample missing");
|
||||
BOOST_CHECK(state.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
||||
@@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(playback_completion_is_session_guarded) {
|
||||
BOOST_CHECK(quiet.snapshot().mode == vamp_zero::app_mode::PERFORMANCE_SCORE);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(playback_worker_discards_cancelled_preparation_and_reports_errors_once) {
|
||||
BOOST_AUTO_TEST_CASE(playback_worker_discards_canceled_preparation_and_reports_errors_once) {
|
||||
auto engine = sonus::engine::create({.no_device = true});
|
||||
BOOST_REQUIRE(engine);
|
||||
auto audio = vamp_zero::audio_controller{{}, std::move(*engine)};
|
||||
|
||||
@@ -158,7 +158,7 @@ class ScoreBundleTests(unittest.TestCase):
|
||||
source['staves'][0]['instruments'] = []
|
||||
with self.assertRaisesRegex(ValueError, 'unknown score instrument'):
|
||||
validate_document(source)
|
||||
def test_catalogue_roundtrip_preserves_written_pitch_and_rhythm(self):
|
||||
def test_catalog_roundtrip_preserves_written_pitch_and_rhythm(self):
|
||||
for path in Path('data').rglob('*.xml'):
|
||||
with self.subTest(path=path):
|
||||
source = load_musicxml(path)
|
||||
|
||||
@@ -64,7 +64,7 @@ struct controlled_scores {
|
||||
struct loader_fixture {
|
||||
boost::asio::io_context io{};
|
||||
std::shared_ptr<controlled_scores> scores{std::make_shared<controlled_scores>(io)};
|
||||
std::shared_ptr<vamp_zero::catalogue const> catalog{std::make_shared<vamp_zero::catalogue const>()};
|
||||
std::shared_ptr<vamp_zero::catalog const> catalog{std::make_shared<vamp_zero::catalog const>()};
|
||||
std::shared_ptr<std::size_t> completions{std::make_shared<std::size_t>()};
|
||||
vamp_zero::score_loader loader{io.get_executor(),
|
||||
[scores = scores](vamp_zero::score_reference reference) { return scores->load(std::move(reference)); },
|
||||
@@ -147,11 +147,11 @@ BOOST_AUTO_TEST_CASE(score_loader_stale_error_does_not_replace_pending_selection
|
||||
BOOST_CHECK_EQUAL(fixture.loader.snapshot().document->id, "available");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(score_loader_catalogue_identity_and_category_invalidate_selection) {
|
||||
BOOST_AUTO_TEST_CASE(score_loader_catalog_identity_and_category_invalidate_selection) {
|
||||
auto fixture = loader_fixture{};
|
||||
fixture.loader.select(fixture.catalog, performance("same-id"));
|
||||
drain(fixture.io);
|
||||
fixture.catalog = std::make_shared<vamp_zero::catalogue const>();
|
||||
fixture.catalog = std::make_shared<vamp_zero::catalog const>();
|
||||
fixture.loader.select(fixture.catalog, performance("same-id"));
|
||||
fixture.scores->complete(0);
|
||||
drain(fixture.io);
|
||||
@@ -279,7 +279,7 @@ BOOST_AUTO_TEST_CASE(score_loader_destruction_during_load_does_not_call_consumer
|
||||
auto loader = vamp_zero::score_loader{io.get_executor(),
|
||||
[scores](vamp_zero::score_reference reference) { return scores->load(std::move(reference)); },
|
||||
[&] { ++completions; }};
|
||||
loader.select(std::make_shared<vamp_zero::catalogue const>(), performance("a"));
|
||||
loader.select(std::make_shared<vamp_zero::catalog const>(), performance("a"));
|
||||
drain(io);
|
||||
BOOST_REQUIRE_EQUAL(scores->requests.size(), 1U);
|
||||
}
|
||||
@@ -301,7 +301,7 @@ BOOST_AUTO_TEST_CASE(score_loader_completion_can_overlap_stop_and_consumer_destr
|
||||
if (auto target = weak.lock()) {
|
||||
++*target;
|
||||
} });
|
||||
loader->select(std::make_shared<vamp_zero::catalogue const>(), performance("a"));
|
||||
loader->select(std::make_shared<vamp_zero::catalog const>(), performance("a"));
|
||||
auto worker = std::thread{[&] { io.run(); }};
|
||||
auto entered_status = entered_future.wait_for(std::chrono::seconds{5});
|
||||
if (entered_status == std::future_status::ready) {
|
||||
@@ -317,7 +317,7 @@ BOOST_AUTO_TEST_CASE(score_loader_completion_can_overlap_stop_and_consumer_destr
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(selected_score_reference_uses_active_part_and_practice_part) {
|
||||
auto catalog = std::make_shared<vamp_zero::catalogue>();
|
||||
auto catalog = std::make_shared<vamp_zero::catalog>();
|
||||
catalog->performance.parts = {{.id = "part-a"}, {.id = "part-b"}};
|
||||
catalog->practice.exercises = {{.id = "scale", .parts = {{.id = "scale-c"}, {.id = "scale-d"}}}};
|
||||
auto state = vamp_zero::app_state{.catalog = catalog};
|
||||
|
||||
Reference in New Issue
Block a user