use of com.simplecity.amp_library.model.Song in project Shuttle by timusus.
the class ShuttleUtilsTest method testIncrementPlayCount.
@Test
public void testIncrementPlayCount() throws Exception {
Context mockContext = mock(Context.class);
ContentResolver mockContentResolver = mock(ContentResolver.class);
Song fakeSong = new Song(mock(Cursor.class));
fakeSong.id = 100L;
fakeSong.playCount = 50;
// getPlayCount has extra logic to conduct SQL Queries, which would be a pain to mock in a test
// so, we can use a Spy here in order to use both fake data (above) plus control return behaviors (below)
Song spySong = spy(fakeSong);
doReturn(50).when(spySong).getPlayCount(any(Context.class));
when(mockContext.getContentResolver()).thenReturn(mockContentResolver);
// Setup to perform the method call on a song with no play counts
when(mockContentResolver.update(any(Uri.class), any(ContentValues.class), anyString(), any(String[].class))).thenReturn(0);
// Call the method and capture the ContentValues object
ArgumentCaptor<ContentValues> contentValuesCaptor = new ArgumentCaptor<>();
ShuttleUtils.incrementPlayCount(mockContext, spySong);
verify(mockContentResolver).update(any(Uri.class), contentValuesCaptor.capture(), anyString(), any(String[].class));
// Check that the values being updated or inserted match the actual song
ContentValues values = contentValuesCaptor.getValue();
assertThat(values.get("_id")).isEqualTo(100L);
assertThat(values.get("play_count")).isEqualTo(51);
verify(mockContentResolver).insert(any(Uri.class), eq(values));
// Next, test what happens with a song that already had play counts (should not cause an insert operation)
reset(mockContentResolver);
when(mockContentResolver.update(any(Uri.class), contentValuesCaptor.capture(), anyString(), any(String[].class))).thenReturn(1);
ShuttleUtils.incrementPlayCount(mockContext, spySong);
verify(mockContentResolver, never()).insert(any(Uri.class), any(ContentValues.class));
}
use of com.simplecity.amp_library.model.Song in project Shuttle by timusus.
the class OperatorsUnitTest method testSongsToAlbums.
@Test
public void testSongsToAlbums() throws Exception {
// When a user doesn't have album tags for a particular album, Android ends up using the
// folder name as the album name. So if there's a bunch of songs in a folder, and none of the
// songs have correct album tags, all the songs will have the same album id.
// This test ensures that the songsToAlbums operator recognises that these songs don't share
// a common albumArtist name (remember, the albumArtistName falls back to artistName if not present)
// and as such, the songs belong to separate albums.
// Conditions:
// 1. The album name & album ID is the same for all songs.
// 2. The album artist differs for some songs.
List<Song> songs = new ArrayList<>();
for (int i = 0; i < 15; i++) {
Song song = new Song(mock(Cursor.class));
song.id = i;
song.name = "Song " + i;
song.albumId = 0;
song.albumName = "Music";
song.albumArtistName = "Artist 1";
songs.add(song);
}
for (int i = 0; i < 15; i++) {
Song song = new Song(mock(Cursor.class));
song.id = i + 14;
song.name = "Song " + i;
song.albumId = 0;
song.albumName = "Music";
song.albumArtistName = "Artist 2";
songs.add(song);
}
assertThat(Operators.songsToAlbums(songs).size()).isEqualTo(2);
// Test to ensure that only one album is generated under the following conditions:
// 1. The album name & album ID is the same for all songs.
// 2. The album artist is the same for all songs.
// 3. The artist differs for some songs.
songs = new ArrayList<>();
for (int i = 0; i < 15; i++) {
Song song = new Song(mock(Cursor.class));
song.id = i;
song.name = "Song " + i;
song.albumId = 0;
song.albumName = "Music";
song.artistId = 0;
song.artistName = "Artist 1";
song.albumArtistName = "Album Artist 1";
songs.add(song);
}
for (int i = 0; i < 15; i++) {
Song song = new Song(mock(Cursor.class));
song.id = i + 14;
song.name = "Song " + i;
song.albumId = 0;
song.albumName = "Music";
song.artistId = 1;
song.artistName = "Artist 2";
song.albumArtistName = "Album Artist 1";
songs.add(song);
}
assertThat(Operators.songsToAlbums(songs).size()).isEqualTo(1);
}
use of com.simplecity.amp_library.model.Song in project Shuttle by timusus.
the class SearchUtilsUnitTest method testJaroWinklerObject.
@Test
public void testJaroWinklerObject() throws Exception {
//These are kind of vague tests, just ensuring that various JaroWinkler search distance
//queries fall roughly in the expected range..
//Todo:
//I'm not really sure if this is the correct use of unit tests. This particular set is less about
//testing whether the code is sound and working as expected, and more about testing whether the logic
//behind that code gives us the results we want..
double SCORE_THRESHOLD = 0.70;
//We expect this to do well, as 'words' is one of the words in the song name. (Score should be 1.0)
Song song = new Song(mock(Cursor.class));
song.name = "The lots of words song";
SearchUtils.JaroWinklerObject jaroWinklerObject = new SearchUtils.JaroWinklerObject<>(song, "words", song.name);
assertThat(jaroWinklerObject.score).isGreaterThan(SCORE_THRESHOLD);
//This was a user-submitted example of a previously failing search - before adjusting the Jaro-Winkler
//to split the song/album/artist name at whitespace, and return the best score for each substring.
song = new Song(mock(Cursor.class));
song.artistName = "Aby Wolf";
jaroWinklerObject = new SearchUtils.JaroWinklerObject<>(song, "aby wolf", song.artistName);
assertThat(jaroWinklerObject.score).isGreaterThan(SCORE_THRESHOLD);
//'Baby worm' isn't similar enough to 'aby wolf' to pass our threshold.
song = new Song(mock(Cursor.class));
song.artistName = "Bad Worms";
jaroWinklerObject = new SearchUtils.JaroWinklerObject<>(song, "aby wolf", song.artistName);
assertThat(jaroWinklerObject.score).isLessThan(SCORE_THRESHOLD);
}
use of com.simplecity.amp_library.model.Song in project Shuttle by timusus.
the class PlaylistUtils method addToFavorites.
/**
* Add a song to the favourites playlist
*/
public static void addToFavorites(final Context context) {
Song song = MusicUtils.getSong();
if (song == null) {
return;
}
Observable.fromCallable(Playlist::favoritesPlaylist).flatMap(playlist -> playlist.getSongsObservable(context).flatMap(new Func1<List<Song>, Observable<Playlist>>() {
@Override
public Observable<Playlist> call(List<Song> songs) {
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlist.id);
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, song.id);
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, songs.size() + 1);
context.getContentResolver().insert(uri, values);
return Observable.just(playlist);
}
})).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(playlist -> {
Toast.makeText(context, context.getResources().getString(R.string.song_to_favourites, song.name), Toast.LENGTH_SHORT).show();
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(MusicService.InternalIntents.FAVORITE_CHANGED));
});
}
use of com.simplecity.amp_library.model.Song in project Shuttle by timusus.
the class PlaylistUtils method addToPlaylist.
/**
* Method addToPlaylist.
*
* @param playlist Playlist
* @param songs List<Song>
* @return boolean true if the playlist addition was successful
*/
public static void addToPlaylist(Context context, Playlist playlist, List<Song> songs) {
if (playlist == null || songs == null || songs.isEmpty()) {
return;
}
playlist.getSongsObservable(context).observeOn(AndroidSchedulers.mainThread()).subscribe(existingSongs -> {
if (!SettingsManager.getInstance().ignoreDuplicates()) {
List<Song> duplicates = Stream.of(existingSongs).filter(songs::contains).distinct().collect(Collectors.toList());
if (!duplicates.isEmpty()) {
View customView = LayoutInflater.from(context).inflate(R.layout.dialog_playlist_duplicates, null);
TextView messageText = (TextView) customView.findViewById(R.id.textView);
CheckBox applyToAll = (CheckBox) customView.findViewById(R.id.applyToAll);
CheckBox alwaysAdd = (CheckBox) customView.findViewById(R.id.alwaysAdd);
if (duplicates.size() <= 1) {
applyToAll.setVisibility(View.GONE);
applyToAll.setChecked(false);
}
messageText.setText(getPlaylistRemoveString(context, duplicates.get(0)));
applyToAll.setText(getApplyCheckboxString(context, duplicates.size()));
DialogUtils.getBuilder(context).title(R.string.dialog_title_playlist_duplicates).customView(customView, false).positiveText(R.string.dialog_button_playlist_duplicate_add).autoDismiss(false).onPositive((dialog, which) -> {
if (duplicates.size() != 1 && !applyToAll.isChecked()) {
duplicates.remove(0);
messageText.setText(getPlaylistRemoveString(context, duplicates.get(0)));
applyToAll.setText(getApplyCheckboxString(context, duplicates.size()));
} else {
insertPlaylistItems(context, playlist, songs, existingSongs.size());
SettingsManager.getInstance().setIgnoreDuplicates(alwaysAdd.isChecked());
dialog.dismiss();
}
}).negativeText(R.string.dialog_button_playlist_duplicate_skip).onNegative((dialog, which) -> {
if (duplicates.size() != 1 && !applyToAll.isChecked()) {
songs.remove(duplicates.remove(0));
messageText.setText(getPlaylistRemoveString(context, duplicates.get(0)));
applyToAll.setText(getApplyCheckboxString(context, duplicates.size()));
} else {
Stream.of(duplicates).filter(songs::contains).forEach(songs::remove);
insertPlaylistItems(context, playlist, songs, existingSongs.size());
SettingsManager.getInstance().setIgnoreDuplicates(alwaysAdd.isChecked());
dialog.dismiss();
}
}).show();
} else {
insertPlaylistItems(context, playlist, songs, existingSongs.size());
}
} else {
insertPlaylistItems(context, playlist, songs, existingSongs.size());
}
});
}
Aggregations