From b106eb528ea5f4067e03e1b0cb6d3f7ebd3c13f2 Mon Sep 17 00:00:00 2001 From: Fernando da Silva Sousa Date: Sun, 10 Dec 2023 03:59:14 -0300 Subject: [PATCH] Add tests and refator --- meson/find_unit_test_sources.sh | 2 +- src/Application.vala | 3 +- src/Core/Lyric.vala | 2 +- src/Core/LyricsService.vala | 46 +++++++++------ tests/MockClass.vala | 10 ++++ tests/MockMethod.vala | 42 ++++++++++++++ tests/mocks/FileMock.vala | 13 +++++ tests/mocks/PlayerMock.vala | 21 +++++++ tests/mocks/RepositoryMock.vala | 15 +++++ tests/unit/Core/LyricsServiceTest.vala | 80 ++++++++++++++++++++++++++ tests/unit/main.vala | 1 + 11 files changed, 214 insertions(+), 21 deletions(-) create mode 100644 tests/MockClass.vala create mode 100644 tests/MockMethod.vala create mode 100644 tests/mocks/FileMock.vala create mode 100644 tests/mocks/PlayerMock.vala create mode 100644 tests/mocks/RepositoryMock.vala create mode 100644 tests/unit/Core/LyricsServiceTest.vala diff --git a/meson/find_unit_test_sources.sh b/meson/find_unit_test_sources.sh index 8b1ad75..28a9a3a 100644 --- a/meson/find_unit_test_sources.sh +++ b/meson/find_unit_test_sources.sh @@ -1,5 +1,5 @@ #!/bin/sh find ./src -type f -name "*.vala" ! -name "main.vala" > /tmp/lyrics_build_source.txt -find ./tests/unit -type f -name "*.vala" > /tmp/lyrics_build_test_sources.txt +find ./tests -type f -name "*.vala" > /tmp/lyrics_build_test_sources.txt cat /tmp/lyrics_build_source.txt /tmp/lyrics_build_test_sources.txt diff --git a/src/Application.vala b/src/Application.vala index 9434e34..db8f0a1 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -59,7 +59,8 @@ public class Lyrics.Application : Gtk.Application { var syncedLyrics = new SyncedLyrics.Shim(); syncedLyrics.install(); - lyrics_service = new LyricsService (); + var repository = new Repository (); + lyrics_service = new LyricsService (repository); players = new Players (); } diff --git a/src/Core/Lyric.vala b/src/Core/Lyric.vala index 8899f30..b8b2b90 100644 --- a/src/Core/Lyric.vala +++ b/src/Core/Lyric.vala @@ -1,5 +1,5 @@ -public class Lyrics.Lyric { +public class Lyrics.Lyric : Object { private Gee.HashMap metadata = new Gee.HashMap (); private Gee.BidirMapIterator lrc_iterator; private Gee.TreeMap treemap; diff --git a/src/Core/LyricsService.vala b/src/Core/LyricsService.vala index 3b23218..ad4df3d 100644 --- a/src/Core/LyricsService.vala +++ b/src/Core/LyricsService.vala @@ -1,12 +1,22 @@ public class Lyrics.LyricsService : Object { public State state { get; set; } - IRepository lyric_repository = new Repository (); + IRepository lyric_repository; public Lyric? lyric { get; set; } + public LyricsService (IRepository repository) { + lyric_repository = repository; + state = State.UNKNOWN; + } + public void set_player (Player player) { GLib.MainLoop loop = new GLib.MainLoop (); + + if (player.current_song == null) { + state = State.UNKNOWN; + return; + } + request_lyric.begin (player.current_song, () => { - request_lyric (player.current_song); loop.quit (); }); loop.run (); @@ -17,22 +27,6 @@ public class Lyrics.LyricsService : Object { state = State.DOWNLOADED; } - private async void request_lyric (Metasong song) { - state = State.DOWNLOADING; - - var lyricfile = lyric_repository.find_first (song); - - if (lyricfile != null) { - lyric = lyricfile.to_lyric (); - state = State.DOWNLOADED; - return; - } - - state = State.LYRICS_NOT_FOUND; - - lyric = null; - } - public enum State { UNKNOWN, DOWNLOADING, @@ -54,4 +48,20 @@ public class Lyrics.LyricsService : Object { } } } + + private async void request_lyric (Metasong song) { + state = State.DOWNLOADING; + + var lyricfile = lyric_repository.find_first (song); + + if (lyricfile != null) { + lyric = lyricfile.to_lyric (); + state = State.DOWNLOADED; + return; + } + + state = State.LYRICS_NOT_FOUND; + + lyric = null; + } } diff --git a/tests/MockClass.vala b/tests/MockClass.vala new file mode 100644 index 0000000..f4be5eb --- /dev/null +++ b/tests/MockClass.vala @@ -0,0 +1,10 @@ +using GLib; + +public abstract class MockClass : Object { + public MockMethod should_call (string method_name) { + GLib.Value value = GLib.Value (typeof (MockMethod)); + var prop = (method_name + "_mock"); + this.get_property (prop, ref value); + return value.get_object () as MockMethod; + } +} diff --git a/tests/MockMethod.vala b/tests/MockMethod.vala new file mode 100644 index 0000000..aa3548b --- /dev/null +++ b/tests/MockMethod.vala @@ -0,0 +1,42 @@ +public errordomain ExpectationFailed { + METHOD_NOT_CALLED, + METHOD_CALLED_TOO_MANY_TIMES, +} + +public class MockMethod : Object { + int expected = 0; + int executed_count = 0; + + ~MockMethod () { + if (executed_count < expected) { + throw new ExpectationFailed.METHOD_NOT_CALLED("Method not called"); + } + } + + public void call () throws ExpectationFailed { + debug ("MockMethod.call()"); + + if (executed_count >= expected) { + throw new ExpectationFailed.METHOD_CALLED_TOO_MANY_TIMES("Method called too many times"); + } + + executed_count = executed_count + 1; + } + + public MockMethod never () { + return times(0); + } + + public MockMethod once () { + return times(1); + } + + public MockMethod twice () { + return times(2); + } + + public MockMethod times (int times) { + expected = expected + 1; + return this; + } +} diff --git a/tests/mocks/FileMock.vala b/tests/mocks/FileMock.vala new file mode 100644 index 0000000..7e8cf73 --- /dev/null +++ b/tests/mocks/FileMock.vala @@ -0,0 +1,13 @@ +public class FileMock : MockClass, Lyrics.ILyricFile { + public string? get_metadata (string attribute_name) { + assert_not_reached (); + } + + public string get_content () { + assert_not_reached (); + } + + public Lyrics.Lyric to_lyric () { + assert_not_reached (); + } +} diff --git a/tests/mocks/PlayerMock.vala b/tests/mocks/PlayerMock.vala new file mode 100644 index 0000000..03f086c --- /dev/null +++ b/tests/mocks/PlayerMock.vala @@ -0,0 +1,21 @@ + +public class PlayerMock : MockClass, Lyrics.Player { + public int64 position { get; } + public Lyrics.Metasong current_song { get; set; } + public Lyrics.Player.State state { get; protected set; } + public string busname { get; protected set; } + public string? identity { get; protected set; } + + public void toggle_play_pause () { + assert_not_reached (); + } + + public void previous () { + assert_not_reached (); + } + + public void next () { + assert_not_reached (); + } + +} diff --git a/tests/mocks/RepositoryMock.vala b/tests/mocks/RepositoryMock.vala new file mode 100644 index 0000000..8620bac --- /dev/null +++ b/tests/mocks/RepositoryMock.vala @@ -0,0 +1,15 @@ + +public class RepositoryMock : MockClass, Lyrics.IRepository { + protected MockMethod find_first_mock { get; set; default = new MockMethod ();} + protected MockMethod find_mock { get; set; default = new MockMethod ();} + + public Lyrics.ILyricFile? find_first (Lyrics.Metasong song) { + find_first_mock.call (); + return null; + } + + public Gee.Collection? find (Lyrics.Metasong song) { + find_mock.call (); + return null; + } +} diff --git a/tests/unit/Core/LyricsServiceTest.vala b/tests/unit/Core/LyricsServiceTest.vala new file mode 100644 index 0000000..f8bbee4 --- /dev/null +++ b/tests/unit/Core/LyricsServiceTest.vala @@ -0,0 +1,80 @@ +using Lyrics; + +public class Unit.Core.LyricsServiceTest : Unit.TestCase { + protected override void setup () { + // + } + + protected override void teardown () { + // + } + + public LyricsServiceTest() { + register ("/test_can_instantiate_lyrics_service", test_can_instantiate_lyrics_service); + register ("/test_set_player_null_song", test_set_player_null_song); + register ("/test_set_player_with_song", test_set_player_with_song); + } + + void test_can_instantiate_lyrics_service() { + var mock_repository = new RepositoryMock (); + var lyrics_service = new LyricsService(mock_repository); + + assert_cmpstr ( + lyrics_service.state.to_string (), + GLib.CompareOperator.EQ, + LyricsService.State.UNKNOWN.to_string () + ); + } + + void test_set_player_null_song() { + var player = new PlayerMock (); + var mock_repository = new RepositoryMock (); + var lyrics_service = new LyricsService(mock_repository); + + lyrics_service.set_player (player); + + assert_cmpstr ( + lyrics_service.state.to_string (), + GLib.CompareOperator.EQ, + LyricsService.State.UNKNOWN.to_string () + ); + } + + void test_set_player_with_song() { + var song = new Metasong (); + var player = new PlayerMock (); + var mock_repository = new RepositoryMock (); + var lyrics_service = new LyricsService(mock_repository); + + mock_repository + .should_call ("find_first") + .never (); + + player.current_song = song; + + LyricsService.State[] state_change = { + LyricsService.State.DOWNLOADING, + LyricsService.State.LYRICS_NOT_FOUND, + }; + + uint state_changed_count = 0; + + lyrics_service.notify["state"].connect ((sender, state) => { + assert_cmpstr ( + lyrics_service.state.to_string (), + GLib.CompareOperator.EQ, + state_change[state_changed_count].to_string () + ); + + state_changed_count = state_changed_count + 1; + }); + + lyrics_service.set_player (player); + + while (lyrics_service.state != LyricsService.State.LYRICS_NOT_FOUND) { + // wait for the state to change + } + + assert_cmpuint(state_changed_count, GLib.CompareOperator.EQ, 2); + } +} diff --git a/tests/unit/main.vala b/tests/unit/main.vala index b2594fb..ae45c82 100644 --- a/tests/unit/main.vala +++ b/tests/unit/main.vala @@ -2,6 +2,7 @@ int main (string[] args) { Test.init (ref args); new Unit.Core.LyricTest(); + new Unit.Core.LyricsServiceTest (); new Unit.Parser.LrcParserTest (); return Test.run ();