From b25fb5f5ca24505cfadedee10d2c5bb9ce1338cf Mon Sep 17 00:00:00 2001 From: Brandon Taylor Date: Mon, 18 Nov 2024 17:41:19 +0000 Subject: [PATCH] combine tests --- src/justly.cpp | 126 ++--- tests/test.cpp | 1279 ++++++++++++++++++------------------------------ 2 files changed, 515 insertions(+), 890 deletions(-) diff --git a/src/justly.cpp b/src/justly.cpp index a4f225be..265fda6f 100644 --- a/src/justly.cpp +++ b/src/justly.cpp @@ -975,19 +975,6 @@ static void set_fluid_int(fluid_settings_t *settings_pointer, const char *field, Q_ASSERT(result == FLUID_OK); } -[[nodiscard]] static auto get_settings_pointer() { - fluid_settings_t *settings_pointer = new_fluid_settings(); - Q_ASSERT(settings_pointer != nullptr); - auto cores = std::thread::hardware_concurrency(); - if (cores > 0) { - set_fluid_int(settings_pointer, "synth.cpu-cores", static_cast(cores)); - } -#ifdef __linux__ - fluid_settings_setstr(settings_pointer, "audio.driver", "pulseaudio"); -#endif - return settings_pointer; -} - struct Chord : public Row { const Instrument *instrument_pointer = nullptr; const PercussionSet *percussion_set_pointer = nullptr; @@ -1231,38 +1218,6 @@ struct Song { CONCERT_A_MIDI; }; -[[nodiscard]] static auto get_note_text(int degree) { - switch (degree) { - case c_degree: - return "C"; - case c_sharp_degree: - return "C♯"; - case d_degree: - return "D"; - case e_flat_degree: - return "E♭"; - case e_degree: - return "E"; - case f_degree: - return "F"; - case f_sharp_degree: - return "F♯"; - case g_degree: - return "G"; - case a_flat_degree: - return "A♭"; - case a_degree: - return "A"; - case b_flat_degree: - return "B♭"; - case b_degree: - return "B"; - default: - Q_ASSERT(false); - return ""; - } -} - [[nodiscard]] static auto get_key_text(const Song &song, int chord_number, double ratio = 1) { const auto &chords = song.chords; @@ -1282,7 +1237,37 @@ struct Song { QString result; QTextStream stream(&result); - stream << key << QObject::tr(" Hz; ") << QObject::tr(get_note_text(degree)) + stream << key << QObject::tr(" Hz; ") << QObject::tr([](int degree) { + switch (degree) { + case c_degree: + return "C"; + case c_sharp_degree: + return "C♯"; + case d_degree: + return "D"; + case e_flat_degree: + return "E♭"; + case e_degree: + return "E"; + case f_degree: + return "F"; + case f_sharp_degree: + return "F♯"; + case g_degree: + return "G"; + case a_flat_degree: + return "A♭"; + case a_degree: + return "A"; + case b_flat_degree: + return "B♭"; + case b_degree: + return "B"; + default: + Q_ASSERT(false); + return ""; + } + }(degree)) << octave; if (cents != 0) { stream << QObject::tr(cents >= 0 ? " + " : " − ") << abs(cents) @@ -1356,7 +1341,19 @@ static void start_real_time(Player &player) { Player::Player(QWidget &parent_input) : parent(parent_input), channel_schedules(QList(NUMBER_OF_MIDI_CHANNELS, 0)), - settings_pointer(get_settings_pointer()), + settings_pointer([]() { + fluid_settings_t *settings_pointer = new_fluid_settings(); + Q_ASSERT(settings_pointer != nullptr); + auto cores = std::thread::hardware_concurrency(); + if (cores > 0) { + set_fluid_int(settings_pointer, "synth.cpu-cores", + static_cast(cores)); + } +#ifdef __linux__ + fluid_settings_setstr(settings_pointer, "audio.driver", "pulseaudio"); +#endif + return settings_pointer; + }()), event_pointer(new_fluid_event()), sequencer_pointer(new_fluid_sequencer2(0)), synth_pointer(new_fluid_synth(settings_pointer)), @@ -1370,7 +1367,6 @@ Player::Player(QWidget &parent_input) Player::~Player() { delete_audio_driver(*this); delete_fluid_event(event_pointer); - delete_fluid_sequencer(sequencer_pointer); delete_fluid_synth(synth_pointer); delete_fluid_settings(settings_pointer); } @@ -1560,12 +1556,6 @@ static void play_chords(Player &player, const Song &song, } } -static void set_fluid_string(fluid_settings_t *settings_pointer, - const char *field, const char *value) { - auto result = fluid_settings_setstr(settings_pointer, field, value); - Q_ASSERT(result == FLUID_OK); -} - static void export_song_to_file(Player &player, const Song &song, const QString &output_file) { auto *settings_pointer = player.settings_pointer; @@ -1574,8 +1564,9 @@ static void export_song_to_file(Player &player, const Song &song, stop_playing(player); delete_audio_driver(player); - set_fluid_string(settings_pointer, "audio.file.name", - output_file.toStdString().c_str()); + auto file_result = fluid_settings_setstr(settings_pointer, "audio.file.name", + output_file.toStdString().c_str()); + Q_ASSERT(file_result == FLUID_OK); set_fluid_int(settings_pointer, "synth.lock-memory", 0); @@ -1679,11 +1670,6 @@ struct RowsModel : public QAbstractTableModel { return uneditable; }; - [[nodiscard]] virtual auto - is_column_editable(int /*column_number*/) const -> bool { - return true; - }; - [[nodiscard]] virtual auto get_status(int /*row_number*/) const -> QString { return ""; }; @@ -2111,16 +2097,6 @@ auto PitchedNote::get_program(const Player &player, int chord_number, ". Using Marimba."); } -static void player_play_pitched_notes(Player &player, const Song &song, - int chord_number, int first_note_number, - int number_of_notes) { - modulate_before_chord(player, song, chord_number); - const auto &chord = song.chords.at(chord_number); - modulate(player, chord); - play_notes(player, chord_number, chord.pitched_notes, first_note_number, - number_of_notes); -}; - [[nodiscard]] static auto get_selection_model(const QTableView &table_view) -> QItemSelectionModel & { return get_reference(table_view.selectionModel()); @@ -2484,14 +2460,6 @@ static void delete_cells(SongEditor &song_editor) { } } -[[nodiscard]] static auto -get_required_object_schema(const nlohmann::json &required_json, - const nlohmann::json &properties_json) { - return nlohmann::json({{"type", "object"}, - {"required", required_json}, - {"properties", properties_json}}); -}; - template SubRow> [[nodiscard]] static auto parse_clipboard(QWidget &parent) { const auto &mime_data = get_const_reference(get_clipboard().mimeData()); diff --git a/tests/test.cpp b/tests/test.cpp index 628851d5..54ea311b 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -314,16 +314,6 @@ static void clear_selection(QItemSelectionModel &selector) { selector.select(QModelIndex(), QItemSelectionModel::Clear); } -[[nodiscard]] static auto get_indices(QAbstractItemModel &model, - int item_number, int number_of_columns) { - std::vector indices; - for (auto column_number = 0; column_number < number_of_columns; - column_number = column_number + 1) { - indices.push_back(model.index(item_number, column_number)); - } - return indices; -} - [[nodiscard]] static auto get_index_pairs(QAbstractItemModel &model, int first_row_number, int second_row_number, @@ -362,23 +352,72 @@ static void open_text(SongEditor *song_editor_pointer, open_file(song_editor_pointer, json_file.fileName()); } -static void test_column_flags_editable(const QAbstractItemModel &model, - int column, bool is_editable) { - auto uneditable_flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; - QCOMPARE(model.index(0, column).flags(), - is_editable ? (uneditable_flags | Qt::ItemIsEditable) - : uneditable_flags); -} - static void test_number_of_columns(const QAbstractItemModel &model, int number_of_columns) { QCOMPARE(model.columnCount(), number_of_columns); } -static void test_set_values(const SongEditor *song_editor_pointer, - const std::vector &rows) { +struct Tester : public QObject { + Q_OBJECT + +public: + bool waiting_for_message = false; + +private slots: + void run_tests(); +}; + +static void close_message_later(Tester &tester, const QString &expected_text) { + auto waiting_before = tester.waiting_for_message; + tester.waiting_for_message = true; + auto &timer = // NOLINT(cppcoreguidelines-owning-memory) + *(new QTimer(&tester)); + timer.setSingleShot(true); + QObject::connect( + &timer, &QTimer::timeout, &tester, [&tester, expected_text]() { + for (auto *const widget_pointer : QApplication::topLevelWidgets()) { + auto *box_pointer = dynamic_cast(widget_pointer); + if (box_pointer != nullptr) { + auto actual_text = box_pointer->text(); + tester.waiting_for_message = false; + QTest::keyEvent(QTest::Press, box_pointer, Qt::Key_Enter); + QCOMPARE(actual_text, expected_text); + break; + } + } + }); + timer.start(WAIT_TIME); + QVERIFY(!waiting_before); +}; + +static void test_model(Tester &tester, SongEditor *song_editor_pointer, + QAbstractItemModel &model, + const std::vector &column_header_rows, + const std::vector &flag_rows, + const std::vector &play_rows, + const std::vector &bad_paste_rows, + int empty_row_number, int full_row_number, + int number_of_columns, int max_set_column) { + for (const auto &row : column_header_rows) { + QCOMPARE(model.headerData(row.column_number, Qt::Horizontal), + row.column_name); + } + + auto uneditable_flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + auto editable_flags = uneditable_flags | Qt::ItemIsEditable; + + for (const auto &row : flag_rows) { + auto uneditable_flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + QCOMPARE(model.index(0, row.column_number).flags(), + row.is_editable ? editable_flags : uneditable_flags); + } + + QCOMPARE(model.index(0, 0).data(Qt::DecorationRole), QVariant()); + QVERIFY(!(model.setData(model.index(0, 1), QVariant(), Qt::DecorationRole))); + const auto &table_view = get_table_view(song_editor_pointer); - for (const auto &row : rows) { + for (const auto &row : get_index_pairs(model, empty_row_number, + full_row_number, max_set_column)) { const auto ©_index = row.first_index; const auto &paste_index = row.second_index; @@ -398,42 +437,23 @@ static void test_set_values(const SongEditor *song_editor_pointer, undo(song_editor_pointer); QCOMPARE(paste_index.data(), paste_value); } -} - -static void test_get_unsupported_role(const QAbstractItemModel &model) { - QCOMPARE(model.index(0, 0).data(Qt::DecorationRole), QVariant()); -} -static void test_set_unsupported_role(QAbstractItemModel &model) { - QVERIFY(!(model.setData(model.index(0, 1), QVariant(), Qt::DecorationRole))); -}; - -static void test_column_headers(const QAbstractItemModel &model, - const std::vector &rows) { - for (const auto &row : rows) { - QCOMPARE(model.headerData(row.column_number, Qt::Horizontal), - row.column_name); - } -} - -static void test_delete_cells(SongEditor *song_editor_pointer, - const std::vector &indices) { - for (const auto &index : indices) { - const auto &old_value = index.data(); + for (auto column_number = 0; column_number < number_of_columns; + column_number = column_number + 1) { + auto delete_index = model.index(full_row_number, column_number); + const auto &old_value = delete_index.data(); - delete_cell(song_editor_pointer, index); + delete_cell(song_editor_pointer, delete_index); - QCOMPARE_NE(index.data(), old_value); + QCOMPARE_NE(delete_index.data(), old_value); undo(song_editor_pointer); - QCOMPARE(index.data(), old_value); + QCOMPARE(delete_index.data(), old_value); } -} -static void test_copy_paste_cells(SongEditor *song_editor_pointer, - const std::vector &rows) { auto &selector = get_selector(get_table_view(song_editor_pointer)); - for (const auto &row : rows) { + for (const auto &row : get_index_pairs(model, empty_row_number, + full_row_number, number_of_columns)) { const auto ©_index = row.first_index; const auto &paste_index = row.second_index; @@ -454,13 +474,9 @@ static void test_copy_paste_cells(SongEditor *song_editor_pointer, undo(song_editor_pointer); QCOMPARE(paste_index.data(), paste_value); } -} - -static void test_cut_paste_cells(SongEditor *song_editor_pointer, - const std::vector &rows) { - auto &selector = get_selector(get_table_view(song_editor_pointer)); - for (const auto &row : rows) { + for (const auto &row : get_index_pairs(model, full_row_number, + empty_row_number, number_of_columns)) { const auto &cut_index = row.first_index; const auto &paste_index = row.second_index; @@ -484,11 +500,7 @@ static void test_cut_paste_cells(SongEditor *song_editor_pointer, undo(song_editor_pointer); QCOMPARE(cut_index.data(), cut_value); } -} -static void test_copy_paste_insert_rows(SongEditor *song_editor_pointer, - QAbstractItemModel &model) { - auto &selector = get_selector(get_table_view(song_editor_pointer)); selector.select(model.index(0, 0), QItemSelectionModel::Select); trigger_copy(song_editor_pointer); clear_selection(selector); @@ -505,26 +517,16 @@ static void test_copy_paste_insert_rows(SongEditor *song_editor_pointer, undo(song_editor_pointer); QCOMPARE(model.rowCount(), number_of_rows); clear_selection(selector); -} - -static void test_insert_into(SongEditor *song_editor_pointer, - QAbstractItemModel &model) { - auto &selector = get_selector(get_table_view(song_editor_pointer)); auto chord_index = model.index(0, chord_interval_column); - auto old_row_count = model.rowCount(chord_index); + auto old_child_row_count = model.rowCount(chord_index); selector.select(chord_index, QItemSelectionModel::Select); trigger_insert_into(song_editor_pointer); clear_selection(selector); - QCOMPARE(model.rowCount(chord_index), old_row_count + 1); + QCOMPARE(model.rowCount(chord_index), old_child_row_count + 1); undo(song_editor_pointer); - QCOMPARE(model.rowCount(chord_index), old_row_count); -} - -static void test_insert_after(SongEditor *song_editor_pointer, - QAbstractItemModel &model) { - auto &selector = get_selector(get_table_view(song_editor_pointer)); + QCOMPARE(model.rowCount(chord_index), old_child_row_count); auto index = model.index(0, 0); auto old_row_count = model.rowCount(); @@ -536,27 +538,16 @@ static void test_insert_after(SongEditor *song_editor_pointer, QCOMPARE(model.rowCount(), old_row_count + 1); undo(song_editor_pointer); QCOMPARE(model.rowCount(), old_row_count); -} -static void test_remove_rows(SongEditor *song_editor_pointer, - QAbstractItemModel &model) { - auto &selector = get_selector(get_table_view(song_editor_pointer)); - - auto index = model.index(0, 0); - auto old_row_count = model.rowCount(); - - selector.select(index, QItemSelectionModel::Select); + selector.select(model.index(0, 0), QItemSelectionModel::Select); trigger_remove_rows(song_editor_pointer); clear_selection(selector); QCOMPARE(model.rowCount(), old_row_count - 1); undo(song_editor_pointer); QCOMPARE(model.rowCount(), old_row_count); -} -static void test_plays(SongEditor *song_editor_pointer, - const std::vector &rows) { - for (const auto &row : rows) { + for (const auto &row : play_rows) { auto &selector = get_selector(get_table_view(song_editor_pointer)); selector.select(QItemSelection(row.first_index, row.second_index), @@ -570,777 +561,443 @@ static void test_plays(SongEditor *song_editor_pointer, clear_selection(selector); } -} -struct Tester : public QObject { - Q_OBJECT + auto bad_paste_index = model.index(0, 0); -public: - SongEditor *const song_editor_pointer; + for (const auto &row : bad_paste_rows) { + auto *new_data_pointer = // NOLINT(cppcoreguidelines-owning-memory) + new QMimeData; - bool waiting_for_message = false; + Q_ASSERT(new_data_pointer != nullptr); + new_data_pointer->setData(row.mime_type, row.copied.toStdString().c_str()); - Tester() : song_editor_pointer(make_song_editor()){}; - ~Tester() override { delete_song_editor(song_editor_pointer); }; + auto *clipboard_pointer = QGuiApplication::clipboard(); + Q_ASSERT(clipboard_pointer != nullptr); + clipboard_pointer->setMimeData(new_data_pointer); - // prevent moving and copying - Tester(const Tester &) = delete; - auto operator=(const Tester &) -> Tester = delete; - Tester(Tester &&) = delete; - auto operator=(Tester &&) -> Tester = delete; + selector.select(bad_paste_index, QItemSelectionModel::Select); + close_message_later(tester, row.error_message); + trigger_paste_over(song_editor_pointer); + clear_selection(selector); + } +}; - void test_bad_pastes(const QModelIndex &index, - const std::vector &rows) { - auto &selector = get_selector(get_table_view(song_editor_pointer)); +void Tester::run_tests() { + set_up(); + + auto *song_editor_pointer = make_song_editor(); + open_text(song_editor_pointer, SONG_TEXT); + + auto &chords_model = get_chords_model(song_editor_pointer); + auto &pitched_notes_model = get_pitched_notes_model(song_editor_pointer); + auto &unpitched_notes_model = get_unpitched_notes_model(song_editor_pointer); + + for (const auto &row : std::vector({ + ToStringRow({chords_model.index(0, chord_instrument_column), ""}), + ToStringRow( + {chords_model.index(0, chord_percussion_set_column), ""}), + ToStringRow( + {chords_model.index(0, chord_percussion_instrument_column), ""}), + ToStringRow({chords_model.index(0, chord_interval_column), ""}), + ToStringRow({chords_model.index(1, chord_interval_column), "3"}), + ToStringRow({chords_model.index(2, chord_interval_column), "/2"}), + ToStringRow({chords_model.index(3, chord_interval_column), "3/2"}), + ToStringRow({chords_model.index(4, chord_interval_column), "o1"}), + ToStringRow({chords_model.index(5, chord_interval_column), "3o1"}), + ToStringRow({chords_model.index(6, chord_interval_column), "/2o1"}), + ToStringRow({chords_model.index(7, chord_interval_column), "3/2o1"}), + ToStringRow({chords_model.index(0, chord_beats_column), ""}), + ToStringRow({chords_model.index(1, chord_beats_column), "3"}), + ToStringRow({chords_model.index(2, chord_beats_column), "/2"}), + ToStringRow({chords_model.index(3, chord_beats_column), "3/2"}), + })) { + QCOMPARE(row.index.data().toString(), row.text); + } - for (const auto &row : rows) { - auto *new_data_pointer = // NOLINT(cppcoreguidelines-owning-memory) - new QMimeData; - - Q_ASSERT(new_data_pointer != nullptr); - new_data_pointer->setData(row.mime_type, - row.copied.toStdString().c_str()); - - auto *clipboard_pointer = QGuiApplication::clipboard(); - Q_ASSERT(clipboard_pointer != nullptr); - clipboard_pointer->setMimeData(new_data_pointer); - - selector.select(index, QItemSelectionModel::Select); - close_message_later(row.error_message); - trigger_paste_over(song_editor_pointer); - clear_selection(selector); - } - }; - - void close_message_later(const QString &expected_text) { - auto waiting_before = waiting_for_message; - waiting_for_message = true; - auto &timer = // NOLINT(cppcoreguidelines-owning-memory) - *(new QTimer(this)); - timer.setSingleShot(true); - connect(&timer, &QTimer::timeout, this, [this, expected_text]() { - for (auto *const widget_pointer : QApplication::topLevelWidgets()) { - auto *box_pointer = dynamic_cast(widget_pointer); - if (box_pointer != nullptr) { - auto actual_text = box_pointer->text(); - waiting_for_message = false; - QTest::keyEvent(QTest::Press, box_pointer, Qt::Key_Enter); - QCOMPARE(actual_text, expected_text); - break; - } - } - }); - timer.start(WAIT_TIME); - QVERIFY(!waiting_before); - }; -private slots: - void initTestCase() const { - set_up(); - open_text(song_editor_pointer, SONG_TEXT); - }; - - void test_to_strings() const { - const auto &chords_model = get_chords_model(song_editor_pointer); - for (const auto &row : std::vector({ - ToStringRow({chords_model.index(0, chord_instrument_column), ""}), - ToStringRow( - {chords_model.index(0, chord_percussion_set_column), ""}), - ToStringRow( - {chords_model.index(0, chord_percussion_instrument_column), - ""}), - ToStringRow({chords_model.index(0, chord_interval_column), ""}), - ToStringRow({chords_model.index(1, chord_interval_column), "3"}), - ToStringRow({chords_model.index(2, chord_interval_column), "/2"}), - ToStringRow({chords_model.index(3, chord_interval_column), "3/2"}), - ToStringRow({chords_model.index(4, chord_interval_column), "o1"}), - ToStringRow({chords_model.index(5, chord_interval_column), "3o1"}), - ToStringRow( - {chords_model.index(6, chord_interval_column), "/2o1"}), - ToStringRow( - {chords_model.index(7, chord_interval_column), "3/2o1"}), - ToStringRow({chords_model.index(0, chord_beats_column), ""}), - ToStringRow({chords_model.index(1, chord_beats_column), "3"}), - ToStringRow({chords_model.index(2, chord_beats_column), "/2"}), - ToStringRow({chords_model.index(3, chord_beats_column), "3/2"}), - })) { - QCOMPARE(row.index.data().toString(), row.text); - } - }; - - void test_chords_count() const { - QCOMPARE(get_chords_model(song_editor_pointer).rowCount(), 8); - }; - void test_pitched_notes_count() const { - const auto &pitched_notes_model = - get_pitched_notes_model(song_editor_pointer); - for (const auto &row : - std::vector({CountRow({0, 0}), CountRow({1, 8}), CountRow({2, 0}), - CountRow({3, 0}), CountRow({4, 0}), CountRow({5, 0}), - CountRow({6, 0}), CountRow({7, 0})})) { - trigger_edit_pitched_notes(song_editor_pointer, row.chord_number); - QCOMPARE(pitched_notes_model.rowCount(), row.number); - undo(song_editor_pointer); - } - }; - void test_unpitched_notes_count() const { - const auto &unpitched_notes_model = - get_unpitched_notes_model(song_editor_pointer); - for (const auto &row : - std::vector({CountRow({0, 0}), CountRow({1, 4}), CountRow({2, 0}), - CountRow({3, 0}), CountRow({4, 0}), CountRow({5, 0}), - CountRow({6, 0}), CountRow({7, 0})})) { - trigger_edit_unpitched_notes(song_editor_pointer, row.chord_number); - QCOMPARE(unpitched_notes_model.rowCount(), row.number); - undo(song_editor_pointer); - } - }; - void test_back_to_chords() const { - trigger_edit_unpitched_notes(song_editor_pointer, 0); - trigger_back_to_chords(song_editor_pointer); - undo(song_editor_pointer); - undo(song_editor_pointer); - }; - - void test_number_of_chord_columns() const { - test_number_of_columns(get_chords_model(song_editor_pointer), - number_of_chord_columns); - }; - void test_number_of_pitched_note_columns() const { - test_number_of_columns(get_pitched_notes_model(song_editor_pointer), - number_of_pitched_note_columns); - }; - void test_number_of_unpitched_note_columns() const { - test_number_of_columns(get_unpitched_notes_model(song_editor_pointer), - number_of_unpitched_note_columns); - }; - - void test_gain_control() const { - auto old_gain = get_gain(song_editor_pointer); - QCOMPARE_NE(old_gain, NEW_GAIN_1); - QCOMPARE_NE(old_gain, NEW_GAIN_2); - - set_gain(song_editor_pointer, NEW_GAIN_1); - QCOMPARE(get_gain(song_editor_pointer), NEW_GAIN_1); - set_gain(song_editor_pointer, NEW_GAIN_2); - QCOMPARE(get_gain(song_editor_pointer), NEW_GAIN_2); + QCOMPARE(chords_model.rowCount(), 8); + for (const auto &row : + std::vector({CountRow({0, 0}), CountRow({1, 8}), CountRow({2, 0}), + CountRow({3, 0}), CountRow({4, 0}), CountRow({5, 0}), + CountRow({6, 0}), CountRow({7, 0})})) { + trigger_edit_pitched_notes(song_editor_pointer, row.chord_number); + QCOMPARE(pitched_notes_model.rowCount(), row.number); undo(song_editor_pointer); - QCOMPARE(get_gain(song_editor_pointer), old_gain); - }; - void test_starting_key_control() const { - auto old_key = get_starting_key(song_editor_pointer); - QCOMPARE_NE(old_key, STARTING_KEY_1); - QCOMPARE_NE(old_key, STARTING_KEY_2); - - // test combining - set_starting_key(song_editor_pointer, STARTING_KEY_1); - QCOMPARE(get_starting_key(song_editor_pointer), STARTING_KEY_1); - set_starting_key(song_editor_pointer, STARTING_KEY_2); - QCOMPARE(get_starting_key(song_editor_pointer), STARTING_KEY_2); - undo(song_editor_pointer); - QCOMPARE(get_starting_key(song_editor_pointer), old_key); - }; - void test_starting_velocity_control() const { - auto old_velocity = get_starting_velocity(song_editor_pointer); - QCOMPARE_NE(old_velocity, STARTING_VELOCITY_1); - QCOMPARE_NE(old_velocity, STARTING_VELOCITY_2); - - // test combining - set_starting_velocity(song_editor_pointer, STARTING_VELOCITY_1); - QCOMPARE(get_starting_velocity(song_editor_pointer), STARTING_VELOCITY_1); - set_starting_velocity(song_editor_pointer, STARTING_VELOCITY_2); - QCOMPARE(get_starting_velocity(song_editor_pointer), STARTING_VELOCITY_2); - undo(song_editor_pointer); - QCOMPARE(get_starting_velocity(song_editor_pointer), old_velocity); - }; - void test_starting_tempo_control() const { - auto old_tempo = get_starting_tempo(song_editor_pointer); - - // test combining - set_starting_tempo(song_editor_pointer, STARTING_TEMPO_1); - QCOMPARE(get_starting_tempo(song_editor_pointer), STARTING_TEMPO_1); - set_starting_tempo(song_editor_pointer, STARTING_TEMPO_2); - QCOMPARE(get_starting_tempo(song_editor_pointer), STARTING_TEMPO_2); - undo(song_editor_pointer); - QCOMPARE(get_starting_tempo(song_editor_pointer), old_tempo); - }; - - void test_row_headers() const { - const auto &chords_model = get_chords_model(song_editor_pointer); - QCOMPARE(chords_model.headerData(0, Qt::Vertical), QVariant(1)); - QCOMPARE(chords_model.headerData(0, Qt::Vertical, Qt::DecorationRole), - QVariant()); - }; - void test_chord_column_headers() const { - test_column_headers( - get_chords_model(song_editor_pointer), - std::vector( - {HeaderRow({chord_instrument_column, "Instrument"}), - HeaderRow({chord_percussion_set_column, "Percussion set"}), - HeaderRow( - {chord_percussion_instrument_column, "Percussion instrument"}), - HeaderRow({chord_interval_column, "Interval"}), - HeaderRow({chord_beats_column, "Beats"}), - HeaderRow({chord_velocity_ratio_column, "Velocity ratio"}), - HeaderRow({chord_tempo_ratio_column, "Tempo ratio"}), - HeaderRow({chord_words_column, "Words"}), - HeaderRow({chord_pitched_notes_column, "Pitched notes"}), - HeaderRow({chord_unpitched_notes_column, "Unpitched notes"})})); - }; - void test_pitched_note_column_headers() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_column_headers( - get_pitched_notes_model(song_editor_pointer), - std::vector( - {HeaderRow({pitched_note_instrument_column, "Instrument"}), - HeaderRow({pitched_note_interval_column, "Interval"}), - HeaderRow({pitched_note_beats_column, "Beats"}), - HeaderRow({pitched_note_velocity_ratio_column, "Velocity ratio"}), - HeaderRow({pitched_note_words_column, "Words"})})); - undo(song_editor_pointer); - }; - void test_unpitched_note_column_headers() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_column_headers( - get_unpitched_notes_model(song_editor_pointer), - std::vector({HeaderRow({unpitched_note_percussion_set_column, - "Percussion set"}), - HeaderRow({unpitched_note_percussion_instrument_column, - "Percussion instrument"}), - HeaderRow({unpitched_note_beats_column, "Beats"}), - HeaderRow({unpitched_note_velocity_ratio_column, - "Velocity ratio"}), - HeaderRow({unpitched_note_words_column, "Words"})})); - undo(song_editor_pointer); - }; - - void test_chord_flags() const { - const auto &chords_model = get_chords_model(song_editor_pointer); - for (const auto &row : - std::vector({FlagRow({chord_interval_column, true}), - FlagRow({chord_pitched_notes_column, false}), - FlagRow({chord_unpitched_notes_column, false})})) { - test_column_flags_editable(chords_model, row.column_number, - row.is_editable); - } - }; - void test_pitched_note_flags() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_column_flags_editable(get_pitched_notes_model(song_editor_pointer), - pitched_note_interval_column, true); - undo(song_editor_pointer); - }; - void test_unpitched_note_flags() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_column_flags_editable(get_unpitched_notes_model(song_editor_pointer), - unpitched_note_percussion_set_column, true); - undo(song_editor_pointer); - }; - - void test_chord_frequencies() const { - const auto &chords_model = get_chords_model(song_editor_pointer); - for (const auto &row : std::vector({ - FrequencyRow({A_MINUS_FREQUENCY, "217 Hz; A3 − 24 cents"}), - FrequencyRow({A_PLUS_FREQUENCY, "223 Hz; A3 + 23 cents"}), - FrequencyRow({A_FREQUENCY, "220 Hz; A3"}), - FrequencyRow({B_FLAT_FREQUENCY, "233 Hz; B♭3 − 1 cents"}), - FrequencyRow({B_FREQUENCY, "247 Hz; B3"}), - FrequencyRow({C_FREQUENCY, "262 Hz; C4 + 2 cents"}), - FrequencyRow({C_SHARP_FREQUENCY, "277 Hz; C♯4 − 1 cents"}), - FrequencyRow({D_FREQUENCY, "294 Hz; D4 + 2 cents"}), - FrequencyRow({E_FLAT_FREQUENCY, "311 Hz; E♭4 − 1 cents"}), - FrequencyRow({E_FREQUENCY, "330 Hz; E4 + 2 cents"}), - FrequencyRow({F_FREQUENCY, "349 Hz; F4 − 1 cents"}), - FrequencyRow({F_SHARP_FREQUENCY, "370 Hz; F♯4"}), - FrequencyRow({G_FREQUENCY, "392 Hz; G4"}), - FrequencyRow({A_FLAT_FREQUENCY, "415 Hz; A♭4 − 1 cents"}), - })) { - set_starting_key(song_editor_pointer, row.frequency); - QCOMPARE( - chords_model.index(0, chord_interval_column).data(Qt::StatusTipRole), - row.text); - undo(song_editor_pointer); - } - }; - void test_pitched_note_frequencies() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - set_starting_key(song_editor_pointer, A_FREQUENCY); - QCOMPARE(get_pitched_notes_model(song_editor_pointer) - .index(0, chord_interval_column) - .data(Qt::StatusTipRole), - "660 Hz; E5 + 2 cents"); - undo(song_editor_pointer); - undo(song_editor_pointer); - }; - void test_unpitched_status() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - QCOMPARE(get_unpitched_notes_model(song_editor_pointer) - .index(0, chord_interval_column) - .data(Qt::StatusTipRole), - ""); - undo(song_editor_pointer); - }; - - void test_get_unsupported_chord_role() const { - test_get_unsupported_role(get_chords_model(song_editor_pointer)); - }; - void test_get_unsupported_pitched_note_role() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_get_unsupported_role(get_pitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - void test_get_unsupported_unpitched_note_role() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_get_unsupported_role(get_unpitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - - void test_set_unsupported_chord_role() const { - test_set_unsupported_role(get_chords_model(song_editor_pointer)); - }; - void test_set_unsupported_pitched_note_role() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_set_unsupported_role(get_pitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - void test_set_unsupported_unpitched_note_role() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_set_unsupported_role(get_unpitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - - void test_set_chord_values() const { - test_set_values(song_editor_pointer, - get_index_pairs(get_chords_model(song_editor_pointer), 0, 1, - number_of_chord_columns - 2)); - }; - void test_set_pitched_note_values() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_set_values( - song_editor_pointer, - get_index_pairs(get_pitched_notes_model(song_editor_pointer), 0, 1, - number_of_pitched_note_columns)); - undo(song_editor_pointer); - }; - void test_set_unpitched_note_values() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_set_values( - song_editor_pointer, - get_index_pairs(get_unpitched_notes_model(song_editor_pointer), 0, 1, - number_of_unpitched_note_columns)); - undo(song_editor_pointer); - }; - - void test_delete_chord_cells() const { - test_delete_cells(song_editor_pointer, - get_indices(get_chords_model(song_editor_pointer), 1, - number_of_chord_columns)); - }; - void test_delete_pitched_note_cells() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_delete_cells(song_editor_pointer, - get_indices(get_pitched_notes_model(song_editor_pointer), - 1, number_of_pitched_note_columns)); - undo(song_editor_pointer); - }; - void test_delete_unpitched_note_cells() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_delete_cells( - song_editor_pointer, - get_indices(get_unpitched_notes_model(song_editor_pointer), 1, - number_of_unpitched_note_columns)); - undo(song_editor_pointer); - }; - - void test_copy_paste_chord_cells() const { - test_copy_paste_cells(song_editor_pointer, - get_index_pairs(get_chords_model(song_editor_pointer), - 0, 1, number_of_chord_columns)); - }; - void test_copy_paste_pitched_note_cells() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_copy_paste_cells( - song_editor_pointer, - get_index_pairs(get_pitched_notes_model(song_editor_pointer), 0, 1, - number_of_pitched_note_columns)); - undo(song_editor_pointer); - }; - void test_copy_paste_unpitched_note_cells() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_copy_paste_cells( - song_editor_pointer, - get_index_pairs(get_unpitched_notes_model(song_editor_pointer), 0, 1, - number_of_unpitched_note_columns)); - undo(song_editor_pointer); - }; - - void test_cut_paste_chord_cells() const { - test_cut_paste_cells(song_editor_pointer, - get_index_pairs(get_chords_model(song_editor_pointer), - 1, 0, number_of_chord_columns)); - }; - void test_cut_paste_pitched_note_cells() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_cut_paste_cells( - song_editor_pointer, - get_index_pairs(get_pitched_notes_model(song_editor_pointer), 1, 0, - number_of_pitched_note_columns)); - undo(song_editor_pointer); - }; - void test_cut_paste_unpitched_note_cells() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_cut_paste_cells( - song_editor_pointer, - get_index_pairs(get_unpitched_notes_model(song_editor_pointer), 1, 0, - number_of_unpitched_note_columns)); - undo(song_editor_pointer); - }; - - void test_copy_paste_insert_chord() const { - test_copy_paste_insert_rows(song_editor_pointer, - get_chords_model(song_editor_pointer)); - }; - void test_copy_paste_insert_pitched_note() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_copy_paste_insert_rows(song_editor_pointer, - get_pitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - void test_copy_paste_insert_unpitched_note() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_copy_paste_insert_rows(song_editor_pointer, - get_unpitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - - void test_chord_insert_into() const { - test_insert_into(song_editor_pointer, - get_chords_model(song_editor_pointer)); - }; - void test_pitched_note_insert_into() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_insert_into(song_editor_pointer, - get_pitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - void test_unpitched_note_insert_into() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_insert_into(song_editor_pointer, - get_unpitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - - void test_chord_insert_after() const { - test_insert_after(song_editor_pointer, - get_chords_model(song_editor_pointer)); - }; - void test_pitched_note_insert_after() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_insert_after(song_editor_pointer, - get_pitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - void test_unpitched_note_insert_after() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_insert_after(song_editor_pointer, - get_unpitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - - void test_chord_remove_rows() const { - test_remove_rows(song_editor_pointer, - get_chords_model(song_editor_pointer)); - }; - void test_pitched_note_remove_rows() const { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_remove_rows(song_editor_pointer, - get_pitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - void test_unpitched_note_remove_rows() const { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_remove_rows(song_editor_pointer, - get_unpitched_notes_model(song_editor_pointer)); - undo(song_editor_pointer); - }; - - void test_bad_chord_pastes() { - test_bad_pastes( - get_chords_model(song_editor_pointer).index(0, 0), - std::vector( - {BadPasteRow({"", "not a mime", - "Cannot paste not a mime into destination needing " - "chords cells"}), - BadPasteRow( - {"", PITCHED_NOTES_CELLS_MIME, - "Cannot paste pitched notes cells into destination needing " - "chords cells"}), - BadPasteRow( - {"[", CHORDS_CELLS_MIME, - "[json.exception.parse_error.101] parse error at line 1, " - "column 2: syntax error while parsing value - unexpected end " - "of input; expected '[', '{', or a literal"}), - BadPasteRow({"[]", CHORDS_CELLS_MIME, "Nothing to paste!"}), - BadPasteRow({"{\"a\": 1}", CHORDS_CELLS_MIME, - "At of {\"a\":1} - required property 'left_column' " - "not found in object\n"})})); - }; - void test_bad_pitched_note_pastes() { - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_bad_pastes( - get_pitched_notes_model(song_editor_pointer).index(0, 0), - std::vector( - {BadPasteRow({"", "not a mime", - "Cannot paste not a mime into destination needing " - "pitched notes cells"}), - BadPasteRow({"", CHORDS_CELLS_MIME, - "Cannot paste chords cells into destination needing " - "pitched notes cells"}), - BadPasteRow( - {"[", PITCHED_NOTES_CELLS_MIME, - "[json.exception.parse_error.101] parse error at line 1, " - "column 2: syntax error while parsing value - unexpected end " - "of input; expected '[', '{', or a literal"}), - BadPasteRow({"[]", PITCHED_NOTES_CELLS_MIME, "Nothing to paste!"}), - BadPasteRow({"{\"a\": 1}", PITCHED_NOTES_CELLS_MIME, - "At of {\"a\":1} - required property 'left_column' " - "not found in object\n"})})); - undo(song_editor_pointer); - }; - void test_bad_unpitched_note_pastes() { - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_bad_pastes( - get_unpitched_notes_model(song_editor_pointer).index(0, 0), - std::vector( - {BadPasteRow({"", "not a mime", - "Cannot paste not a mime into destination needing " - "unpitched notes cells"}), - BadPasteRow({"", CHORDS_CELLS_MIME, - "Cannot paste chords cells into destination needing " - "unpitched notes cells"}), - BadPasteRow( - {"[", UNPITCHED_NOTES_CELLS_MIME, - "[json.exception.parse_error.101] parse error at line 1, " - "column 2: syntax error while parsing value - unexpected end " - "of input; expected '[', '{', or a literal"}), - BadPasteRow( - {"[]", UNPITCHED_NOTES_CELLS_MIME, "Nothing to paste!"}), - BadPasteRow({"{\"a\": 1}", UNPITCHED_NOTES_CELLS_MIME, - "At of {\"a\":1} - required property 'left_column' " - "not found in object\n"})})); + } + + for (const auto &row : + std::vector({CountRow({0, 0}), CountRow({1, 4}), CountRow({2, 0}), + CountRow({3, 0}), CountRow({4, 0}), CountRow({5, 0}), + CountRow({6, 0}), CountRow({7, 0})})) { + trigger_edit_unpitched_notes(song_editor_pointer, row.chord_number); + QCOMPARE(unpitched_notes_model.rowCount(), row.number); undo(song_editor_pointer); - }; + } - void test_too_loud() { - trigger_edit_pitched_notes(song_editor_pointer, 1); + trigger_edit_unpitched_notes(song_editor_pointer, 0); + trigger_back_to_chords(song_editor_pointer); + undo(song_editor_pointer); + undo(song_editor_pointer); - set_starting_velocity(song_editor_pointer, BIG_VELOCITY); + test_number_of_columns(chords_model, number_of_chord_columns); + test_number_of_columns(pitched_notes_model, number_of_pitched_note_columns); + test_number_of_columns(unpitched_notes_model, + number_of_unpitched_note_columns); - close_message_later( - "Velocity 378 exceeds 127 for chord 2, pitched note 1. Playing " - "with velocity 127"); + auto old_gain = get_gain(song_editor_pointer); + QCOMPARE_NE(old_gain, NEW_GAIN_1); + QCOMPARE_NE(old_gain, NEW_GAIN_2); - play_cell(song_editor_pointer, get_pitched_notes_model(song_editor_pointer) - .index(0, pitched_note_interval_column)); + set_gain(song_editor_pointer, NEW_GAIN_1); + QCOMPARE(get_gain(song_editor_pointer), NEW_GAIN_1); + set_gain(song_editor_pointer, NEW_GAIN_2); + QCOMPARE(get_gain(song_editor_pointer), NEW_GAIN_2); - QThread::msleep(WAIT_TIME); - trigger_stop_playing(song_editor_pointer); - undo(song_editor_pointer); + undo(song_editor_pointer); + QCOMPARE(get_gain(song_editor_pointer), old_gain); + + auto old_key = get_starting_key(song_editor_pointer); + QCOMPARE_NE(old_key, STARTING_KEY_1); + QCOMPARE_NE(old_key, STARTING_KEY_2); + + // test combining + set_starting_key(song_editor_pointer, STARTING_KEY_1); + QCOMPARE(get_starting_key(song_editor_pointer), STARTING_KEY_1); + set_starting_key(song_editor_pointer, STARTING_KEY_2); + QCOMPARE(get_starting_key(song_editor_pointer), STARTING_KEY_2); + undo(song_editor_pointer); + QCOMPARE(get_starting_key(song_editor_pointer), old_key); + + auto old_velocity = get_starting_velocity(song_editor_pointer); + QCOMPARE_NE(old_velocity, STARTING_VELOCITY_1); + QCOMPARE_NE(old_velocity, STARTING_VELOCITY_2); + // test combining + set_starting_velocity(song_editor_pointer, STARTING_VELOCITY_1); + QCOMPARE(get_starting_velocity(song_editor_pointer), STARTING_VELOCITY_1); + set_starting_velocity(song_editor_pointer, STARTING_VELOCITY_2); + QCOMPARE(get_starting_velocity(song_editor_pointer), STARTING_VELOCITY_2); + undo(song_editor_pointer); + QCOMPARE(get_starting_velocity(song_editor_pointer), old_velocity); + + auto old_tempo = get_starting_tempo(song_editor_pointer); + + // test combining + set_starting_tempo(song_editor_pointer, STARTING_TEMPO_1); + QCOMPARE(get_starting_tempo(song_editor_pointer), STARTING_TEMPO_1); + set_starting_tempo(song_editor_pointer, STARTING_TEMPO_2); + QCOMPARE(get_starting_tempo(song_editor_pointer), STARTING_TEMPO_2); + undo(song_editor_pointer); + QCOMPARE(get_starting_tempo(song_editor_pointer), old_tempo); + + QCOMPARE(chords_model.headerData(0, Qt::Vertical), QVariant(1)); + QCOMPARE(chords_model.headerData(0, Qt::Vertical, Qt::DecorationRole), + QVariant()); + + for (const auto &row : std::vector({ + FrequencyRow({A_MINUS_FREQUENCY, "217 Hz; A3 − 24 cents"}), + FrequencyRow({A_PLUS_FREQUENCY, "223 Hz; A3 + 23 cents"}), + FrequencyRow({A_FREQUENCY, "220 Hz; A3"}), + FrequencyRow({B_FLAT_FREQUENCY, "233 Hz; B♭3 − 1 cents"}), + FrequencyRow({B_FREQUENCY, "247 Hz; B3"}), + FrequencyRow({C_FREQUENCY, "262 Hz; C4 + 2 cents"}), + FrequencyRow({C_SHARP_FREQUENCY, "277 Hz; C♯4 − 1 cents"}), + FrequencyRow({D_FREQUENCY, "294 Hz; D4 + 2 cents"}), + FrequencyRow({E_FLAT_FREQUENCY, "311 Hz; E♭4 − 1 cents"}), + FrequencyRow({E_FREQUENCY, "330 Hz; E4 + 2 cents"}), + FrequencyRow({F_FREQUENCY, "349 Hz; F4 − 1 cents"}), + FrequencyRow({F_SHARP_FREQUENCY, "370 Hz; F♯4"}), + FrequencyRow({G_FREQUENCY, "392 Hz; G4"}), + FrequencyRow({A_FLAT_FREQUENCY, "415 Hz; A♭4 − 1 cents"}), + })) { + set_starting_key(song_editor_pointer, row.frequency); + QCOMPARE( + chords_model.index(0, chord_interval_column).data(Qt::StatusTipRole), + row.text); undo(song_editor_pointer); - }; - void test_too_many_channels() { - trigger_edit_pitched_notes(song_editor_pointer, 2); + } - for (auto number = 0; number < OVERLOAD_NUMBER; number = number + 1) { - trigger_insert_into(song_editor_pointer); - } + trigger_edit_pitched_notes(song_editor_pointer, 1); + set_starting_key(song_editor_pointer, A_FREQUENCY); + QCOMPARE(pitched_notes_model.index(0, chord_interval_column) + .data(Qt::StatusTipRole), + "660 Hz; E5 + 2 cents"); + undo(song_editor_pointer); + undo(song_editor_pointer); - trigger_back_to_chords(song_editor_pointer); + trigger_edit_unpitched_notes(song_editor_pointer, 1); + QCOMPARE(unpitched_notes_model.index(0, chord_interval_column) + .data(Qt::StatusTipRole), + ""); + undo(song_editor_pointer); - close_message_later( - "Out of MIDI channels for chord 3, pitched note 17. Not " - "playing note."); + test_model( + *this, song_editor_pointer, chords_model, + std::vector( + {HeaderRow({chord_instrument_column, "Instrument"}), + HeaderRow({chord_percussion_set_column, "Percussion set"}), + HeaderRow( + {chord_percussion_instrument_column, "Percussion instrument"}), + HeaderRow({chord_interval_column, "Interval"}), + HeaderRow({chord_beats_column, "Beats"}), + HeaderRow({chord_velocity_ratio_column, "Velocity ratio"}), + HeaderRow({chord_tempo_ratio_column, "Tempo ratio"}), + HeaderRow({chord_words_column, "Words"}), + HeaderRow({chord_pitched_notes_column, "Pitched notes"}), + HeaderRow({chord_unpitched_notes_column, "Unpitched notes"})}), + std::vector({FlagRow({chord_interval_column, true}), + FlagRow({chord_pitched_notes_column, false}), + FlagRow({chord_unpitched_notes_column, false})}), + std::vector({ + TwoIndicesRow({chords_model.index(0, chord_interval_column), + chords_model.index(1, chord_interval_column)}), + TwoIndicesRow({chords_model.index(1, chord_interval_column), + chords_model.index(1, chord_interval_column)}), + }), + std::vector( + {BadPasteRow({"", "not a mime", + "Cannot paste not a mime into destination needing " + "chords cells"}), + BadPasteRow( + {"", PITCHED_NOTES_CELLS_MIME, + "Cannot paste pitched notes cells into destination needing " + "chords cells"}), + BadPasteRow( + {"[", CHORDS_CELLS_MIME, + "[json.exception.parse_error.101] parse error at line 1, " + "column 2: syntax error while parsing value - unexpected end " + "of input; expected '[', '{', or a literal"}), + BadPasteRow({"[]", CHORDS_CELLS_MIME, "Nothing to paste!"}), + BadPasteRow({"{\"a\": 1}", CHORDS_CELLS_MIME, + "At of {\"a\":1} - required property 'left_column' " + "not found in object\n"})}), + 0, 1, number_of_chord_columns, number_of_chord_columns - 2); + + trigger_edit_pitched_notes(song_editor_pointer, 1); + test_model( + *this, song_editor_pointer, pitched_notes_model, + std::vector( + {HeaderRow({pitched_note_instrument_column, "Instrument"}), + HeaderRow({pitched_note_interval_column, "Interval"}), + HeaderRow({pitched_note_beats_column, "Beats"}), + HeaderRow({pitched_note_velocity_ratio_column, "Velocity ratio"}), + HeaderRow({pitched_note_words_column, "Words"})}), + std::vector({FlagRow({pitched_note_interval_column, true})}), + std::vector({ + TwoIndicesRow( + {pitched_notes_model.index(0, pitched_note_interval_column), + pitched_notes_model.index(1, pitched_note_interval_column)}), + TwoIndicesRow( + {pitched_notes_model.index(1, pitched_note_interval_column), + pitched_notes_model.index(1, pitched_note_interval_column)}), + }), + std::vector( + {BadPasteRow({"", "not a mime", + "Cannot paste not a mime into destination needing " + "pitched notes cells"}), + BadPasteRow({"", CHORDS_CELLS_MIME, + "Cannot paste chords cells into destination needing " + "pitched notes cells"}), + BadPasteRow( + {"[", PITCHED_NOTES_CELLS_MIME, + "[json.exception.parse_error.101] parse error at line 1, " + "column 2: syntax error while parsing value - unexpected end " + "of input; expected '[', '{', or a literal"}), + BadPasteRow({"[]", PITCHED_NOTES_CELLS_MIME, "Nothing to paste!"}), + BadPasteRow({"{\"a\": 1}", PITCHED_NOTES_CELLS_MIME, + "At of {\"a\":1} - required property 'left_column' " + "not found in object\n"})}), + 0, 1, number_of_pitched_note_columns, number_of_pitched_note_columns); + undo(song_editor_pointer); - play_cell( - song_editor_pointer, - get_chords_model(song_editor_pointer).index(2, chord_interval_column)); + trigger_edit_unpitched_notes(song_editor_pointer, 1); + test_model( + *this, song_editor_pointer, unpitched_notes_model, + std::vector( + {HeaderRow({unpitched_note_percussion_set_column, "Percussion set"}), + HeaderRow({unpitched_note_percussion_instrument_column, + "Percussion instrument"}), + HeaderRow({unpitched_note_beats_column, "Beats"}), + HeaderRow({unpitched_note_velocity_ratio_column, "Velocity ratio"}), + HeaderRow({unpitched_note_words_column, "Words"})}), + std::vector({FlagRow({unpitched_note_percussion_set_column, true})}), + std::vector({ + TwoIndicesRow({unpitched_notes_model.index( + 0, unpitched_note_percussion_set_column), + unpitched_notes_model.index( + 1, unpitched_note_percussion_set_column)}), + TwoIndicesRow({unpitched_notes_model.index( + 1, unpitched_note_percussion_set_column), + unpitched_notes_model.index( + 1, unpitched_note_percussion_set_column)}), + }), + std::vector( + {BadPasteRow({"", "not a mime", + "Cannot paste not a mime into destination needing " + "unpitched notes cells"}), + BadPasteRow({"", CHORDS_CELLS_MIME, + "Cannot paste chords cells into destination needing " + "unpitched notes cells"}), + BadPasteRow( + {"[", UNPITCHED_NOTES_CELLS_MIME, + "[json.exception.parse_error.101] parse error at line 1, " + "column 2: syntax error while parsing value - unexpected end " + "of input; expected '[', '{', or a literal"}), + BadPasteRow({"[]", UNPITCHED_NOTES_CELLS_MIME, "Nothing to paste!"}), + BadPasteRow({"{\"a\": 1}", UNPITCHED_NOTES_CELLS_MIME, + "At of {\"a\":1} - required property 'left_column' " + "not found in object\n"})}), + 0, 1, number_of_unpitched_note_columns, number_of_unpitched_note_columns); + undo(song_editor_pointer); - QThread::msleep(WAIT_TIME); - trigger_stop_playing(song_editor_pointer); + trigger_edit_pitched_notes(song_editor_pointer, 1); - // undo back to chords - undo(song_editor_pointer); + set_starting_velocity(song_editor_pointer, BIG_VELOCITY); - for (auto index = 0; index < OVERLOAD_NUMBER; index = index + 1) { - undo(song_editor_pointer); - } + close_message_later( + *this, "Velocity 378 exceeds 127 for chord 2, pitched note 1. Playing " + "with velocity 127"); - // undo edit pitched_notes - undo(song_editor_pointer); - }; - void test_missing_instruments() { - auto &chords_model = get_chords_model(song_editor_pointer); - auto &pitched_notes_model = get_pitched_notes_model(song_editor_pointer); - auto &unpitched_notes_model = - get_unpitched_notes_model(song_editor_pointer); - - delete_cell(song_editor_pointer, - chords_model.index(1, chord_instrument_column)); - delete_cell(song_editor_pointer, - chords_model.index(1, chord_percussion_set_column)); - delete_cell(song_editor_pointer, - chords_model.index(1, chord_percussion_instrument_column)); - - trigger_edit_pitched_notes(song_editor_pointer, 1); - - delete_cell(song_editor_pointer, - pitched_notes_model.index(0, pitched_note_instrument_column)); - QCOMPARE( - pitched_notes_model - .data(pitched_notes_model.index(0, pitched_note_instrument_column)) - .toString(), - ""); - close_message_later( - "No instrument for chord 2, pitched note 1. Using Marimba."); - - play_cell(song_editor_pointer, - pitched_notes_model.index(0, pitched_note_instrument_column)); + play_cell(song_editor_pointer, + pitched_notes_model.index(0, pitched_note_interval_column)); - // undo delete pitched_note instrument - undo(song_editor_pointer); - // undo edit pitched_notes - undo(song_editor_pointer); + QThread::msleep(WAIT_TIME); + trigger_stop_playing(song_editor_pointer); + undo(song_editor_pointer); - trigger_edit_unpitched_notes(song_editor_pointer, 1); + undo(song_editor_pointer); - delete_cell( - song_editor_pointer, - unpitched_notes_model.index(0, unpitched_note_percussion_set_column)); + trigger_edit_pitched_notes(song_editor_pointer, 2); - close_message_later( - "No percussion set for chord 2, unpitched note 1. Using Standard."); + for (auto number = 0; number < OVERLOAD_NUMBER; number = number + 1) { + trigger_insert_into(song_editor_pointer); + } - play_cell( - song_editor_pointer, - unpitched_notes_model.index(0, unpitched_note_percussion_set_column)); - // undo edit delete unpitched_note set - undo(song_editor_pointer); + trigger_back_to_chords(song_editor_pointer); - delete_cell(song_editor_pointer, - unpitched_notes_model.index( - 0, unpitched_note_percussion_instrument_column)); + close_message_later(*this, + "Out of MIDI channels for chord 3, pitched note 17. Not " + "playing note."); - close_message_later("No percussion instrument for chord 2, " - "unpitched note 1. Using Tambourine."); + play_cell(song_editor_pointer, chords_model.index(2, chord_interval_column)); - play_cell( - song_editor_pointer, - unpitched_notes_model.index(0, unpitched_note_percussion_set_column)); - // undo delete unpitched_note instrument - undo(song_editor_pointer); - // undo edit unpitched_notes - undo(song_editor_pointer); - // undo delete chord unpitched_note instrument - undo(song_editor_pointer); - // undo delete chord unpitched_note set - undo(song_editor_pointer); - // undo delete chord instrument - undo(song_editor_pointer); - }; - - void test_chord_plays() const { - const auto &chords_model = get_chords_model(song_editor_pointer); - test_plays( - song_editor_pointer, - std::vector({ - TwoIndicesRow({chords_model.index(0, chord_interval_column), - chords_model.index(1, chord_interval_column)}), - TwoIndicesRow({chords_model.index(1, chord_interval_column), - chords_model.index(1, chord_interval_column)}), - })); - }; - void test_pitched_note_plays() const { - const auto &pitched_notes_model = - get_pitched_notes_model(song_editor_pointer); - trigger_edit_pitched_notes(song_editor_pointer, 1); - test_plays( - song_editor_pointer, - std::vector({ - TwoIndicesRow( - {pitched_notes_model.index(0, pitched_note_interval_column), - pitched_notes_model.index(1, pitched_note_interval_column)}), - TwoIndicesRow( - {pitched_notes_model.index(1, pitched_note_interval_column), - pitched_notes_model.index(1, pitched_note_interval_column)}), - })); - undo(song_editor_pointer); - }; - void test_unpitched_note_plays() const { - const auto &unpitched_notes_model = - get_unpitched_notes_model(song_editor_pointer); - trigger_edit_unpitched_notes(song_editor_pointer, 1); - test_plays( - song_editor_pointer, - std::vector({ - TwoIndicesRow({unpitched_notes_model.index( - 0, unpitched_note_percussion_set_column), - unpitched_notes_model.index( - 1, unpitched_note_percussion_set_column)}), - TwoIndicesRow({unpitched_notes_model.index( - 1, unpitched_note_percussion_set_column), - unpitched_notes_model.index( - 1, unpitched_note_percussion_set_column)}), - })); + QThread::msleep(WAIT_TIME); + trigger_stop_playing(song_editor_pointer); + + // undo back to chords + undo(song_editor_pointer); + + for (auto index = 0; index < OVERLOAD_NUMBER; index = index + 1) { undo(song_editor_pointer); - }; + } + + // undo edit pitched_notes + undo(song_editor_pointer); - void test_save() const { - QTemporaryFile temp_json_file; - QVERIFY(temp_json_file.open()); - temp_json_file.close(); - auto file_name = temp_json_file.fileName(); - save_as_file(song_editor_pointer, file_name); + delete_cell(song_editor_pointer, + chords_model.index(1, chord_instrument_column)); + delete_cell(song_editor_pointer, + chords_model.index(1, chord_percussion_set_column)); + delete_cell(song_editor_pointer, + chords_model.index(1, chord_percussion_instrument_column)); - QCOMPARE(get_current_file(song_editor_pointer), file_name); + trigger_edit_pitched_notes(song_editor_pointer, 1); - QVERIFY(temp_json_file.open()); - auto written = QString(temp_json_file.readAll()); - temp_json_file.close(); + delete_cell(song_editor_pointer, + pitched_notes_model.index(0, pitched_note_instrument_column)); + QCOMPARE( + pitched_notes_model + .data(pitched_notes_model.index(0, pitched_note_instrument_column)) + .toString(), + ""); + close_message_later( + *this, "No instrument for chord 2, pitched note 1. Using Marimba."); + + play_cell(song_editor_pointer, + pitched_notes_model.index(0, pitched_note_instrument_column)); + + // undo delete pitched_note instrument + undo(song_editor_pointer); + // undo edit pitched_notes + undo(song_editor_pointer); + + trigger_edit_unpitched_notes(song_editor_pointer, 1); + + delete_cell( + song_editor_pointer, + unpitched_notes_model.index(0, unpitched_note_percussion_set_column)); + + close_message_later( + *this, + "No percussion set for chord 2, unpitched note 1. Using Standard."); + + play_cell(song_editor_pointer, unpitched_notes_model.index( + 0, unpitched_note_percussion_set_column)); + // undo edit delete unpitched_note set + undo(song_editor_pointer); + + delete_cell(song_editor_pointer, + unpitched_notes_model.index( + 0, unpitched_note_percussion_instrument_column)); + + close_message_later(*this, "No percussion instrument for chord 2, " + "unpitched note 1. Using Tambourine."); + + play_cell(song_editor_pointer, unpitched_notes_model.index( + 0, unpitched_note_percussion_set_column)); + // undo delete unpitched_note instrument + undo(song_editor_pointer); + // undo edit unpitched_notes + undo(song_editor_pointer); + // undo delete chord unpitched_note instrument + undo(song_editor_pointer); + // undo delete chord unpitched_note set + undo(song_editor_pointer); + // undo delete chord instrument + undo(song_editor_pointer); + + QTemporaryFile temp_json_file; + QVERIFY(temp_json_file.open()); + temp_json_file.close(); + auto file_name = temp_json_file.fileName(); + save_as_file(song_editor_pointer, file_name); + + QCOMPARE(get_current_file(song_editor_pointer), file_name); + + QVERIFY(temp_json_file.open()); + auto written = QString(temp_json_file.readAll()); + temp_json_file.close(); // different encoding on windows or something #ifndef _WIN32 - QCOMPARE(written, SONG_TEXT); + QCOMPARE(written, SONG_TEXT); #endif - trigger_save(song_editor_pointer); - }; - void test_export() const { - QTemporaryFile temp_json_file; - QVERIFY(temp_json_file.open()); - temp_json_file.close(); - export_to_file(song_editor_pointer, temp_json_file.fileName()); - }; - void test_broken_file() { - for (const auto &row : std::vector({ - TwoStringsRow( - {"{", - "[json.exception.parse_error.101] parse error at line 1, " - "column 2: syntax error while parsing object key - " - "unexpected end of input; expected string literal"}), - TwoStringsRow({"[]", "At of [] - unexpected instance type\n"}), - TwoStringsRow({"[1]", "At of [1] - unexpected instance type\n"}), - })) { - close_message_later(row.second_string); - open_text(song_editor_pointer, row.first_string); - } - }; - void test_open_empty() const { - open_text(song_editor_pointer, R""""({ + trigger_save(song_editor_pointer); + + QTemporaryFile temp_export_file; + QVERIFY(temp_export_file.open()); + temp_export_file.close(); + export_to_file(song_editor_pointer, temp_export_file.fileName()); + + for (const auto &row : std::vector({ + TwoStringsRow( + {"{", "[json.exception.parse_error.101] parse error at line 1, " + "column 2: syntax error while parsing object key - " + "unexpected end of input; expected string literal"}), + TwoStringsRow({"[]", "At of [] - unexpected instance type\n"}), + TwoStringsRow({"[1]", "At of [1] - unexpected instance type\n"}), + })) { + close_message_later(*this, row.second_string); + open_text(song_editor_pointer, row.first_string); + } + + open_text(song_editor_pointer, R""""({ "gain": 5.0, "starting_key": 220, "starting_tempo": 200, "starting_velocity": 64 })""""); - }; + + delete_song_editor(song_editor_pointer); }; QTEST_MAIN(Tester);