View Javadoc

1   /***
2    *     Ambient - A music player for the Android platform
3    Copyright (C) 2007 Martin Vysny
4    
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9    
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14  
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  package sk.baka.ambient.playlist;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import junit.framework.TestCase;
24  import sk.baka.ambient.collection.TrackMetadataBean;
25  import sk.baka.ambient.collection.TrackOriginEnum;
26  import sk.baka.ambient.collection.TrackMetadataBean.Builder;
27  import sk.baka.ambient.commons.Interval;
28  
29  /***
30   * Common utility methods for testing a playlist strategy.
31   * 
32   * @author mvy
33   */
34  public abstract class AbstractPlaylistStrategyTest extends TestCase {
35  	/***
36  	 * Returns the strategy instance.
37  	 * 
38  	 * @return the strategy instance. The strategy playlist must be empty.
39  	 */
40  	protected abstract IPlaylistStrategy getStrategy();
41  
42  	/***
43  	 * Contains 30 test tracks.
44  	 */
45  	protected List<TrackMetadataBean> tracks;
46  
47  	/***
48  	 * The strategy instance being tested.
49  	 */
50  	protected IPlaylistStrategy strategy;
51  
52  	@Override
53  	protected void setUp() throws Exception {
54  		super.setUp();
55  		tracks = new ArrayList<TrackMetadataBean>();
56  		for (int i = 0; i < 30; i++) {
57  			final Builder track = TrackMetadataBean.newBuilder();
58  			track.setOrigin(TrackOriginEnum.LocalFs).setLocation(
59  					"/sdcard/" + i + ".mp3");
60  			track.setLength(100 * i).setFileSize(100 * i);
61  			tracks.add(track.build(i));
62  		}
63  		strategy = getStrategy();
64  	}
65  
66  	/***
67  	 * @throws Exception
68  	 */
69  	public void testEmptyPlaylist() throws Exception {
70  		assertEquals(0, strategy.size());
71  		assertEquals(-1, strategy.previous());
72  	}
73  
74  	/***
75  	 * @throws Exception
76  	 */
77  	public void testAdding30Tracks() throws Exception {
78  		strategy.add(0, tracks);
79  		assertEquals(tracks, strategy.getPlayItems());
80  	}
81  
82  	/***
83  	 * @throws Exception
84  	 */
85  	public void testQueuingTracks() throws Exception {
86  		for (final Random r : Random.values()) {
87  			strategy = getStrategy();
88  			strategy.setRandom(r);
89  			strategy.add(0, tracks);
90  			// queue 5 tracks
91  			Interval queueInterval = new Interval(5, 5);
92  			strategy.queue(queueInterval);
93  			assertEquals(tracks.size(), strategy.size());
94  			assertEqualsQueue(tracks.subList(5, 10));
95  			verifyQueueProperties(5);
96  			// queue another 5 tracks
97  			queueInterval = new Interval(15, 5);
98  			strategy.queue(queueInterval);
99  			List<TrackMetadataBean> expectedQueue = new ArrayList<TrackMetadataBean>(
100 					tracks.subList(5, 10));
101 			expectedQueue.addAll(tracks.subList(15, 20));
102 			assertEqualsQueue(expectedQueue);
103 			verifyQueueProperties(10);
104 		}
105 	}
106 
107 	/***
108 	 */
109 	public void testPlayingQueuedTracks() {
110 		for (final Random r : Random.values()) {
111 			strategy = getStrategy();
112 			strategy.setRandom(r);
113 			strategy.add(0, tracks);
114 			// queue 5 tracks
115 			Interval queueInterval = new Interval(5, 5);
116 			strategy.queue(queueInterval);
117 			assertNextTracks(tracks.subList(5, 10), false);
118 			verifyQueueProperties(0);
119 			strategy.next();
120 			verifyQueueProperties(0);
121 		}
122 	}
123 
124 	/***
125 	 * Asserts that next x tracks will be in same ordering as in the
126 	 * <code>tracks</code> list.
127 	 * 
128 	 * @param tracks
129 	 *            expect this ordering when playing next tracks.
130 	 * @param playlistEnd
131 	 *            if <code>true</code> then the playlist must end after given
132 	 *            tracks.
133 	 */
134 	protected void assertNextTracks(final List<TrackMetadataBean> tracks,
135 			boolean playlistEnd) {
136 		for (final TrackMetadataBean track : tracks) {
137 			final int trackIndex = strategy.next();
138 			assertEquals(trackIndex, strategy.getCurrentlyPlaying());
139 			assertTrue("There should be more tracks to play", trackIndex >= 0);
140 			assertEquals(track, strategy.getPlayItems().get(trackIndex).track);
141 		}
142 		if (playlistEnd) {
143 			final int i = strategy.next();
144 			if (i >= 0) {
145 				fail("There are items left in the playlist; "
146 						+ getCurrentlyPlaying());
147 			}
148 		}
149 	}
150 
151 	/***
152 	 * Compares current {@link #strategy}
153 	 * {@link IPlaylistStrategy#getPlayItems()} to tracks in {@link #tracks}.
154 	 * 
155 	 * @param trackNumbers
156 	 *            indexes to the {@link #tracks} list. <code>null</code>
157 	 *            values are skipped.
158 	 * @param startIndex
159 	 *            where to start
160 	 */
161 	protected void assertTracks(final List<Integer> trackNumbers, int startIndex) {
162 		int i = startIndex;
163 		for (final Integer index : trackNumbers) {
164 			if (index != null) {
165 				final TrackMetadataBean expected = tracks.get(index);
166 				final TrackMetadataBean got = strategy.getPlayItems().get(i).track;
167 				assertEquals(expected, got);
168 			}
169 			i++;
170 		}
171 	}
172 
173 	/***
174 	 * Asserts that next x tracks matches tracks in given <code>tracks</code>
175 	 * list. The number of tracks must match, however the track ordering is
176 	 * irrelevant (as opposed to {@link #assertNextTracks(List, boolean)}).
177 	 * 
178 	 * @param tracks
179 	 *            expect these tracks when playing next tracks.
180 	 * @param playlistEnd
181 	 *            if <code>true</code> then the playlist must end after given
182 	 *            tracks.
183 	 */
184 	protected void assertNextTracksUnordered(
185 			final List<TrackMetadataBean> tracks, boolean playlistEnd) {
186 		final List<TrackMetadataBean> tracks_ = new ArrayList<TrackMetadataBean>(
187 				tracks);
188 		while (!tracks_.isEmpty()) {
189 			final int trackIndex = strategy.next();
190 			assertTrue("No more tracks - tracks not present in the playlist: "
191 					+ tracks_, trackIndex >= 0);
192 			final TrackMetadataBean track = strategy.getPlayItems().get(
193 					trackIndex).track;
194 			assertTrue(
195 					"Track "
196 							+ track
197 							+ " was provided by the playlist but not present in the track list",
198 					tracks_.remove(track));
199 		}
200 		if (playlistEnd) {
201 			assertEquals("There are items left in the playlist; "
202 					+ getCurrentlyPlaying(), -1, strategy.next());
203 		}
204 	}
205 
206 	/***
207 	 * Checks if the queue has correct queue count etc.
208 	 * 
209 	 * @param expectedQueueLength
210 	 */
211 	protected void verifyQueueProperties(final int expectedQueueLength) {
212 		final List<Integer> queue = strategy.getQueue();
213 		assertEquals(expectedQueueLength, queue.size());
214 		// check queuedCount of queued items
215 		for (int i = 0; i < queue.size(); i++) {
216 			final PlaylistItem pi = strategy.getPlayItems().get(queue.get(i));
217 			assertEquals(pi.toString() + " must be queued", i + 1,
218 					pi.queueOrder);
219 		}
220 		// verify that unqueued tracks have queuedCount of zero
221 		for (int i = 0; i < strategy.getPlayItems().size(); i++) {
222 			if (queue.contains(i))
223 				continue;
224 			final PlaylistItem pi = strategy.getPlayItems().get(i);
225 			assertEquals(pi.toString() + " must not be queued", 0,
226 					pi.queueOrder);
227 		}
228 	}
229 
230 	/***
231 	 * Compares given track list with a playlist.
232 	 * 
233 	 * @param expected
234 	 *            the expected track list
235 	 * @param actual
236 	 *            the playlist
237 	 */
238 	public static void assertEquals(
239 			final List<? extends TrackMetadataBean> expected,
240 			final List<? extends PlaylistItem> actual) {
241 		for (int i = 0; i < expected.size(); i++) {
242 			assertEquals("At index i=" + i, expected.get(i), actual.get(i)
243 					.getTrack());
244 		}
245 		assertEquals(expected.size(), actual.size());
246 	}
247 
248 	/***
249 	 * Compares given track list with a playlist.
250 	 * 
251 	 * @param expected
252 	 *            the expected track list
253 	 */
254 	protected void assertEqualsQueue(
255 			final List<? extends TrackMetadataBean> expected) {
256 		final List<? extends Integer> actual = strategy.getQueue();
257 		assertEquals(expected.size(), actual.size());
258 		for (int i = 0; i < expected.size(); i++) {
259 			assertEquals(expected.get(i), strategy.getPlayItems().get(
260 					actual.get(i)).getTrack());
261 		}
262 	}
263 
264 	/***
265 	 * Asserts that given list has given content.
266 	 * 
267 	 * @param expected
268 	 * @param actual
269 	 */
270 	public static void assertEquals(final Object[] expected,
271 			final List<?> actual) {
272 		assertEquals(expected.length, actual.size());
273 		for (int i = 0; i < expected.length; i++) {
274 			assertEquals(expected[i], actual.get(i));
275 		}
276 	}
277 
278 	/***
279 	 */
280 	public void testPlaySameTrack() {
281 		strategy.add(0, tracks);
282 		strategy.play(6);
283 		int i = strategy.getCurrentlyPlaying();
284 		// the currently played track may not be the 6th track in case of the
285 		// dynamic playlist
286 		assertTrue(i >= 0);
287 		strategy.play(i);
288 		assertEquals(i, strategy.getCurrentlyPlaying());
289 		strategy.play(-1);
290 		assertEquals(-1, strategy.getCurrentlyPlaying());
291 		strategy.play(-1);
292 		assertEquals(-1, strategy.getCurrentlyPlaying());
293 	}
294 
295 	/***
296 	 * 
297 	 */
298 	public void testNormalOrder() {
299 		strategy.add(0, tracks);
300 		assertNextTracks(tracks, false);
301 	}
302 
303 	/***
304 	 */
305 	public void testRemovingPlayedTrackRandom() {
306 		strategy.setRandom(Random.TRACK);
307 		strategy.add(0, tracks);
308 		strategy.play(strategy.size() - 1);
309 		strategy.remove(new Interval(0, strategy.size()));
310 		assertEquals(-1, strategy.getCurrentlyPlaying());
311 	}
312 
313 	/***
314 	 */
315 	public void testRemovingTracksPreservesCurrentlyPlayedTrack() {
316 		strategy.add(0, tracks);
317 		strategy.play(15);
318 		TrackMetadataBean track = getCurrentlyPlaying();
319 		strategy.remove(new Interval(20, 5));
320 		assertEquals(track, getCurrentlyPlaying());
321 		strategy.remove(new Interval(5, 5));
322 		assertEquals(track, getCurrentlyPlaying());
323 	}
324 
325 	/***
326 	 * Returns {@link #strategy strategy} currently played track.
327 	 * 
328 	 * @return never <code>null</code>. Fails if no track is being played.
329 	 */
330 	protected TrackMetadataBean getCurrentlyPlaying() {
331 		final int i = strategy.getCurrentlyPlaying();
332 		assertTrue("No track is being played", i >= 0);
333 		return strategy.getPlayItems().get(i).getTrack();
334 	}
335 
336 	/***
337 	 * 
338 	 */
339 	public void testSetRandomModePreservesCurrentTrack() {
340 		strategy.add(0, tracks);
341 		strategy.next();
342 		strategy.next();
343 		strategy.next();
344 		TrackMetadataBean old = getCurrentlyPlaying();
345 		strategy.setRandom(Random.TRACK);
346 		assertEquals(old, getCurrentlyPlaying());
347 		strategy.setRandom(Random.ALBUM);
348 		assertEquals(old, getCurrentlyPlaying());
349 		strategy.setRandom(Random.NONE);
350 		assertEquals(old, getCurrentlyPlaying());
351 	}
352 }