NEWS: update from 3.0.x branch
[vlc.git] / src / playlist / test.c
blobbb9290925c89d40d97462f450dfc76f8057d91a3
1 /*****************************************************************************
2 * playlist/test.c
3 *****************************************************************************
4 * Copyright (C) 2018 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifndef DOC
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <stdio.h>
28 #include "item.h"
29 #include "playlist.h"
30 #include "preparse.h"
32 /* the playlist lock is the one of the player */
33 # define vlc_playlist_Lock(p) VLC_UNUSED(p);
34 # define vlc_playlist_Unlock(p) VLC_UNUSED(p);
36 static input_item_t *
37 CreateDummyMedia(int num)
39 char *url;
40 char *name;
42 int res = asprintf(&url, "vlc://item-%d", num);
43 if (res == -1)
44 return NULL;
46 res = asprintf(&name, "item-%d", num);
47 if (res == -1)
48 return NULL;
50 input_item_t *media = input_item_New(url, name);
51 free(url);
52 free(name);
53 return media;
56 static void
57 CreateDummyMediaArray(input_item_t *out[], size_t count)
59 for (size_t i = 0; i < count; ++i)
61 out[i] = CreateDummyMedia(i);
62 assert(out[i]);
66 static void
67 DestroyMediaArray(input_item_t *const array[], size_t count)
69 for (size_t i = 0; i < count; ++i)
70 input_item_Release(array[i]);
73 #define EXPECT_AT(index, id) \
74 assert(vlc_playlist_Get(playlist, index)->media == media[id])
76 static void
77 test_append(void)
79 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
80 assert(playlist);
82 input_item_t *media[10];
83 CreateDummyMediaArray(media, 10);
85 /* append one by one */
86 for (int i = 0; i < 5; ++i)
88 int ret = vlc_playlist_AppendOne(playlist, media[i]);
89 assert(ret == VLC_SUCCESS);
92 /* append several at once */
93 int ret = vlc_playlist_Append(playlist, &media[5], 5);
94 assert(ret == VLC_SUCCESS);
96 assert(vlc_playlist_Count(playlist) == 10);
97 EXPECT_AT(0, 0);
98 EXPECT_AT(1, 1);
99 EXPECT_AT(2, 2);
100 EXPECT_AT(3, 3);
101 EXPECT_AT(4, 4);
102 EXPECT_AT(5, 5);
103 EXPECT_AT(6, 6);
104 EXPECT_AT(7, 7);
105 EXPECT_AT(8, 8);
106 EXPECT_AT(9, 9);
108 DestroyMediaArray(media, 10);
109 vlc_playlist_Delete(playlist);
112 static void
113 test_insert(void)
115 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
116 assert(playlist);
118 input_item_t *media[15];
119 CreateDummyMediaArray(media, 15);
121 /* initial playlist with 5 items */
122 int ret = vlc_playlist_Append(playlist, media, 5);
123 assert(ret == VLC_SUCCESS);
125 /* insert one by one */
126 for (int i = 0; i < 5; ++i)
128 ret = vlc_playlist_InsertOne(playlist, 2, media[i + 5]);
129 assert(ret == VLC_SUCCESS);
132 /* insert several at once */
133 ret = vlc_playlist_Insert(playlist, 6, &media[10], 5);
134 assert(ret == VLC_SUCCESS);
136 assert(vlc_playlist_Count(playlist) == 15);
138 EXPECT_AT(0, 0);
139 EXPECT_AT(1, 1);
141 EXPECT_AT(2, 9);
142 EXPECT_AT(3, 8);
143 EXPECT_AT(4, 7);
144 EXPECT_AT(5, 6);
146 EXPECT_AT(6, 10);
147 EXPECT_AT(7, 11);
148 EXPECT_AT(8, 12);
149 EXPECT_AT(9, 13);
150 EXPECT_AT(10, 14);
152 EXPECT_AT(11, 5);
153 EXPECT_AT(12, 2);
154 EXPECT_AT(13, 3);
155 EXPECT_AT(14, 4);
157 DestroyMediaArray(media, 15);
158 vlc_playlist_Delete(playlist);
161 static void
162 test_move(void)
164 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
165 assert(playlist);
167 input_item_t *media[10];
168 CreateDummyMediaArray(media, 10);
170 /* initial playlist with 10 items */
171 int ret = vlc_playlist_Append(playlist, media, 10);
172 assert(ret == VLC_SUCCESS);
174 /* move slice {3, 4, 5, 6} so that its new position is 5 */
175 vlc_playlist_Move(playlist, 3, 4, 5);
177 EXPECT_AT(0, 0);
178 EXPECT_AT(1, 1);
179 EXPECT_AT(2, 2);
180 EXPECT_AT(3, 7);
181 EXPECT_AT(4, 8);
182 EXPECT_AT(5, 3);
183 EXPECT_AT(6, 4);
184 EXPECT_AT(7, 5);
185 EXPECT_AT(8, 6);
186 EXPECT_AT(9, 9);
188 /* move it back to its original position */
189 vlc_playlist_Move(playlist, 5, 4, 3);
191 EXPECT_AT(0, 0);
192 EXPECT_AT(1, 1);
193 EXPECT_AT(2, 2);
194 EXPECT_AT(3, 3);
195 EXPECT_AT(4, 4);
196 EXPECT_AT(5, 5);
197 EXPECT_AT(6, 6);
198 EXPECT_AT(7, 7);
199 EXPECT_AT(8, 8);
200 EXPECT_AT(9, 9);
202 DestroyMediaArray(media, 10);
203 vlc_playlist_Delete(playlist);
206 static void
207 test_remove(void)
209 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
210 assert(playlist);
212 input_item_t *media[10];
213 CreateDummyMediaArray(media, 10);
215 /* initial playlist with 10 items */
216 int ret = vlc_playlist_Append(playlist, media, 10);
217 assert(ret == VLC_SUCCESS);
219 /* remove one by one */
220 for (int i = 0; i < 3; ++i)
221 vlc_playlist_RemoveOne(playlist, 2);
223 /* remove several at once */
224 vlc_playlist_Remove(playlist, 3, 2);
226 assert(vlc_playlist_Count(playlist) == 5);
227 EXPECT_AT(0, 0);
228 EXPECT_AT(1, 1);
229 EXPECT_AT(2, 5);
230 EXPECT_AT(3, 8);
231 EXPECT_AT(4, 9);
233 DestroyMediaArray(media, 10);
234 vlc_playlist_Delete(playlist);
237 static void
238 test_clear(void)
240 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
241 assert(playlist);
243 input_item_t *media[10];
244 CreateDummyMediaArray(media, 10);
246 /* initial playlist with 10 items */
247 int ret = vlc_playlist_Append(playlist, media, 10);
248 assert(ret == VLC_SUCCESS);
250 assert(vlc_playlist_Count(playlist) == 10);
251 vlc_playlist_Clear(playlist);
252 assert(vlc_playlist_Count(playlist) == 0);
254 DestroyMediaArray(media, 10);
255 vlc_playlist_Delete(playlist);
258 static void
259 test_expand_item(void)
261 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
262 assert(playlist);
264 input_item_t *media[16];
265 CreateDummyMediaArray(media, 16);
267 /* initial playlist with 10 items */
268 int ret = vlc_playlist_Append(playlist, media, 10);
269 assert(ret == VLC_SUCCESS);
271 /* create a subtree for item 8 with 4 children */
272 input_item_t *item_to_expand = playlist->items.data[8]->media;
273 input_item_node_t *root = input_item_node_Create(item_to_expand);
274 for (int i = 0; i < 4; ++i)
276 input_item_node_t *node = input_item_node_AppendItem(root,
277 media[i + 10]);
278 assert(node);
281 /* on the 3rd children, add 2 grand-children */
282 input_item_node_t *parent = root->pp_children[2];
283 for (int i = 0; i < 2; ++i)
285 input_item_node_t *node = input_item_node_AppendItem(parent,
286 media[i + 14]);
287 assert(node);
290 playlist->current = 8;
291 playlist->has_prev = true;
292 playlist->has_next = true;
294 ret = vlc_playlist_ExpandItem(playlist, 8, root);
295 assert(ret == VLC_SUCCESS);
296 assert(vlc_playlist_Count(playlist) == 15);
297 EXPECT_AT(7, 7);
299 EXPECT_AT(8, 10);
300 EXPECT_AT(9, 11);
301 EXPECT_AT(10, 12);
303 EXPECT_AT(11, 14);
304 EXPECT_AT(12, 15);
306 EXPECT_AT(13, 13);
308 EXPECT_AT(14, 9);
310 /* item 8 will be replaced, the current must stay the same */
311 assert(playlist->current == 8);
313 input_item_node_Delete(root);
314 DestroyMediaArray(media, 16);
315 vlc_playlist_Delete(playlist);
318 struct playlist_state
320 size_t playlist_size;
321 ssize_t current;
322 bool has_prev;
323 bool has_next;
326 static void
327 playlist_state_init(struct playlist_state *state, vlc_playlist_t *playlist)
329 state->playlist_size = vlc_playlist_Count(playlist);
330 state->current = vlc_playlist_GetCurrentIndex(playlist);
331 state->has_prev = vlc_playlist_HasPrev(playlist);
332 state->has_next = vlc_playlist_HasNext(playlist);
335 struct items_reset_report
337 size_t count;
338 struct playlist_state state;
341 struct items_added_report
343 size_t index;
344 size_t count;
345 struct playlist_state state;
348 struct items_moved_report
350 size_t index;
351 size_t count;
352 size_t target;
353 struct playlist_state state;
356 struct items_removed_report
358 size_t index;
359 size_t count;
360 struct playlist_state state;
363 struct playback_repeat_changed_report
365 enum vlc_playlist_playback_repeat repeat;
368 struct playback_order_changed_report
370 enum vlc_playlist_playback_order order;
373 struct current_index_changed_report
375 ssize_t current;
378 struct has_prev_changed_report
380 bool has_prev;
383 struct has_next_changed_report
385 bool has_next;
388 struct callback_ctx
390 struct VLC_VECTOR(struct items_reset_report) vec_items_reset;
391 struct VLC_VECTOR(struct items_added_report) vec_items_added;
392 struct VLC_VECTOR(struct items_moved_report) vec_items_moved;
393 struct VLC_VECTOR(struct items_removed_report) vec_items_removed;
394 struct VLC_VECTOR(struct playback_order_changed_report)
395 vec_playback_order_changed;
396 struct VLC_VECTOR(struct playback_repeat_changed_report)
397 vec_playback_repeat_changed;
398 struct VLC_VECTOR(struct current_index_changed_report)
399 vec_current_index_changed;
400 struct VLC_VECTOR(struct has_prev_changed_report) vec_has_prev_changed;
401 struct VLC_VECTOR(struct has_next_changed_report) vec_has_next_changed;
404 #define CALLBACK_CTX_INITIALIZER \
406 VLC_VECTOR_INITIALIZER, \
407 VLC_VECTOR_INITIALIZER, \
408 VLC_VECTOR_INITIALIZER, \
409 VLC_VECTOR_INITIALIZER, \
410 VLC_VECTOR_INITIALIZER, \
411 VLC_VECTOR_INITIALIZER, \
412 VLC_VECTOR_INITIALIZER, \
413 VLC_VECTOR_INITIALIZER, \
414 VLC_VECTOR_INITIALIZER, \
417 static inline void
418 callback_ctx_reset(struct callback_ctx *ctx)
420 vlc_vector_clear(&ctx->vec_items_reset);
421 vlc_vector_clear(&ctx->vec_items_added);
422 vlc_vector_clear(&ctx->vec_items_moved);
423 vlc_vector_clear(&ctx->vec_items_removed);
424 vlc_vector_clear(&ctx->vec_playback_repeat_changed);
425 vlc_vector_clear(&ctx->vec_playback_order_changed);
426 vlc_vector_clear(&ctx->vec_current_index_changed);
427 vlc_vector_clear(&ctx->vec_has_prev_changed);
428 vlc_vector_clear(&ctx->vec_has_next_changed);
431 static inline void
432 callback_ctx_destroy(struct callback_ctx *ctx)
434 vlc_vector_destroy(&ctx->vec_items_reset);
435 vlc_vector_destroy(&ctx->vec_items_added);
436 vlc_vector_destroy(&ctx->vec_items_moved);
437 vlc_vector_destroy(&ctx->vec_items_removed);
438 vlc_vector_destroy(&ctx->vec_playback_repeat_changed);
439 vlc_vector_destroy(&ctx->vec_playback_order_changed);
440 vlc_vector_destroy(&ctx->vec_current_index_changed);
441 vlc_vector_destroy(&ctx->vec_has_prev_changed);
442 vlc_vector_destroy(&ctx->vec_has_next_changed);
445 static void
446 callback_on_items_reset(vlc_playlist_t *playlist,
447 vlc_playlist_item_t *const items[], size_t count,
448 void *userdata)
450 VLC_UNUSED(items);
451 struct callback_ctx *ctx = userdata;
453 struct items_reset_report report;
454 report.count = count;
455 playlist_state_init(&report.state, playlist);
456 vlc_vector_push(&ctx->vec_items_reset, report);
459 static void
460 callback_on_items_added(vlc_playlist_t *playlist, size_t index,
461 vlc_playlist_item_t *const items[], size_t count,
462 void *userdata)
464 VLC_UNUSED(items);
465 struct callback_ctx *ctx = userdata;
467 struct items_added_report report;
468 report.index = index;
469 report.count = count;
470 playlist_state_init(&report.state, playlist);
471 vlc_vector_push(&ctx->vec_items_added, report);
474 static void
475 callback_on_items_moved(vlc_playlist_t *playlist, size_t index, size_t count,
476 size_t target, void *userdata)
478 struct callback_ctx *ctx = userdata;
480 struct items_moved_report report;
481 report.index = index;
482 report.count = count;
483 report.target = target;
484 playlist_state_init(&report.state, playlist);
485 vlc_vector_push(&ctx->vec_items_moved, report);
488 static void
489 callback_on_items_removed(vlc_playlist_t *playlist, size_t index, size_t count,
490 void *userdata)
492 struct callback_ctx *ctx = userdata;
494 struct items_removed_report report;
495 report.index = index;
496 report.count = count;
497 playlist_state_init(&report.state, playlist);
498 vlc_vector_push(&ctx->vec_items_removed, report);
501 static void
502 callback_on_playback_repeat_changed(vlc_playlist_t *playlist,
503 enum vlc_playlist_playback_repeat repeat,
504 void *userdata)
506 VLC_UNUSED(playlist);
507 struct callback_ctx *ctx = userdata;
509 struct playback_repeat_changed_report report;
510 report.repeat = repeat;
511 vlc_vector_push(&ctx->vec_playback_repeat_changed, report);
514 static void
515 callback_on_playback_order_changed(vlc_playlist_t *playlist,
516 enum vlc_playlist_playback_order order,
517 void *userdata)
519 VLC_UNUSED(playlist);
520 struct callback_ctx *ctx = userdata;
522 struct playback_order_changed_report report;
523 report.order = order;
524 vlc_vector_push(&ctx->vec_playback_order_changed, report);
527 static void
528 callback_on_current_index_changed(vlc_playlist_t *playlist, ssize_t index,
529 void *userdata)
531 VLC_UNUSED(playlist);
532 struct callback_ctx *ctx = userdata;
534 struct current_index_changed_report report;
535 report.current = index;
536 vlc_vector_push(&ctx->vec_current_index_changed, report);
539 static void
540 callback_on_has_prev_changed(vlc_playlist_t *playlist, bool has_prev,
541 void *userdata)
543 VLC_UNUSED(playlist);
544 struct callback_ctx *ctx = userdata;
546 struct has_prev_changed_report report;
547 report.has_prev = has_prev;
548 vlc_vector_push(&ctx->vec_has_prev_changed, report);
551 static void
552 callback_on_has_next_changed(vlc_playlist_t *playlist, bool has_next,
553 void *userdata)
555 VLC_UNUSED(playlist);
556 struct callback_ctx *ctx = userdata;
558 struct has_next_changed_report report;
559 report.has_next = has_next;
560 vlc_vector_push(&ctx->vec_has_next_changed, report);
563 static void
564 test_items_added_callbacks(void)
566 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
567 assert(playlist);
569 input_item_t *media[10];
570 CreateDummyMediaArray(media, 10);
572 struct vlc_playlist_callbacks cbs = {
573 .on_items_added = callback_on_items_added,
574 .on_current_index_changed = callback_on_current_index_changed,
575 .on_has_prev_changed = callback_on_has_prev_changed,
576 .on_has_next_changed = callback_on_has_next_changed,
579 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
580 vlc_playlist_listener_id *listener =
581 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
582 assert(listener);
584 int ret = vlc_playlist_AppendOne(playlist, media[0]);
585 assert(ret == VLC_SUCCESS);
587 /* the callbacks must be called with *all* values up to date */
588 assert(ctx.vec_items_added.size == 1);
589 assert(ctx.vec_items_added.data[0].index == 0);
590 assert(ctx.vec_items_added.data[0].count == 1);
591 assert(ctx.vec_items_added.data[0].state.playlist_size == 1);
592 assert(ctx.vec_items_added.data[0].state.current == -1);
593 assert(!ctx.vec_items_added.data[0].state.has_prev);
594 assert(ctx.vec_items_added.data[0].state.has_next);
596 assert(ctx.vec_current_index_changed.size == 0);
598 assert(ctx.vec_has_prev_changed.size == 0);
600 assert(ctx.vec_has_next_changed.size == 1);
601 assert(ctx.vec_has_next_changed.data[0].has_next);
603 callback_ctx_reset(&ctx);
605 /* set the only item as current */
606 playlist->current = 0;
607 playlist->has_prev = false;
608 playlist->has_next = false;
610 /* insert before the current item */
611 ret = vlc_playlist_Insert(playlist, 0, &media[1], 4);
612 assert(ret == VLC_SUCCESS);
614 assert(ctx.vec_items_added.size == 1);
615 assert(ctx.vec_items_added.data[0].index == 0);
616 assert(ctx.vec_items_added.data[0].count == 4);
617 assert(ctx.vec_items_added.data[0].state.playlist_size == 5);
618 assert(ctx.vec_items_added.data[0].state.current == 4); /* shifted */
619 assert(ctx.vec_items_added.data[0].state.has_prev);
620 assert(!ctx.vec_items_added.data[0].state.has_next);
622 assert(ctx.vec_current_index_changed.size == 1);
623 assert(ctx.vec_current_index_changed.data[0].current == 4);
625 assert(ctx.vec_has_prev_changed.size == 1);
626 assert(ctx.vec_has_prev_changed.data[0].has_prev);
628 assert(ctx.vec_has_next_changed.size == 0);
630 callback_ctx_reset(&ctx);
632 /* append (after the current item) */
633 ret = vlc_playlist_Append(playlist, &media[5], 5);
634 assert(ret == VLC_SUCCESS);
636 assert(ctx.vec_items_added.size == 1);
637 assert(ctx.vec_items_added.data[0].index == 5);
638 assert(ctx.vec_items_added.data[0].count == 5);
639 assert(ctx.vec_items_added.data[0].state.playlist_size == 10);
640 assert(ctx.vec_items_added.data[0].state.current == 4);
641 assert(ctx.vec_items_added.data[0].state.has_prev);
642 assert(ctx.vec_items_added.data[0].state.has_next);
644 assert(ctx.vec_current_index_changed.size == 0);
646 assert(ctx.vec_has_prev_changed.size == 0);
648 assert(ctx.vec_has_next_changed.size == 1);
649 assert(ctx.vec_has_next_changed.data[0].has_next);
651 callback_ctx_destroy(&ctx);
652 vlc_playlist_RemoveListener(playlist, listener);
653 DestroyMediaArray(media, 10);
654 vlc_playlist_Delete(playlist);
657 static void
658 test_items_moved_callbacks(void)
660 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
661 assert(playlist);
663 input_item_t *media[10];
664 CreateDummyMediaArray(media, 10);
666 /* initial playlist with 10 items */
667 int ret = vlc_playlist_Append(playlist, media, 10);
668 assert(ret == VLC_SUCCESS);
670 struct vlc_playlist_callbacks cbs = {
671 .on_items_moved = callback_on_items_moved,
672 .on_current_index_changed = callback_on_current_index_changed,
673 .on_has_prev_changed = callback_on_has_prev_changed,
674 .on_has_next_changed = callback_on_has_next_changed,
677 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
678 vlc_playlist_listener_id *listener =
679 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
680 assert(listener);
682 vlc_playlist_Move(playlist, 2, 3, 5);
684 assert(ctx.vec_items_moved.size == 1);
685 assert(ctx.vec_items_moved.data[0].index == 2);
686 assert(ctx.vec_items_moved.data[0].count == 3);
687 assert(ctx.vec_items_moved.data[0].target == 5);
688 assert(ctx.vec_items_moved.data[0].state.playlist_size == 10);
689 assert(ctx.vec_items_moved.data[0].state.current == -1);
690 assert(!ctx.vec_items_moved.data[0].state.has_prev);
691 assert(ctx.vec_items_moved.data[0].state.has_next);
693 assert(ctx.vec_current_index_changed.size == 0);
694 assert(ctx.vec_has_prev_changed.size == 0);
695 assert(ctx.vec_has_next_changed.size == 0);
697 playlist->current = 3;
698 playlist->has_prev = true;
699 playlist->has_next = true;
701 callback_ctx_reset(&ctx);
703 /* the current index belongs to the moved slice */
704 vlc_playlist_Move(playlist, 1, 3, 5);
706 assert(ctx.vec_items_moved.size == 1);
707 assert(ctx.vec_items_moved.data[0].index == 1);
708 assert(ctx.vec_items_moved.data[0].count == 3);
709 assert(ctx.vec_items_moved.data[0].target == 5);
710 assert(ctx.vec_items_moved.data[0].state.playlist_size == 10);
711 assert(ctx.vec_items_moved.data[0].state.current == 7);
712 assert(ctx.vec_items_moved.data[0].state.has_prev);
713 assert(ctx.vec_items_moved.data[0].state.has_next);
715 assert(ctx.vec_current_index_changed.size == 1);
716 assert(ctx.vec_current_index_changed.data[0].current == 7);
718 assert(ctx.vec_has_prev_changed.size == 0);
719 assert(ctx.vec_has_next_changed.size == 0);
721 callback_ctx_reset(&ctx);
723 /* as a result of this move, the current item (7) will be at index 0 */
724 vlc_playlist_Move(playlist, 0, 7, 1);
726 assert(ctx.vec_items_moved.size == 1);
727 assert(ctx.vec_items_moved.data[0].index == 0);
728 assert(ctx.vec_items_moved.data[0].count == 7);
729 assert(ctx.vec_items_moved.data[0].target == 1);
730 assert(ctx.vec_items_moved.data[0].state.playlist_size == 10);
731 assert(ctx.vec_items_moved.data[0].state.current == 0);
732 assert(!ctx.vec_items_moved.data[0].state.has_prev);
733 assert(ctx.vec_items_moved.data[0].state.has_next);
735 assert(ctx.vec_current_index_changed.size == 1);
736 assert(ctx.vec_current_index_changed.data[0].current == 0);
738 assert(ctx.vec_has_prev_changed.size == 1);
739 assert(!ctx.vec_has_prev_changed.data[0].has_prev);
741 assert(ctx.vec_has_next_changed.size == 0);
743 callback_ctx_reset(&ctx);
745 playlist->current = 5;
746 playlist->has_prev = true;
747 playlist->has_next = true;
749 vlc_playlist_Move(playlist, 6, 2, 3);
751 assert(ctx.vec_items_moved.size == 1);
752 assert(ctx.vec_items_moved.data[0].index == 6);
753 assert(ctx.vec_items_moved.data[0].count == 2);
754 assert(ctx.vec_items_moved.data[0].target == 3);
755 assert(ctx.vec_items_moved.data[0].state.playlist_size == 10);
756 assert(ctx.vec_items_moved.data[0].state.current == 7);
757 assert(ctx.vec_items_moved.data[0].state.has_prev);
758 assert(ctx.vec_items_moved.data[0].state.has_next);
760 assert(ctx.vec_current_index_changed.size == 1);
761 assert(ctx.vec_current_index_changed.data[0].current == 7);
763 assert(ctx.vec_has_prev_changed.size == 0);
765 assert(ctx.vec_has_next_changed.size == 0);
767 callback_ctx_destroy(&ctx);
768 vlc_playlist_RemoveListener(playlist, listener);
769 DestroyMediaArray(media, 10);
770 vlc_playlist_Delete(playlist);
773 static void
774 test_items_removed_callbacks(void)
776 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
777 assert(playlist);
779 input_item_t *media[10];
780 CreateDummyMediaArray(media, 10);
782 /* initial playlist with 10 items */
783 int ret = vlc_playlist_Append(playlist, media, 10);
784 assert(ret == VLC_SUCCESS);
786 struct vlc_playlist_callbacks cbs = {
787 .on_items_removed = callback_on_items_removed,
788 .on_current_index_changed = callback_on_current_index_changed,
789 .on_has_prev_changed = callback_on_has_prev_changed,
790 .on_has_next_changed = callback_on_has_next_changed,
793 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
794 vlc_playlist_listener_id *listener =
795 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
796 assert(listener);
798 vlc_playlist_RemoveOne(playlist, 4);
800 assert(ctx.vec_items_removed.size == 1);
801 assert(ctx.vec_items_removed.data[0].index == 4);
802 assert(ctx.vec_items_removed.data[0].count == 1);
803 assert(ctx.vec_items_removed.data[0].state.playlist_size == 9);
804 assert(ctx.vec_items_removed.data[0].state.current == -1);
805 assert(!ctx.vec_items_removed.data[0].state.has_prev);
806 assert(ctx.vec_items_removed.data[0].state.has_next);
808 assert(ctx.vec_current_index_changed.size == 0);
809 assert(ctx.vec_has_prev_changed.size == 0);
810 assert(ctx.vec_has_next_changed.size == 0);
812 playlist->current = 7;
813 playlist->has_prev = true;
814 playlist->has_next = true;
816 callback_ctx_reset(&ctx);
818 /* remove items before the current */
819 vlc_playlist_Remove(playlist, 2, 4);
821 assert(ctx.vec_items_removed.size == 1);
822 assert(ctx.vec_items_removed.data[0].index == 2);
823 assert(ctx.vec_items_removed.data[0].count == 4);
824 assert(ctx.vec_items_removed.data[0].state.playlist_size == 5);
825 assert(ctx.vec_items_removed.data[0].state.current == 3); /* shifted */
826 assert(ctx.vec_items_removed.data[0].state.has_prev);
827 assert(ctx.vec_items_removed.data[0].state.has_next);
829 assert(ctx.vec_current_index_changed.size == 1);
830 assert(ctx.vec_current_index_changed.data[0].current == 3);
832 assert(ctx.vec_has_prev_changed.size == 0);
834 assert(ctx.vec_has_next_changed.size == 0);
836 callback_ctx_reset(&ctx);
838 /* remove the remaining items (without Clear) */
839 vlc_playlist_Remove(playlist, 0, 5);
841 assert(ctx.vec_items_removed.size == 1);
842 assert(ctx.vec_items_removed.data[0].index == 0);
843 assert(ctx.vec_items_removed.data[0].count == 5);
844 assert(ctx.vec_items_removed.data[0].state.playlist_size == 0);
845 assert(ctx.vec_items_removed.data[0].state.current == -1);
846 assert(!ctx.vec_items_removed.data[0].state.has_prev);
847 assert(!ctx.vec_items_removed.data[0].state.has_next);
849 assert(ctx.vec_current_index_changed.size == 1);
850 assert(ctx.vec_current_index_changed.data[0].current == -1);
852 assert(ctx.vec_has_prev_changed.size == 1);
853 assert(!ctx.vec_has_prev_changed.data[0].has_prev);
855 assert(ctx.vec_has_next_changed.size == 1);
856 assert(!ctx.vec_has_next_changed.data[0].has_next);
858 callback_ctx_destroy(&ctx);
859 vlc_playlist_RemoveListener(playlist, listener);
860 DestroyMediaArray(media, 10);
861 vlc_playlist_Delete(playlist);
864 static void
865 test_items_reset_callbacks(void)
867 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
868 assert(playlist);
870 input_item_t *media[10];
871 CreateDummyMediaArray(media, 10);
873 /* initial playlist with 10 items */
874 int ret = vlc_playlist_Append(playlist, media, 10);
875 assert(ret == VLC_SUCCESS);
877 struct vlc_playlist_callbacks cbs = {
878 .on_items_reset = callback_on_items_reset,
879 .on_current_index_changed = callback_on_current_index_changed,
880 .on_has_prev_changed = callback_on_has_prev_changed,
881 .on_has_next_changed = callback_on_has_next_changed,
884 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
885 vlc_playlist_listener_id *listener =
886 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
887 assert(listener);
889 callback_ctx_reset(&ctx);
891 playlist->current = 9; /* last item */
892 playlist->has_prev = true;
893 playlist->has_next = false;
895 vlc_playlist_Clear(playlist);
897 assert(ctx.vec_items_reset.size == 1);
898 assert(ctx.vec_items_reset.data[0].count == 0);
899 assert(ctx.vec_items_reset.data[0].state.playlist_size == 0);
900 assert(ctx.vec_items_reset.data[0].state.current == -1);
901 assert(!ctx.vec_items_reset.data[0].state.has_prev);
902 assert(!ctx.vec_items_reset.data[0].state.has_next);
904 assert(ctx.vec_current_index_changed.size == 1);
905 assert(ctx.vec_current_index_changed.data[0].current == -1);
907 assert(ctx.vec_has_prev_changed.size == 1);
908 assert(!ctx.vec_has_prev_changed.data[0].has_prev);
910 assert(ctx.vec_has_next_changed.size == 0);
912 callback_ctx_destroy(&ctx);
913 vlc_playlist_RemoveListener(playlist, listener);
914 DestroyMediaArray(media, 10);
915 vlc_playlist_Delete(playlist);
918 static void
919 test_playback_repeat_changed_callbacks(void)
921 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
922 assert(playlist);
924 playlist->repeat = VLC_PLAYLIST_PLAYBACK_REPEAT_NONE;
926 struct vlc_playlist_callbacks cbs = {
927 .on_playback_repeat_changed = callback_on_playback_repeat_changed,
930 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
931 vlc_playlist_listener_id *listener =
932 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
933 assert(listener);
935 vlc_playlist_SetPlaybackRepeat(playlist, VLC_PLAYLIST_PLAYBACK_REPEAT_ALL);
937 assert(vlc_playlist_GetPlaybackRepeat(playlist) ==
938 VLC_PLAYLIST_PLAYBACK_REPEAT_ALL);
940 assert(ctx.vec_playback_repeat_changed.size == 1);
941 assert(ctx.vec_playback_repeat_changed.data[0].repeat ==
942 VLC_PLAYLIST_PLAYBACK_REPEAT_ALL);
944 callback_ctx_destroy(&ctx);
945 vlc_playlist_RemoveListener(playlist, listener);
946 vlc_playlist_Delete(playlist);
949 static void
950 test_playback_order_changed_callbacks(void)
952 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
953 assert(playlist);
955 playlist->order = VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL;
957 struct vlc_playlist_callbacks cbs = {
958 .on_playback_order_changed = callback_on_playback_order_changed,
961 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
962 vlc_playlist_listener_id *listener =
963 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
964 assert(listener);
966 vlc_playlist_SetPlaybackOrder(playlist, VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM);
968 assert(vlc_playlist_GetPlaybackOrder(playlist) ==
969 VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM);
971 assert(ctx.vec_playback_order_changed.size == 1);
972 assert(ctx.vec_playback_order_changed.data[0].order ==
973 VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM);
975 callback_ctx_destroy(&ctx);
976 vlc_playlist_RemoveListener(playlist, listener);
977 vlc_playlist_Delete(playlist);
980 static void
981 test_callbacks_on_add_listener(void)
983 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
984 assert(playlist);
986 input_item_t *media[10];
987 CreateDummyMediaArray(media, 10);
989 /* initial playlist with 10 items */
990 int ret = vlc_playlist_Append(playlist, media, 10);
991 assert(ret == VLC_SUCCESS);
993 vlc_playlist_SetPlaybackRepeat(playlist, VLC_PLAYLIST_PLAYBACK_REPEAT_ALL);
994 vlc_playlist_SetPlaybackOrder(playlist, VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL);
996 ret = vlc_playlist_GoTo(playlist, 5);
997 assert(ret == VLC_SUCCESS);
999 struct vlc_playlist_callbacks cbs = {
1000 .on_items_reset = callback_on_items_reset,
1001 .on_playback_repeat_changed = callback_on_playback_repeat_changed,
1002 .on_playback_order_changed = callback_on_playback_order_changed,
1003 .on_current_index_changed = callback_on_current_index_changed,
1004 .on_has_prev_changed = callback_on_has_prev_changed,
1005 .on_has_next_changed = callback_on_has_next_changed,
1008 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1009 vlc_playlist_listener_id *listener =
1010 vlc_playlist_AddListener(playlist, &cbs, &ctx, true);
1011 assert(listener);
1013 assert(ctx.vec_items_reset.size == 1);
1014 assert(ctx.vec_items_reset.data[0].count == 10);
1016 assert(ctx.vec_playback_repeat_changed.size == 1);
1017 assert(ctx.vec_playback_repeat_changed.data[0].repeat ==
1018 VLC_PLAYLIST_PLAYBACK_REPEAT_ALL);
1020 assert(ctx.vec_playback_order_changed.size == 1);
1021 assert(ctx.vec_playback_order_changed.data[0].order ==
1022 VLC_PLAYLIST_PLAYBACK_ORDER_NORMAL);
1024 assert(ctx.vec_current_index_changed.size == 1);
1025 assert(ctx.vec_current_index_changed.data[0].current == 5);
1027 assert(ctx.vec_has_prev_changed.size == 1);
1028 assert(ctx.vec_has_prev_changed.data[0].has_prev);
1030 assert(ctx.vec_has_next_changed.size == 1);
1031 assert(ctx.vec_has_next_changed.data[0].has_next);
1033 callback_ctx_destroy(&ctx);
1034 vlc_playlist_RemoveListener(playlist, listener);
1035 DestroyMediaArray(media, 10);
1036 vlc_playlist_Delete(playlist);
1039 static void
1040 test_index_of(void)
1042 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1043 assert(playlist);
1045 input_item_t *media[10];
1046 CreateDummyMediaArray(media, 10);
1048 /* initial playlist with 9 items (1 is not added) */
1049 int ret = vlc_playlist_Append(playlist, media, 9);
1050 assert(ret == VLC_SUCCESS);
1052 assert(vlc_playlist_IndexOfMedia(playlist, media[4]) == 4);
1053 /* only items 0 to 8 were added */
1054 assert(vlc_playlist_IndexOfMedia(playlist, media[9]) == -1);
1056 vlc_playlist_item_t *item = vlc_playlist_Get(playlist, 4);
1057 assert(vlc_playlist_IndexOf(playlist, item) == 4);
1059 vlc_playlist_item_Hold(item);
1060 vlc_playlist_RemoveOne(playlist, 4);
1061 assert(vlc_playlist_IndexOf(playlist, item) == -1);
1062 vlc_playlist_item_Release(item);
1064 DestroyMediaArray(media, 10);
1065 vlc_playlist_Delete(playlist);
1068 static void
1069 test_prev(void)
1071 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1072 assert(playlist);
1074 input_item_t *media[4];
1075 CreateDummyMediaArray(media, 4);
1077 /* initial playlist with 3 items */
1078 int ret = vlc_playlist_Append(playlist, media, 3);
1079 assert(ret == VLC_SUCCESS);
1081 struct vlc_playlist_callbacks cbs = {
1082 .on_current_index_changed = callback_on_current_index_changed,
1083 .on_has_prev_changed = callback_on_has_prev_changed,
1084 .on_has_next_changed = callback_on_has_next_changed,
1087 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1088 vlc_playlist_listener_id *listener =
1089 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1090 assert(listener);
1092 playlist->current = 2; /* last item */
1093 playlist->has_prev = true;
1094 playlist->has_next = false;
1096 /* go to the previous item (at index 1) */
1097 assert(vlc_playlist_HasPrev(playlist));
1098 ret = vlc_playlist_Prev(playlist);
1099 assert(ret == VLC_SUCCESS);
1101 assert(playlist->current == 1);
1102 assert(playlist->has_prev);
1103 assert(playlist->has_next);
1105 assert(ctx.vec_current_index_changed.size == 1);
1106 assert(ctx.vec_current_index_changed.data[0].current == 1);
1108 assert(ctx.vec_has_prev_changed.size == 0);
1110 assert(ctx.vec_has_next_changed.size == 1);
1111 assert(ctx.vec_has_next_changed.data[0].has_next);
1113 callback_ctx_reset(&ctx);
1115 /* go to the previous item (at index 0) */
1116 assert(vlc_playlist_HasPrev(playlist));
1117 ret = vlc_playlist_Prev(playlist);
1118 assert(ret == VLC_SUCCESS);
1120 assert(playlist->current == 0);
1121 assert(!playlist->has_prev);
1122 assert(playlist->has_next);
1124 assert(ctx.vec_current_index_changed.size == 1);
1125 assert(ctx.vec_current_index_changed.data[0].current == 0);
1127 assert(ctx.vec_has_prev_changed.size == 1);
1128 assert(!ctx.vec_has_prev_changed.data[0].has_prev);
1130 assert(ctx.vec_has_next_changed.size == 0);
1132 /* no more previous item */
1133 assert(!vlc_playlist_HasPrev(playlist));
1135 /* returns an error, but does not crash */
1136 assert(vlc_playlist_Prev(playlist) == VLC_EGENERIC);
1138 callback_ctx_destroy(&ctx);
1139 vlc_playlist_RemoveListener(playlist, listener);
1140 DestroyMediaArray(media, 4);
1141 vlc_playlist_Delete(playlist);
1144 static void
1145 test_next(void)
1147 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1148 assert(playlist);
1150 input_item_t *media[3];
1151 CreateDummyMediaArray(media, 3);
1153 /* initial playlist with 3 items */
1154 int ret = vlc_playlist_Append(playlist, media, 3);
1155 assert(ret == VLC_SUCCESS);
1157 struct vlc_playlist_callbacks cbs = {
1158 .on_current_index_changed = callback_on_current_index_changed,
1159 .on_has_prev_changed = callback_on_has_prev_changed,
1160 .on_has_next_changed = callback_on_has_next_changed,
1163 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1164 vlc_playlist_listener_id *listener =
1165 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1166 assert(listener);
1168 playlist->current = 0; /* first item */
1169 playlist->has_prev = false;
1170 playlist->has_next = true;
1172 /* go to the next item (at index 1) */
1173 assert(vlc_playlist_HasNext(playlist));
1174 ret = vlc_playlist_Next(playlist);
1175 assert(ret == VLC_SUCCESS);
1177 assert(playlist->current == 1);
1178 assert(playlist->has_prev);
1179 assert(playlist->has_next);
1181 assert(ctx.vec_current_index_changed.size == 1);
1182 assert(ctx.vec_current_index_changed.data[0].current == 1);
1184 assert(ctx.vec_has_prev_changed.size == 1);
1185 assert(ctx.vec_has_prev_changed.data[0].has_prev);
1187 assert(ctx.vec_has_next_changed.size == 0);
1189 callback_ctx_reset(&ctx);
1191 /* go to the next item (at index 2) */
1192 assert(vlc_playlist_HasNext(playlist));
1193 ret = vlc_playlist_Next(playlist);
1194 assert(ret == VLC_SUCCESS);
1196 assert(playlist->current == 2);
1197 assert(playlist->has_prev);
1198 assert(!playlist->has_next);
1200 assert(ctx.vec_current_index_changed.size == 1);
1201 assert(ctx.vec_current_index_changed.data[0].current == 2);
1203 assert(ctx.vec_has_prev_changed.size == 0);
1205 assert(ctx.vec_has_next_changed.size == 1);
1206 assert(!ctx.vec_has_next_changed.data[0].has_next);
1208 /* no more next item */
1209 assert(!vlc_playlist_HasNext(playlist));
1211 /* returns an error, but does not crash */
1212 assert(vlc_playlist_Next(playlist) == VLC_EGENERIC);
1214 callback_ctx_destroy(&ctx);
1215 vlc_playlist_RemoveListener(playlist, listener);
1216 DestroyMediaArray(media, 3);
1217 vlc_playlist_Delete(playlist);
1220 static void
1221 test_goto(void)
1223 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1224 assert(playlist);
1226 input_item_t *media[10];
1227 CreateDummyMediaArray(media, 10);
1229 /* initial playlist with 10 items */
1230 int ret = vlc_playlist_Append(playlist, media, 10);
1231 assert(ret == VLC_SUCCESS);
1233 struct vlc_playlist_callbacks cbs = {
1234 .on_current_index_changed = callback_on_current_index_changed,
1235 .on_has_prev_changed = callback_on_has_prev_changed,
1236 .on_has_next_changed = callback_on_has_next_changed,
1239 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1240 vlc_playlist_listener_id *listener =
1241 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1242 assert(listener);
1244 /* go to an item in the middle */
1245 ret = vlc_playlist_GoTo(playlist, 4);
1246 assert(ret == VLC_SUCCESS);
1248 assert(playlist->current == 4);
1249 assert(playlist->has_prev);
1250 assert(playlist->has_next);
1252 assert(ctx.vec_current_index_changed.size == 1);
1253 assert(ctx.vec_current_index_changed.data[0].current == 4);
1255 assert(ctx.vec_has_prev_changed.size == 1);
1256 assert(ctx.vec_has_prev_changed.data[0].has_prev);
1258 assert(ctx.vec_has_next_changed.size == 0);
1260 callback_ctx_reset(&ctx);
1262 /* go to the same item */
1263 ret = vlc_playlist_GoTo(playlist, 4);
1264 assert(ret == VLC_SUCCESS);
1266 assert(playlist->current == 4);
1267 assert(playlist->has_prev);
1268 assert(playlist->has_next);
1270 assert(ctx.vec_current_index_changed.size == 0);
1271 assert(ctx.vec_has_prev_changed.size == 0);
1272 assert(ctx.vec_has_next_changed.size == 0);
1274 callback_ctx_reset(&ctx);
1276 /* go to the first item */
1277 ret = vlc_playlist_GoTo(playlist, 0);
1278 assert(ret == VLC_SUCCESS);
1280 assert(playlist->current == 0);
1281 assert(!playlist->has_prev);
1282 assert(playlist->has_next);
1284 assert(ctx.vec_current_index_changed.size == 1);
1285 assert(ctx.vec_current_index_changed.data[0].current == 0);
1287 assert(ctx.vec_has_prev_changed.size == 1);
1288 assert(!ctx.vec_has_prev_changed.data[0].has_prev);
1290 assert(ctx.vec_has_next_changed.size == 0);
1292 callback_ctx_reset(&ctx);
1294 /* go to the last item */
1295 ret = vlc_playlist_GoTo(playlist, 9);
1296 assert(ret == VLC_SUCCESS);
1298 assert(playlist->current == 9);
1299 assert(playlist->has_prev);
1300 assert(!playlist->has_next);
1302 assert(ctx.vec_current_index_changed.size == 1);
1303 assert(ctx.vec_current_index_changed.data[0].current == 9);
1305 assert(ctx.vec_has_prev_changed.size == 1);
1306 assert(ctx.vec_has_prev_changed.data[0].has_prev);
1308 assert(ctx.vec_has_next_changed.size == 1);
1309 assert(!ctx.vec_has_next_changed.data[0].has_next);
1311 callback_ctx_reset(&ctx);
1313 /* deselect current */
1314 ret = vlc_playlist_GoTo(playlist, -1);
1315 assert(ret == VLC_SUCCESS);
1317 assert(playlist->current == -1);
1318 assert(!playlist->has_prev);
1319 assert(playlist->has_next);
1321 assert(ctx.vec_current_index_changed.size == 1);
1322 assert(ctx.vec_current_index_changed.data[0].current == -1);
1324 assert(ctx.vec_has_prev_changed.size == 1);
1325 assert(!ctx.vec_has_prev_changed.data[0].has_prev);
1327 assert(ctx.vec_has_next_changed.size == 1);
1328 assert(ctx.vec_has_next_changed.data[0].has_next);
1330 callback_ctx_destroy(&ctx);
1331 vlc_playlist_RemoveListener(playlist, listener);
1332 DestroyMediaArray(media, 10);
1333 vlc_playlist_Delete(playlist);
1336 static void
1337 test_request_insert(void)
1339 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1340 assert(playlist);
1342 input_item_t *media[5];
1343 CreateDummyMediaArray(media, 5);
1345 /* initial playlist with 3 items */
1346 int ret = vlc_playlist_Append(playlist, media, 3);
1347 assert(ret == VLC_SUCCESS);
1349 struct vlc_playlist_callbacks cbs = {
1350 .on_items_added = callback_on_items_added,
1353 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1354 vlc_playlist_listener_id *listener =
1355 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1356 assert(listener);
1358 /* insert 5 items at index 10 (out-of-bounds) */
1359 ret = vlc_playlist_RequestInsert(playlist, 10, &media[3], 2);
1360 assert(ret == VLC_SUCCESS);
1362 assert(vlc_playlist_Count(playlist) == 5);
1364 EXPECT_AT(0, 0);
1365 EXPECT_AT(1, 1);
1366 EXPECT_AT(2, 2);
1367 EXPECT_AT(3, 3);
1368 EXPECT_AT(4, 4);
1370 assert(ctx.vec_items_added.size == 1);
1371 assert(ctx.vec_items_added.data[0].index == 3); /* index was changed */
1372 assert(ctx.vec_items_added.data[0].count == 2);
1373 assert(ctx.vec_items_added.data[0].state.playlist_size == 5);
1375 callback_ctx_destroy(&ctx);
1376 vlc_playlist_RemoveListener(playlist, listener);
1377 DestroyMediaArray(media, 5);
1378 vlc_playlist_Delete(playlist);
1381 static void
1382 test_request_remove_with_matching_hint(void)
1384 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1385 assert(playlist);
1387 input_item_t *media[10];
1388 CreateDummyMediaArray(media, 10);
1390 /* initial playlist with 10 items */
1391 int ret = vlc_playlist_Append(playlist, media, 10);
1392 assert(ret == VLC_SUCCESS);
1394 struct vlc_playlist_callbacks cbs = {
1395 .on_items_removed = callback_on_items_removed,
1398 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1399 vlc_playlist_listener_id *listener =
1400 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1401 assert(listener);
1403 vlc_playlist_item_t *items_to_remove[] = {
1404 vlc_playlist_Get(playlist, 3),
1405 vlc_playlist_Get(playlist, 4),
1406 vlc_playlist_Get(playlist, 5),
1407 vlc_playlist_Get(playlist, 6),
1410 ret = vlc_playlist_RequestRemove(playlist, items_to_remove, 4, 3);
1411 assert(ret == VLC_SUCCESS);
1413 assert(vlc_playlist_Count(playlist) == 6);
1415 EXPECT_AT(0, 0);
1416 EXPECT_AT(1, 1);
1417 EXPECT_AT(2, 2);
1418 EXPECT_AT(3, 7);
1419 EXPECT_AT(4, 8);
1420 EXPECT_AT(5, 9);
1422 assert(ctx.vec_items_removed.size == 1);
1423 assert(ctx.vec_items_removed.data[0].index == 3);
1424 assert(ctx.vec_items_removed.data[0].count == 4);
1425 assert(ctx.vec_items_removed.data[0].state.playlist_size == 6);
1427 callback_ctx_destroy(&ctx);
1428 vlc_playlist_RemoveListener(playlist, listener);
1429 DestroyMediaArray(media, 10);
1430 vlc_playlist_Delete(playlist);
1433 static void
1434 test_request_remove_without_hint(void)
1436 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1437 assert(playlist);
1439 input_item_t *media[10];
1440 CreateDummyMediaArray(media, 10);
1442 /* initial playlist with 10 items */
1443 int ret = vlc_playlist_Append(playlist, media, 10);
1444 assert(ret == VLC_SUCCESS);
1446 struct vlc_playlist_callbacks cbs = {
1447 .on_items_removed = callback_on_items_removed,
1450 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1451 vlc_playlist_listener_id *listener =
1452 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1453 assert(listener);
1455 vlc_playlist_item_t *items_to_remove[] = {
1456 vlc_playlist_Get(playlist, 3),
1457 vlc_playlist_Get(playlist, 4),
1458 vlc_playlist_Get(playlist, 5),
1459 vlc_playlist_Get(playlist, 6),
1462 ret = vlc_playlist_RequestRemove(playlist, items_to_remove, 4, -1);
1463 assert(ret == VLC_SUCCESS);
1465 assert(vlc_playlist_Count(playlist) == 6);
1467 EXPECT_AT(0, 0);
1468 EXPECT_AT(1, 1);
1469 EXPECT_AT(2, 2);
1470 EXPECT_AT(3, 7);
1471 EXPECT_AT(4, 8);
1472 EXPECT_AT(5, 9);
1474 assert(ctx.vec_items_removed.size == 1);
1475 assert(ctx.vec_items_removed.data[0].index == 3);
1476 assert(ctx.vec_items_removed.data[0].count == 4);
1477 assert(ctx.vec_items_removed.data[0].state.playlist_size == 6);
1479 callback_ctx_destroy(&ctx);
1480 vlc_playlist_RemoveListener(playlist, listener);
1481 DestroyMediaArray(media, 10);
1482 vlc_playlist_Delete(playlist);
1485 static void
1486 test_request_remove_adapt(void)
1488 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1489 assert(playlist);
1491 input_item_t *media[11];
1492 CreateDummyMediaArray(media, 11);
1494 /* initial playlist with 10 items */
1495 int ret = vlc_playlist_Append(playlist, media, 10);
1496 assert(ret == VLC_SUCCESS);
1498 struct vlc_playlist_callbacks cbs = {
1499 .on_items_removed = callback_on_items_removed,
1502 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1503 vlc_playlist_listener_id *listener =
1504 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1505 assert(listener);
1507 vlc_playlist_item_t *dummy = vlc_playlist_item_New(media[10], 0);
1508 assert(dummy);
1510 /* remove items in a wrong order at wrong position, as if the playlist had
1511 * been sorted/shuffled before the request were applied */
1512 vlc_playlist_item_t *items_to_remove[] = {
1513 vlc_playlist_Get(playlist, 3),
1514 vlc_playlist_Get(playlist, 2),
1515 vlc_playlist_Get(playlist, 6),
1516 vlc_playlist_Get(playlist, 9),
1517 vlc_playlist_Get(playlist, 1),
1518 dummy, /* inexistant */
1519 vlc_playlist_Get(playlist, 8),
1522 ret = vlc_playlist_RequestRemove(playlist, items_to_remove, 7, 3);
1523 assert(ret == VLC_SUCCESS);
1525 vlc_playlist_item_Release(dummy);
1527 assert(vlc_playlist_Count(playlist) == 4);
1529 EXPECT_AT(0, 0);
1530 EXPECT_AT(1, 4);
1531 EXPECT_AT(2, 5);
1532 EXPECT_AT(3, 7);
1534 /* it should notify 3 different slices removed, in descending order for
1535 * optimization: {8,9}, {6}, {1,2,3}. */
1537 assert(ctx.vec_items_removed.size == 3);
1539 assert(ctx.vec_items_removed.data[0].index == 8);
1540 assert(ctx.vec_items_removed.data[0].count == 2);
1541 assert(ctx.vec_items_removed.data[0].state.playlist_size == 8);
1543 assert(ctx.vec_items_removed.data[1].index == 6);
1544 assert(ctx.vec_items_removed.data[1].count == 1);
1545 assert(ctx.vec_items_removed.data[1].state.playlist_size == 7);
1547 assert(ctx.vec_items_removed.data[2].index == 1);
1548 assert(ctx.vec_items_removed.data[2].count == 3);
1549 assert(ctx.vec_items_removed.data[2].state.playlist_size == 4);
1551 callback_ctx_destroy(&ctx);
1552 vlc_playlist_RemoveListener(playlist, listener);
1553 DestroyMediaArray(media, 11);
1554 vlc_playlist_Delete(playlist);
1557 static void
1558 test_request_move_with_matching_hint(void)
1560 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1561 assert(playlist);
1563 input_item_t *media[10];
1564 CreateDummyMediaArray(media, 10);
1566 /* initial playlist with 10 items */
1567 int ret = vlc_playlist_Append(playlist, media, 10);
1568 assert(ret == VLC_SUCCESS);
1570 struct vlc_playlist_callbacks cbs = {
1571 .on_items_moved = callback_on_items_moved,
1574 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1575 vlc_playlist_listener_id *listener =
1576 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1577 assert(listener);
1579 vlc_playlist_item_t *items_to_move[] = {
1580 vlc_playlist_Get(playlist, 5),
1581 vlc_playlist_Get(playlist, 6),
1582 vlc_playlist_Get(playlist, 7),
1583 vlc_playlist_Get(playlist, 8),
1586 ret = vlc_playlist_RequestMove(playlist, items_to_move, 4, 2, 5);
1587 assert(ret == VLC_SUCCESS);
1589 assert(vlc_playlist_Count(playlist) == 10);
1591 EXPECT_AT(0, 0);
1592 EXPECT_AT(1, 1);
1593 EXPECT_AT(2, 5);
1594 EXPECT_AT(3, 6);
1595 EXPECT_AT(4, 7);
1596 EXPECT_AT(5, 8);
1597 EXPECT_AT(6, 2);
1598 EXPECT_AT(7, 3);
1599 EXPECT_AT(8, 4);
1600 EXPECT_AT(9, 9);
1602 assert(ctx.vec_items_moved.size == 1);
1603 assert(ctx.vec_items_moved.data[0].index == 5);
1604 assert(ctx.vec_items_moved.data[0].count == 4);
1605 assert(ctx.vec_items_moved.data[0].state.playlist_size == 10);
1607 callback_ctx_destroy(&ctx);
1608 vlc_playlist_RemoveListener(playlist, listener);
1609 DestroyMediaArray(media, 10);
1610 vlc_playlist_Delete(playlist);
1613 static void
1614 test_request_move_without_hint(void)
1616 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1617 assert(playlist);
1619 input_item_t *media[10];
1620 CreateDummyMediaArray(media, 10);
1622 /* initial playlist with 10 items */
1623 int ret = vlc_playlist_Append(playlist, media, 10);
1624 assert(ret == VLC_SUCCESS);
1626 struct vlc_playlist_callbacks cbs = {
1627 .on_items_moved = callback_on_items_moved,
1630 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1631 vlc_playlist_listener_id *listener =
1632 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1633 assert(listener);
1635 vlc_playlist_item_t *items_to_move[] = {
1636 vlc_playlist_Get(playlist, 5),
1637 vlc_playlist_Get(playlist, 6),
1638 vlc_playlist_Get(playlist, 7),
1639 vlc_playlist_Get(playlist, 8),
1642 ret = vlc_playlist_RequestMove(playlist, items_to_move, 4, 2, -1);
1643 assert(ret == VLC_SUCCESS);
1645 assert(vlc_playlist_Count(playlist) == 10);
1647 EXPECT_AT(0, 0);
1648 EXPECT_AT(1, 1);
1649 EXPECT_AT(2, 5);
1650 EXPECT_AT(3, 6);
1651 EXPECT_AT(4, 7);
1652 EXPECT_AT(5, 8);
1653 EXPECT_AT(6, 2);
1654 EXPECT_AT(7, 3);
1655 EXPECT_AT(8, 4);
1656 EXPECT_AT(9, 9);
1658 assert(ctx.vec_items_moved.size == 1);
1659 assert(ctx.vec_items_moved.data[0].index == 5);
1660 assert(ctx.vec_items_moved.data[0].count == 4);
1661 assert(ctx.vec_items_moved.data[0].state.playlist_size == 10);
1663 vlc_playlist_item_t *item = vlc_playlist_Get(playlist, 3);
1664 /* move it to index 42 (out of bounds) */
1665 vlc_playlist_RequestMove(playlist, &item, 1, 42, -1);
1667 EXPECT_AT(0, 0);
1668 EXPECT_AT(1, 1);
1669 EXPECT_AT(2, 5);
1670 EXPECT_AT(3, 7);
1671 EXPECT_AT(4, 8);
1672 EXPECT_AT(5, 2);
1673 EXPECT_AT(6, 3);
1674 EXPECT_AT(7, 4);
1675 EXPECT_AT(8, 9);
1676 EXPECT_AT(9, 6);
1678 callback_ctx_destroy(&ctx);
1679 vlc_playlist_RemoveListener(playlist, listener);
1680 DestroyMediaArray(media, 10);
1681 vlc_playlist_Delete(playlist);
1684 static void
1685 test_request_move_adapt(void)
1687 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1688 assert(playlist);
1690 input_item_t *media[16];
1691 CreateDummyMediaArray(media, 16);
1693 /* initial playlist with 15 items */
1694 int ret = vlc_playlist_Append(playlist, media, 15);
1695 assert(ret == VLC_SUCCESS);
1697 struct vlc_playlist_callbacks cbs = {
1698 .on_items_moved = callback_on_items_moved,
1701 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1702 vlc_playlist_listener_id *listener =
1703 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1704 assert(listener);
1706 vlc_playlist_item_t *dummy = vlc_playlist_item_New(media[15], 0);
1707 assert(dummy);
1709 /* move items in a wrong order at wrong position, as if the playlist had
1710 * been sorted/shuffled before the request were applied */
1711 vlc_playlist_item_t *items_to_move[] = {
1712 vlc_playlist_Get(playlist, 7),
1713 vlc_playlist_Get(playlist, 8),
1714 vlc_playlist_Get(playlist, 5),
1715 vlc_playlist_Get(playlist, 12),
1716 dummy, /* inexistant */
1717 vlc_playlist_Get(playlist, 3),
1718 vlc_playlist_Get(playlist, 13),
1719 vlc_playlist_Get(playlist, 14),
1720 vlc_playlist_Get(playlist, 1),
1723 vlc_playlist_RequestMove(playlist, items_to_move, 9, 3, 2);
1725 vlc_playlist_item_Release(dummy);
1727 assert(vlc_playlist_Count(playlist) == 15);
1729 EXPECT_AT(0, 0);
1730 EXPECT_AT(1, 2);
1731 EXPECT_AT(2, 4);
1733 EXPECT_AT(3, 7);
1734 EXPECT_AT(4, 8);
1735 EXPECT_AT(5, 5);
1736 EXPECT_AT(6, 12);
1737 EXPECT_AT(7, 3);
1738 EXPECT_AT(8, 13);
1739 EXPECT_AT(9, 14);
1740 EXPECT_AT(10, 1);
1742 EXPECT_AT(11, 6);
1743 EXPECT_AT(12, 9);
1744 EXPECT_AT(13, 10);
1745 EXPECT_AT(14, 11);
1747 /* there are 6 slices to move: 7-8, 5, 12, 3, 13-14, 1 */
1748 assert(ctx.vec_items_moved.size == 6);
1750 struct VLC_VECTOR(int) vec = VLC_VECTOR_INITIALIZER;
1751 for (int i = 0; i < 15; ++i)
1752 vlc_vector_push(&vec, i * 10);
1754 struct items_moved_report report;
1755 vlc_vector_foreach(report, &ctx.vec_items_moved)
1756 /* apply the changes as reported by the callbacks */
1757 vlc_vector_move_slice(&vec, report.index, report.count, report.target);
1759 /* the vector items must have been moved the same way as the playlist */
1760 assert(vec.size == 15);
1761 assert(vec.data[0] == 0);
1762 assert(vec.data[1] == 20);
1763 assert(vec.data[2] == 40);
1764 assert(vec.data[3] == 70);
1765 assert(vec.data[4] == 80);
1766 assert(vec.data[5] == 50);
1767 assert(vec.data[6] == 120);
1768 assert(vec.data[7] == 30);
1769 assert(vec.data[8] == 130);
1770 assert(vec.data[9] == 140);
1771 assert(vec.data[10] == 10);
1772 assert(vec.data[11] == 60);
1773 assert(vec.data[12] == 90);
1774 assert(vec.data[13] == 100);
1775 assert(vec.data[14] == 110);
1777 vlc_vector_destroy(&vec);
1779 callback_ctx_destroy(&ctx);
1780 vlc_playlist_RemoveListener(playlist, listener);
1781 DestroyMediaArray(media, 16);
1782 vlc_playlist_Delete(playlist);
1785 static void
1786 test_request_move_to_end_adapt(void)
1788 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1789 assert(playlist);
1791 input_item_t *media[16];
1792 CreateDummyMediaArray(media, 16);
1794 /* initial playlist with 15 items */
1795 int ret = vlc_playlist_Append(playlist, media, 15);
1796 assert(ret == VLC_SUCCESS);
1798 struct vlc_playlist_callbacks cbs = {
1799 .on_items_moved = callback_on_items_moved,
1802 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1803 vlc_playlist_listener_id *listener =
1804 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1805 assert(listener);
1807 vlc_playlist_item_t *dummy = vlc_playlist_item_New(media[15], 0);
1808 assert(dummy);
1810 /* move items in a wrong order at wrong position, as if the playlist had
1811 * been sorted/shuffled before the request were applied */
1812 vlc_playlist_item_t *items_to_move[] = {
1813 vlc_playlist_Get(playlist, 7),
1814 vlc_playlist_Get(playlist, 8),
1815 vlc_playlist_Get(playlist, 5),
1816 vlc_playlist_Get(playlist, 12),
1817 dummy, /* inexistant */
1818 vlc_playlist_Get(playlist, 3),
1819 vlc_playlist_Get(playlist, 13),
1820 vlc_playlist_Get(playlist, 14),
1821 vlc_playlist_Get(playlist, 1),
1824 /* target 20 is far beyond the end of the list */
1825 vlc_playlist_RequestMove(playlist, items_to_move, 9, 20, 2);
1827 vlc_playlist_item_Release(dummy);
1829 assert(vlc_playlist_Count(playlist) == 15);
1831 EXPECT_AT(0, 0);
1832 EXPECT_AT(1, 2);
1833 EXPECT_AT(2, 4);
1834 EXPECT_AT(3, 6);
1835 EXPECT_AT(4, 9);
1836 EXPECT_AT(5, 10);
1837 EXPECT_AT(6, 11);
1839 EXPECT_AT(7, 7);
1840 EXPECT_AT(8, 8);
1841 EXPECT_AT(9, 5);
1842 EXPECT_AT(10, 12);
1843 EXPECT_AT(11, 3);
1844 EXPECT_AT(12, 13);
1845 EXPECT_AT(13, 14);
1846 EXPECT_AT(14, 1);
1848 /* there are 6 slices to move: 7-8, 5, 12, 3, 13-14, 1 */
1849 assert(ctx.vec_items_moved.size == 6);
1851 struct VLC_VECTOR(int) vec = VLC_VECTOR_INITIALIZER;
1852 for (int i = 0; i < 15; ++i)
1853 vlc_vector_push(&vec, i * 10);
1855 struct items_moved_report report;
1856 vlc_vector_foreach(report, &ctx.vec_items_moved)
1857 /* apply the changes as reported by the callbacks */
1858 vlc_vector_move_slice(&vec, report.index, report.count, report.target);
1860 /* the vector items must have been moved the same way as the playlist */
1861 assert(vec.size == 15);
1862 assert(vec.data[0] == 0);
1863 assert(vec.data[1] == 20);
1864 assert(vec.data[2] == 40);
1865 assert(vec.data[3] == 60);
1866 assert(vec.data[4] == 90);
1867 assert(vec.data[5] == 100);
1868 assert(vec.data[6] == 110);
1869 assert(vec.data[7] == 70);
1870 assert(vec.data[8] == 80);
1871 assert(vec.data[9] == 50);
1872 assert(vec.data[10] == 120);
1873 assert(vec.data[11] == 30);
1874 assert(vec.data[12] == 130);
1875 assert(vec.data[13] == 140);
1876 assert(vec.data[14] == 10);
1878 vlc_vector_destroy(&vec);
1880 callback_ctx_destroy(&ctx);
1881 vlc_playlist_RemoveListener(playlist, listener);
1882 DestroyMediaArray(media, 16);
1883 vlc_playlist_Delete(playlist);
1886 static void
1887 test_request_goto_with_matching_hint(void)
1889 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1890 assert(playlist);
1892 input_item_t *media[10];
1893 CreateDummyMediaArray(media, 10);
1895 /* initial playlist with 10 items */
1896 int ret = vlc_playlist_Append(playlist, media, 10);
1897 assert(ret == VLC_SUCCESS);
1899 struct vlc_playlist_callbacks cbs = {
1900 .on_current_index_changed = callback_on_current_index_changed,
1901 .on_has_prev_changed = callback_on_has_prev_changed,
1902 .on_has_next_changed = callback_on_has_next_changed,
1905 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1906 vlc_playlist_listener_id *listener =
1907 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1908 assert(listener);
1910 /* go to an item in the middle, with incorrect index_hint */
1911 vlc_playlist_item_t *item = vlc_playlist_Get(playlist, 4);
1912 ret = vlc_playlist_RequestGoTo(playlist, item, 4);
1913 assert(ret == VLC_SUCCESS);
1915 assert(playlist->current == 4);
1916 assert(playlist->has_prev);
1917 assert(playlist->has_next);
1919 assert(ctx.vec_current_index_changed.size == 1);
1920 assert(ctx.vec_current_index_changed.data[0].current == 4);
1922 assert(ctx.vec_has_prev_changed.size == 1);
1923 assert(ctx.vec_has_prev_changed.data[0].has_prev);
1925 assert(ctx.vec_has_next_changed.size == 0);
1927 callback_ctx_destroy(&ctx);
1928 vlc_playlist_RemoveListener(playlist, listener);
1929 DestroyMediaArray(media, 10);
1930 vlc_playlist_Delete(playlist);
1933 static void
1934 test_request_goto_without_hint(void)
1936 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1937 assert(playlist);
1939 input_item_t *media[10];
1940 CreateDummyMediaArray(media, 10);
1942 /* initial playlist with 10 items */
1943 int ret = vlc_playlist_Append(playlist, media, 10);
1944 assert(ret == VLC_SUCCESS);
1946 struct vlc_playlist_callbacks cbs = {
1947 .on_current_index_changed = callback_on_current_index_changed,
1948 .on_has_prev_changed = callback_on_has_prev_changed,
1949 .on_has_next_changed = callback_on_has_next_changed,
1952 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
1953 vlc_playlist_listener_id *listener =
1954 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
1955 assert(listener);
1957 /* go to an item in the middle, with incorrect index_hint */
1958 vlc_playlist_item_t *item = vlc_playlist_Get(playlist, 4);
1959 ret = vlc_playlist_RequestGoTo(playlist, item, -1); /* no hint */
1960 assert(ret == VLC_SUCCESS);
1962 assert(playlist->current == 4);
1963 assert(playlist->has_prev);
1964 assert(playlist->has_next);
1966 assert(ctx.vec_current_index_changed.size == 1);
1967 assert(ctx.vec_current_index_changed.data[0].current == 4);
1969 assert(ctx.vec_has_prev_changed.size == 1);
1970 assert(ctx.vec_has_prev_changed.data[0].has_prev);
1972 assert(ctx.vec_has_next_changed.size == 0);
1974 callback_ctx_destroy(&ctx);
1975 vlc_playlist_RemoveListener(playlist, listener);
1976 DestroyMediaArray(media, 10);
1977 vlc_playlist_Delete(playlist);
1980 static void
1981 test_request_goto_adapt(void)
1983 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
1984 assert(playlist);
1986 input_item_t *media[10];
1987 CreateDummyMediaArray(media, 10);
1989 /* initial playlist with 10 items */
1990 int ret = vlc_playlist_Append(playlist, media, 10);
1991 assert(ret == VLC_SUCCESS);
1993 struct vlc_playlist_callbacks cbs = {
1994 .on_current_index_changed = callback_on_current_index_changed,
1995 .on_has_prev_changed = callback_on_has_prev_changed,
1996 .on_has_next_changed = callback_on_has_next_changed,
1999 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
2000 vlc_playlist_listener_id *listener =
2001 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
2002 assert(listener);
2004 /* go to an item in the middle, with incorrect index_hint */
2005 vlc_playlist_item_t *item = vlc_playlist_Get(playlist, 4);
2006 ret = vlc_playlist_RequestGoTo(playlist, item, 7); /* wrong index hint */
2007 assert(ret == VLC_SUCCESS);
2009 assert(playlist->current == 4);
2010 assert(playlist->has_prev);
2011 assert(playlist->has_next);
2013 assert(ctx.vec_current_index_changed.size == 1);
2014 assert(ctx.vec_current_index_changed.data[0].current == 4);
2016 assert(ctx.vec_has_prev_changed.size == 1);
2017 assert(ctx.vec_has_prev_changed.data[0].has_prev);
2019 assert(ctx.vec_has_next_changed.size == 0);
2021 callback_ctx_destroy(&ctx);
2022 vlc_playlist_RemoveListener(playlist, listener);
2023 DestroyMediaArray(media, 10);
2024 vlc_playlist_Delete(playlist);
2027 /* this only tests that the randomizer is correctly managed by the playlist,
2028 * for further tests on randomization properties, see randomizer tests. */
2029 static void
2030 test_random(void)
2032 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
2033 assert(playlist);
2035 input_item_t *media[6];
2036 CreateDummyMediaArray(media, 6);
2038 /* initial playlist with 5 items (1 is not added immediately) */
2039 int ret = vlc_playlist_Append(playlist, media, 5);
2040 assert(ret == VLC_SUCCESS);
2042 struct vlc_playlist_callbacks cbs = {
2043 .on_current_index_changed = callback_on_current_index_changed,
2044 .on_has_prev_changed = callback_on_has_prev_changed,
2045 .on_has_next_changed = callback_on_has_next_changed,
2048 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
2049 vlc_playlist_listener_id *listener =
2050 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
2051 assert(listener);
2053 assert(!vlc_playlist_HasPrev(playlist));
2054 assert(vlc_playlist_HasNext(playlist));
2056 for (int i = 0; i < 3; ++i)
2058 assert(vlc_playlist_HasNext(playlist));
2059 ret = vlc_playlist_Next(playlist);
2060 assert(ret == VLC_SUCCESS);
2063 assert(vlc_playlist_HasPrev(playlist));
2064 vlc_playlist_SetPlaybackOrder(playlist, VLC_PLAYLIST_PLAYBACK_ORDER_RANDOM);
2066 /* in random order, previous uses the history of randomly selected items */
2067 assert(!vlc_playlist_HasPrev(playlist));
2069 bool selected[5] = {};
2070 for (int i = 0; i < 5; ++i)
2072 assert(vlc_playlist_HasNext(playlist));
2073 ret = vlc_playlist_Next(playlist);
2074 assert(ret == VLC_SUCCESS);
2075 ssize_t index = vlc_playlist_GetCurrentIndex(playlist);
2076 assert(index != -1);
2077 assert(!selected[index]); /* not selected twice */
2078 selected[index] = true;
2081 assert(!vlc_playlist_HasNext(playlist));
2083 /* add a new item, it must be taken into account */
2084 ret = vlc_playlist_AppendOne(playlist, media[5]);
2085 assert(ret == VLC_SUCCESS);
2086 assert(vlc_playlist_HasNext(playlist));
2088 ret = vlc_playlist_Next(playlist);
2089 assert(ret == VLC_SUCCESS);
2091 assert(vlc_playlist_GetCurrentIndex(playlist) == 5);
2092 assert(!vlc_playlist_HasNext(playlist));
2094 vlc_playlist_RemoveOne(playlist, 5);
2096 /* enable repeat */
2097 vlc_playlist_SetPlaybackRepeat(playlist, VLC_PLAYLIST_PLAYBACK_REPEAT_ALL);
2099 /* now there are more items */
2100 assert(vlc_playlist_HasNext(playlist));
2102 /* once again */
2103 memset(selected, 0, sizeof(selected));
2104 for (int i = 0; i < 5; ++i)
2106 assert(vlc_playlist_HasNext(playlist));
2107 ret = vlc_playlist_Next(playlist);
2108 assert(ret == VLC_SUCCESS);
2109 ssize_t index = vlc_playlist_GetCurrentIndex(playlist);
2110 assert(index != -1);
2111 assert(!selected[index]); /* not selected twice */
2112 selected[index] = true;
2115 /* there are always more items */
2116 assert(vlc_playlist_HasNext(playlist));
2118 /* move to the middle of the random array */
2119 for (int i = 0; i < 3; ++i)
2121 assert(vlc_playlist_HasNext(playlist));
2122 ret = vlc_playlist_Next(playlist);
2123 assert(ret == VLC_SUCCESS);
2126 memset(selected, 0, sizeof(selected));
2127 int actual[5]; /* store the selected items (by their index) */
2129 ssize_t current = vlc_playlist_GetCurrentIndex(playlist);
2130 assert(current != -1);
2131 actual[4] = current;
2133 for (int i = 3; i >= 0; --i)
2135 assert(vlc_playlist_HasPrev(playlist));
2136 ret = vlc_playlist_Prev(playlist);
2137 assert(ret == VLC_SUCCESS);
2138 ssize_t index = vlc_playlist_GetCurrentIndex(playlist);
2139 assert(index != -1);
2140 actual[i] = index;
2141 assert(!selected[index]); /* not selected twice */
2142 selected[index] = true;
2145 /* no more previous, the history may only contain each item once */
2146 assert(!vlc_playlist_HasPrev(playlist));
2148 /* we should get the same items in the reverse order going forward */
2149 for (int i = 1; i < 5; ++i)
2151 assert(vlc_playlist_HasNext(playlist));
2152 ret = vlc_playlist_Next(playlist);
2153 assert(ret == VLC_SUCCESS);
2154 ssize_t index = vlc_playlist_GetCurrentIndex(playlist);
2155 assert(index != -1);
2156 assert(index == actual[i]);
2159 /* there are always more items */
2160 assert(vlc_playlist_HasNext(playlist));
2162 callback_ctx_destroy(&ctx);
2163 vlc_playlist_RemoveListener(playlist, listener);
2164 DestroyMediaArray(media, 6);
2165 vlc_playlist_Delete(playlist);
2168 static void
2169 test_shuffle(void)
2171 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
2172 assert(playlist);
2174 input_item_t *media[10];
2175 CreateDummyMediaArray(media, 10);
2177 /* initial playlist with 10 items */
2178 int ret = vlc_playlist_Append(playlist, media, 10);
2179 assert(ret == VLC_SUCCESS);
2181 struct vlc_playlist_callbacks cbs = {
2182 .on_items_reset = callback_on_items_reset,
2183 .on_current_index_changed = callback_on_current_index_changed,
2184 .on_has_prev_changed = callback_on_has_prev_changed,
2185 .on_has_next_changed = callback_on_has_next_changed,
2188 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
2189 vlc_playlist_listener_id *listener =
2190 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
2191 assert(listener);
2193 playlist->current = 4;
2194 playlist->has_prev = true;
2195 playlist->has_next = true;
2197 vlc_playlist_Shuffle(playlist);
2199 ssize_t index = vlc_playlist_IndexOfMedia(playlist, media[4]);
2200 assert(index != -1);
2201 assert(index == playlist->current);
2203 assert(ctx.vec_items_reset.size == 1);
2204 assert(ctx.vec_items_reset.data[0].count == 10);
2205 assert(ctx.vec_items_reset.data[0].state.playlist_size == 10);
2206 assert(ctx.vec_items_reset.data[0].state.current == index);
2207 assert(ctx.vec_items_reset.data[0].state.has_prev == (index > 0));
2208 assert(ctx.vec_items_reset.data[0].state.has_next == (index < 9));
2210 if (index == 4)
2211 assert(ctx.vec_current_index_changed.size == 0);
2212 else
2214 assert(ctx.vec_current_index_changed.size == 1);
2215 assert(ctx.vec_current_index_changed.data[0].current == index);
2218 if (index == 0)
2220 assert(!playlist->has_prev);
2221 assert(ctx.vec_has_prev_changed.size == 1);
2222 assert(!ctx.vec_has_prev_changed.data[0].has_prev);
2224 else
2226 assert(playlist->has_prev);
2227 assert(ctx.vec_has_prev_changed.size == 0);
2230 if (index == 9)
2232 assert(!playlist->has_next);
2233 assert(ctx.vec_has_next_changed.size == 1);
2234 assert(!ctx.vec_has_next_changed.data[0].has_next);
2236 else
2238 assert(playlist->has_next);
2239 assert(ctx.vec_has_next_changed.size == 0);
2242 callback_ctx_destroy(&ctx);
2243 vlc_playlist_RemoveListener(playlist, listener);
2244 DestroyMediaArray(media, 10);
2245 vlc_playlist_Delete(playlist);
2248 static void
2249 test_sort(void)
2251 vlc_playlist_t *playlist = vlc_playlist_New(NULL);
2252 assert(playlist);
2254 input_item_t *media[10];
2255 media[0] = CreateDummyMedia(4); media[0]->i_duration = 42;
2256 media[1] = CreateDummyMedia(1); media[1]->i_duration = 5;
2257 media[2] = CreateDummyMedia(6); media[2]->i_duration = 100;
2258 media[3] = CreateDummyMedia(2); media[3]->i_duration = 1;
2259 media[4] = CreateDummyMedia(1); media[4]->i_duration = 8;
2260 media[5] = CreateDummyMedia(4); media[5]->i_duration = 23;
2261 media[6] = CreateDummyMedia(3); media[6]->i_duration = 60;
2262 media[7] = CreateDummyMedia(3); media[7]->i_duration = 40;
2263 media[8] = CreateDummyMedia(0); media[8]->i_duration = 42;
2264 media[9] = CreateDummyMedia(5); media[9]->i_duration = 42;
2266 /* initial playlist with 10 items */
2267 int ret = vlc_playlist_Append(playlist, media, 10);
2268 assert(ret == VLC_SUCCESS);
2270 struct vlc_playlist_callbacks cbs = {
2271 .on_items_reset = callback_on_items_reset,
2272 .on_current_index_changed = callback_on_current_index_changed,
2273 .on_has_prev_changed = callback_on_has_prev_changed,
2274 .on_has_next_changed = callback_on_has_next_changed,
2277 struct callback_ctx ctx = CALLBACK_CTX_INITIALIZER;
2278 vlc_playlist_listener_id *listener =
2279 vlc_playlist_AddListener(playlist, &cbs, &ctx, false);
2280 assert(listener);
2282 playlist->current = 0;
2283 playlist->has_prev = false;
2284 playlist->has_next = true;
2286 struct vlc_playlist_sort_criterion criteria1[] = {
2287 { VLC_PLAYLIST_SORT_KEY_TITLE, VLC_PLAYLIST_SORT_ORDER_ASCENDING },
2288 { VLC_PLAYLIST_SORT_KEY_DURATION, VLC_PLAYLIST_SORT_ORDER_ASCENDING },
2290 vlc_playlist_Sort(playlist, criteria1, 2);
2292 EXPECT_AT(0, 8);
2293 EXPECT_AT(1, 1);
2294 EXPECT_AT(2, 4);
2295 EXPECT_AT(3, 3);
2296 EXPECT_AT(4, 7);
2297 EXPECT_AT(5, 6);
2298 EXPECT_AT(6, 5);
2299 EXPECT_AT(7, 0);
2300 EXPECT_AT(8, 9);
2301 EXPECT_AT(9, 2);
2303 ssize_t index = vlc_playlist_IndexOfMedia(playlist, media[0]);
2304 assert(index == 7);
2305 assert(playlist->current == 7);
2307 assert(ctx.vec_items_reset.size == 1);
2308 assert(ctx.vec_items_reset.data[0].count == 10);
2309 assert(ctx.vec_items_reset.data[0].state.playlist_size == 10);
2310 assert(ctx.vec_items_reset.data[0].state.current == 7);
2311 assert(ctx.vec_items_reset.data[0].state.has_prev);
2312 assert(ctx.vec_items_reset.data[0].state.has_next);
2314 assert(ctx.vec_current_index_changed.size == 1);
2315 assert(ctx.vec_current_index_changed.data[0].current == 7);
2317 assert(ctx.vec_has_prev_changed.size == 1);
2318 assert(ctx.vec_has_prev_changed.data[0].has_prev);
2320 assert(ctx.vec_has_next_changed.size == 0);
2322 callback_ctx_reset(&ctx);
2324 struct vlc_playlist_sort_criterion criteria2[] = {
2325 { VLC_PLAYLIST_SORT_KEY_DURATION, VLC_PLAYLIST_SORT_ORDER_DESCENDING },
2326 { VLC_PLAYLIST_SORT_KEY_TITLE, VLC_PLAYLIST_SORT_ORDER_ASCENDING },
2329 vlc_playlist_Sort(playlist, criteria2, 2);
2331 EXPECT_AT(0, 2);
2332 EXPECT_AT(1, 6);
2333 EXPECT_AT(2, 8);
2334 EXPECT_AT(3, 0);
2335 EXPECT_AT(4, 9);
2336 EXPECT_AT(5, 7);
2337 EXPECT_AT(6, 5);
2338 EXPECT_AT(7, 4);
2339 EXPECT_AT(8, 1);
2340 EXPECT_AT(9, 3);
2342 assert(ctx.vec_items_reset.size == 1);
2343 assert(ctx.vec_items_reset.data[0].count == 10);
2344 assert(ctx.vec_items_reset.data[0].state.playlist_size == 10);
2346 callback_ctx_destroy(&ctx);
2347 vlc_playlist_RemoveListener(playlist, listener);
2348 DestroyMediaArray(media, 10);
2349 vlc_playlist_Delete(playlist);
2352 #undef EXPECT_AT
2354 int main(void)
2356 test_append();
2357 test_insert();
2358 test_move();
2359 test_remove();
2360 test_clear();
2361 test_expand_item();
2362 test_items_added_callbacks();
2363 test_items_moved_callbacks();
2364 test_items_removed_callbacks();
2365 test_items_reset_callbacks();
2366 test_playback_repeat_changed_callbacks();
2367 test_playback_order_changed_callbacks();
2368 test_callbacks_on_add_listener();
2369 test_index_of();
2370 test_prev();
2371 test_next();
2372 test_goto();
2373 test_request_insert();
2374 test_request_remove_with_matching_hint();
2375 test_request_remove_without_hint();
2376 test_request_remove_adapt();
2377 test_request_move_with_matching_hint();
2378 test_request_move_without_hint();
2379 test_request_move_adapt();
2380 test_request_move_to_end_adapt();
2381 test_request_goto_with_matching_hint();
2382 test_request_goto_without_hint();
2383 test_request_goto_adapt();
2384 test_random();
2385 test_shuffle();
2386 test_sort();
2387 return 0;
2390 #endif