diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index 215a78c781..d4c8fe71e2 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -47,6 +47,7 @@ asset_obj = qt_env.Object("assets", assets) qt_env.Program("soundd/_soundd", ["soundd/main.cc", "soundd/sound.cc"], LIBS=qt_libs) if GetOption('test'): qt_env.Program("tests/playsound", "tests/playsound.cc", LIBS=base_libs) + qt_env.Program('tests/test_sound', ['tests/test_runner.cc', 'soundd/sound.cc', 'tests/test_sound.cc'], LIBS=[base_libs]) qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs) diff --git a/selfdrive/ui/soundd/.gitignore b/selfdrive/ui/soundd/.gitignore index 5fb1a93459..c47f949d37 100644 --- a/selfdrive/ui/soundd/.gitignore +++ b/selfdrive/ui/soundd/.gitignore @@ -1 +1 @@ -_soundd \ No newline at end of file +_soundd diff --git a/selfdrive/ui/soundd/main.cc b/selfdrive/ui/soundd/main.cc index 209cb4b7ce..64088deff8 100644 --- a/selfdrive/ui/soundd/main.cc +++ b/selfdrive/ui/soundd/main.cc @@ -1,6 +1,9 @@ -#include "selfdrive/ui/soundd/sound.h" +#include + +#include #include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/soundd/sound.h" void sigHandler(int s) { qApp->quit(); diff --git a/selfdrive/ui/soundd/sound.cc b/selfdrive/ui/soundd/sound.cc index a95b9c4658..499e8a1170 100644 --- a/selfdrive/ui/soundd/sound.cc +++ b/selfdrive/ui/soundd/sound.cc @@ -1,5 +1,8 @@ #include "selfdrive/ui/soundd/sound.h" +#include "cereal/messaging/messaging.h" +#include "selfdrive/common/util.h" + // TODO: detect when we can't play sounds // TODO: detect when we can't display the UI @@ -62,49 +65,3 @@ void Sound::setAlert(const QString &alert_type, AudibleAlert sound) { } } } - -// const int test_loop_cnt = 2; - -// void test_sound() { -// PubMaster pm({"controlsState"}); -// const int DT_CTRL = 10; // ms -// for (int i = 0; i < test_loop_cnt; ++i) { -// for (auto &[alert, fn, loops] : sound_list) { -// printf("testing %s\n", qPrintable(fn)); -// for (int j = 0; j < 1000 / DT_CTRL; ++j) { -// MessageBuilder msg; -// auto cs = msg.initEvent().initControlsState(); -// cs.setAlertSound(alert); -// cs.setAlertType(fn.toStdString()); -// pm.send("controlsState", msg); -// QThread::msleep(DT_CTRL); -// } -// } -// } -// QThread::currentThread()->quit(); -// } - -// void run_test(Sound *sound) { -// static QMap> stats; -// for (auto i = sound->sounds.constBegin(); i != sound->sounds.constEnd(); ++i) { -// QObject::connect(i.value().first, &QSoundEffect::playingChanged, [s = i.value().first, a = i.key()]() { -// if (s->isPlaying()) { -// bool repeat = a == AudibleAlert::CHIME_WARNING_REPEAT || a == AudibleAlert::CHIME_WARNING2_REPEAT; -// assert(s->loopsRemaining() == repeat ? QSoundEffect::Infinite : 1); -// stats[a].first++; -// } else { -// stats[a].second++; -// } -// }); -// } - -// QThread *t = new QThread(qApp); -// QObject::connect(t, &QThread::started, [=]() { test_sound(); }); -// QObject::connect(t, &QThread::finished, [&]() { -// for (auto [play, stop] : stats) { -// assert(play == test_loop_cnt && stop == test_loop_cnt); -// } -// qApp->quit(); -// }); -// t->start(); -// } diff --git a/selfdrive/ui/soundd/sound.h b/selfdrive/ui/soundd/sound.h index 41f882c38c..3e417a9c03 100644 --- a/selfdrive/ui/soundd/sound.h +++ b/selfdrive/ui/soundd/sound.h @@ -1,13 +1,7 @@ -#include - -#include +#include #include #include -#include -#include -#include "cereal/messaging/messaging.h" -#include "selfdrive/common/util.h" #include "selfdrive/hardware/hw.h" #include "selfdrive/ui/ui.h" diff --git a/selfdrive/ui/tests/.gitignore b/selfdrive/ui/tests/.gitignore index b80a5b49ce..241f6ef63e 100644 --- a/selfdrive/ui/tests/.gitignore +++ b/selfdrive/ui/tests/.gitignore @@ -1,2 +1,3 @@ test play_sound +test_sound diff --git a/selfdrive/ui/tests/test_runner.cc b/selfdrive/ui/tests/test_runner.cc new file mode 100644 index 0000000000..b20ac86c64 --- /dev/null +++ b/selfdrive/ui/tests/test_runner.cc @@ -0,0 +1,10 @@ +#define CATCH_CONFIG_RUNNER +#include "catch2/catch.hpp" +#include + +int main(int argc, char **argv) { + // unit tests for Qt + QCoreApplication app(argc, argv); + const int res = Catch::Session().run(argc, argv); + return (res < 0xff ? res : 0xff); +} diff --git a/selfdrive/ui/tests/test_sound.cc b/selfdrive/ui/tests/test_sound.cc new file mode 100644 index 0000000000..579867ad2b --- /dev/null +++ b/selfdrive/ui/tests/test_sound.cc @@ -0,0 +1,63 @@ +#include +#include +#include + +#include "catch2/catch.hpp" +#include "selfdrive/ui/soundd/sound.h" + +class TestSound : public Sound { +public: + TestSound() : Sound() { + for (auto i = sounds.constBegin(); i != sounds.constEnd(); ++i) { + QObject::connect(i.value().first, &QSoundEffect::playingChanged, [=, s = i.value().first, a = i.key()]() { + if (s->isPlaying()) { + bool repeat = a == AudibleAlert::CHIME_WARNING_REPEAT || a == AudibleAlert::CHIME_WARNING2_REPEAT; + REQUIRE((s->loopsRemaining() == repeat ? QSoundEffect::Infinite : 1)); + sound_stats[a].first++; + } else { + sound_stats[a].second++; + } + }); + } + } + + QMap> sound_stats; +}; + +void controls_thread(int loop_cnt) { + PubMaster pm({"controlsState"}); + const int DT_CTRL = 10; // ms + for (int i = 0; i < loop_cnt; ++i) { + for (auto &[alert, fn, loops] : sound_list) { + printf("testing %s\n", qPrintable(fn)); + for (int j = 0; j < 1000 / DT_CTRL; ++j) { + MessageBuilder msg; + auto cs = msg.initEvent().initControlsState(); + cs.setAlertSound(alert); + cs.setAlertType(fn.toStdString()); + pm.send("controlsState", msg); + QThread::msleep(DT_CTRL); + } + } + } + QThread::currentThread()->quit(); +} + +TEST_CASE("test sound") { + QEventLoop loop; + + TestSound test_sound; + + const int test_loop_cnt = 2; + QThread t; + QObject::connect(&t, &QThread::started, [=]() { controls_thread(test_loop_cnt); }); + QObject::connect(&t, &QThread::finished, [&]() { loop.quit(); }); + t.start(); + + loop.exec(); + + for (auto [play, stop] : test_sound.sound_stats) { + REQUIRE(play == test_loop_cnt); + REQUIRE(stop == test_loop_cnt); + } +}