1 #include "catch.hpp"
2 #include "doc/docundostack.hpp"
3 #include "test_utils.hpp"
4 
5 #include <QString>
6 #include <cmath>
7 #include <iostream>
8 #include <tuple>
9 #include <unordered_set>
10 
11 #include "definitions.h"
12 #define private public
13 #define protected public
14 #include "core.h"
15 
16 using namespace fakeit;
17 Mlt::Profile profile_mix;
18 
19 TEST_CASE("Simple Mix", "[SameTrackMix]")
20 {
21     // Create timeline
22     auto binModel = pCore->projectItemModel();
23     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
24     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
25 
26     // Here we do some trickery to enable testing.
27     // We mock the project class so that the undoStack function returns our undoStack
28 
29     Mock<ProjectManager> pmMock;
30     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
31     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
32 
33     ProjectManager &mocked = pmMock.get();
34     pCore->m_projectManager = &mocked;
35 
36     // We also mock timeline object to spy few functions and mock others
37     TimelineItemModel tim(&profile_mix, undoStack);
38     Mock<TimelineItemModel> timMock(tim);
__anonb3283b290102(...) 39     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
40     TimelineItemModel::finishConstruct(timeline, guideModel);
41 
42         // Create a request
43     int tid1 = TrackModel::construct(timeline, -1, -1, QString(), true);
44     int tid3 = TrackModel::construct(timeline, -1, -1, QString(), true);
45     int tid2 = TrackModel::construct(timeline);
46     int tid4 = TrackModel::construct(timeline);
47 
48     // Create clip with audio
49     QString binId = createProducerWithSound(profile_mix, binModel, 100);
50 
51     // Create video clip
52     QString binId2 = createProducer(profile_mix, "red", binModel, 50, false);
53     // Setup insert stream data
54     QMap <int, QString>audioInfo;
55     audioInfo.insert(1,QStringLiteral("stream1"));
56     timeline->m_binAudioTargets = audioInfo;
57 
58     // Create AV clip 1
59     int cid1;
60     int cid2;
61     int cid3;
62     int cid4;
63     REQUIRE(timeline->requestClipInsertion(binId, tid2, 100, cid1));
64     REQUIRE(timeline->requestItemResize(cid1, 10, true, true));
65 
66     // Create AV clip 2
67     REQUIRE(timeline->requestClipInsertion(binId, tid2, 110, cid2));
68     REQUIRE(timeline->requestItemResize(cid2, 10, true, true));
69     REQUIRE(timeline->requestClipMove(cid2, tid2, 110));
70 
71     // Create color clip 1
72     REQUIRE(timeline->requestClipInsertion(binId2, tid2, 500, cid3));
73     REQUIRE(timeline->requestItemResize(cid3, 20, true, true));
74     REQUIRE(timeline->requestClipInsertion(binId2, tid2, 520, cid4));
75     REQUIRE(timeline->requestItemResize(cid4, 20, true, true));
76     int mixDuration = pCore->getDurationFromString(KdenliveSettings::mix_duration());
77 
__anonb3283b290202() 78     auto state0 = [&]() {
79         REQUIRE(timeline->getClipsCount() == 6);
80         REQUIRE(timeline->getClipPlaytime(cid1) == 10);
81         REQUIRE(timeline->getClipPosition(cid1) == 100);
82         REQUIRE(timeline->getClipPlaytime(cid2) == 10);
83         REQUIRE(timeline->getClipPosition(cid2) == 110);
84         REQUIRE(timeline->getClipPosition(cid3) == 500);
85         REQUIRE(timeline->getClipPlaytime(cid3) == 20);
86         REQUIRE(timeline->getClipPosition(cid4) == 520);
87         REQUIRE(timeline->getClipPlaytime(cid4) == 20);
88         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
89         REQUIRE(timeline->getTrackById_const(tid1)->mixCount() == 0);
90         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
91     };
92 
__anonb3283b290302() 93     auto state1 = [&]() {
94         REQUIRE(timeline->getClipsCount() == 6);
95         REQUIRE(timeline->getClipPlaytime(cid1) > 10);
96         REQUIRE(timeline->getClipPosition(cid1) == 100);
97         REQUIRE(timeline->getClipPlaytime(cid2) > 10);
98         REQUIRE(timeline->getClipPosition(cid2) < 110);
99         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 1);
100         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
101     };
102 
__anonb3283b290402() 103     auto state3 = [&, mixDuration]() {
104         REQUIRE(timeline->getClipsCount() == 6);
105         REQUIRE(timeline->getClipPlaytime(cid1) > 30);
106         REQUIRE(timeline->getClipPosition(cid1) == 100);
107         REQUIRE(timeline->getClipPlaytime(cid2) > 30);
108         REQUIRE(timeline->getClipPosition(cid2) < 130);
109         REQUIRE(timeline->m_allClips[cid2]->getMixDuration() == mixDuration);
110         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 1);
111         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
112     };
113 
__anonb3283b290502() 114     auto state2 = [&]() {
115         REQUIRE(timeline->getClipsCount() == 6);
116         REQUIRE(timeline->getClipPlaytime(cid3) > 20);
117         REQUIRE(timeline->getClipPosition(cid3) == 500);
118         REQUIRE(timeline->getClipPlaytime(cid4) > 20);
119         REQUIRE(timeline->getClipPosition(cid4) < 520);
120         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
121         REQUIRE(timeline->getTrackById_const(tid1)->mixCount() == 0);
122         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
123     };
124 
125     SECTION("Create and delete mix on color clips")
126     {
127         state0();
128         REQUIRE(timeline->mixClip(cid4));
129         state2();
130         undoStack->undo();
131         state0();
132         undoStack->redo();
133         state2();
134         undoStack->undo();
135         state0();
136     }
137 
138     SECTION("Create mix on color clips and move main (right side) clip")
139     {
140         // CID 3 length=20, pos=500, CID4 length=20, pos=520
141         // Default mix duration = 25 frames (12 before / 13 after)
142         state0();
143         REQUIRE(timeline->mixClip(cid4));
144         state2();
145 
146         // Move right clip to the left, should fail
147         REQUIRE(timeline->requestClipMove(cid4, tid2, 506) == false);
148 
149         // Move clip inside mix zone, should delete the mix
150         REQUIRE(timeline->requestClipMove(cid4, tid2, 509));
151         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
152         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
153         undoStack->undo();
154         state2();
155         // Move clip outside mix zone, should delete the mix and move it back to playlist 0
156         REQUIRE(timeline->requestClipMove(cid4, tid2, 600));
157         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
158         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
159         undoStack->undo();
160         state2();
161         // Move clip to another track, should delete mix
162         REQUIRE(timeline->requestClipMove(cid4, tid4, 600));
163         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
164         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
165         REQUIRE(timeline->getTrackById_const(tid4)->mixCount() == 0);
166         undoStack->undo();
167         state2();
168         undoStack->undo();
169         state0();
170     }
171 
172     SECTION("Create mix on color clip and move left side clip")
173     {
174         state0();
175         REQUIRE(timeline->mixClip(cid4));
176         state2();
177 
178         // Move left clip to the right, should silently fail
179         REQUIRE(timeline->requestClipMove(cid3, tid2, 502, true, true, false) == false);
180         REQUIRE(timeline->getClipPosition(cid3) == 500);
181 
182         // Move clip inside mix zone, should delete the mix
183         REQUIRE(timeline->requestClipMove(cid3, tid2, 499));
184         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
185         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
186         undoStack->undo();
187         state2();
188         // Move clip outside mix zone, should delete the mix
189         REQUIRE(timeline->requestClipMove(cid3, tid2, 450));
190         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
191         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
192         undoStack->undo();
193         state2();
194         // Move clip to another track, should delete mix
195         REQUIRE(timeline->requestClipMove(cid3, tid4, 600));
196         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
197         REQUIRE(timeline->getTrackById_const(tid4)->mixCount() == 0);
198         undoStack->undo();
199         state2();
200         undoStack->undo();
201         state0();
202     }
203 
204     SECTION("Create mix on color clips and move some to another track")
205     {
206         state0();
207         // insert third color clip
208         int cid5;
209         REQUIRE(timeline->requestClipInsertion(binId2, tid2, 540, cid5));
210         REQUIRE(timeline->requestItemResize(cid5, 20, true, true));
211         REQUIRE(timeline->getClipPosition(cid5) == 540);
212 
213         // CID 3 length=20, pos=500, CID4 length=20, pos=520, CID% length=20, pos=540
214         // Default mix duration = 25 frames (12 before / 13 after)
215 
216         REQUIRE(timeline->mixClip(cid4));
217         REQUIRE(timeline->mixClip(cid5));
218         REQUIRE(timeline->getClipPosition(cid5) < 540);
219         undoStack->undo();
220         REQUIRE(timeline->getClipPosition(cid5) == 540);
221         undoStack->redo();
222         REQUIRE(timeline->getClipPosition(cid5) < 540);
223         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
224         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
225         REQUIRE(timeline->m_allClips[cid5]->getSubPlaylistIndex() == 0);
226         REQUIRE(timeline->getTrackById_const(tid4)->mixCount() == 0);
227         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 2);
228 
229         // Move middle clip to another track, should delete the mixes
230         REQUIRE(timeline->requestClipMove(cid4, tid4, 500));
231         REQUIRE(timeline->getClipPosition(cid5) == 540);
232         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
233         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
234         REQUIRE(timeline->m_allClips[cid5]->getSubPlaylistIndex() == 0);
235         REQUIRE(timeline->getTrackById_const(tid4)->mixCount() == 0);
236         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
237 
238         // Undo track move
239         undoStack->undo();
240         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
241         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
242         REQUIRE(timeline->m_allClips[cid5]->getSubPlaylistIndex() == 0);
243         REQUIRE(timeline->getTrackById_const(tid4)->mixCount() == 0);
244         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 2);
245 
246         // Undo mixes
247         undoStack->undo();
248         undoStack->undo();
249         // undo 3rd clip resize & insert
250         undoStack->undo();
251         undoStack->undo();
252         state0();
253     }
254 
255     SECTION("Create mix on color clips and group move")
256     {
257         state0();
258         REQUIRE(timeline->mixClip(cid4));
259         state2();
260         // Move clip inside mix zone, should resize the mix
261         auto g1 = std::unordered_set<int>({cid3, cid4});
262         REQUIRE(timeline->requestClipsGroup(g1));
263         // Move clip to another track, should delete mix
264         REQUIRE(timeline->requestClipMove(cid4, tid4, 600));
265         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
266         REQUIRE(timeline->getTrackById_const(tid4)->mixCount() == 1);
267         undoStack->undo();
268         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
269         REQUIRE(timeline->getTrackById_const(tid4)->mixCount() == 0);
270         state2();
271         // Move on same track
272         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
273         REQUIRE(timeline->requestClipMove(cid4, tid3, 800));
274         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
275         undoStack->undo();
276         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
277         state2();
278         // Undo group
279         undoStack->undo();
280         // Undo mix
281         undoStack->undo();
282         state0();
283     }
284 
285     SECTION("Create and delete mix on AV clips")
286     {
287         state0();
288         REQUIRE(timeline->requestItemResize(cid2, 30, true, true) == 30);
289         REQUIRE(timeline->requestItemResize(cid2, 10, false, true) == 10);
290         REQUIRE(timeline->requestClipMove(cid2, tid2, 110));
291         REQUIRE(timeline->mixClip(cid2));
292         state1();
293         undoStack->undo();
294         state0();
295         undoStack->redo();
296         state1();
297         undoStack->undo();
298         state0();
299     }
300 
301     SECTION("Create mix and move AV clips")
302     {
303         // CID 1 length=10, pos=100, CID2 length=10, pos=110
304         // Default mix duration = 25 frames (12 before / 13 after)
305         // Resize CID2 so that it has some space to expand left
306         REQUIRE(timeline->requestItemResize(cid2, 30, true, true) == 30);
307         REQUIRE(timeline->requestItemResize(cid2, 10, false, true) == 10);
308         REQUIRE(timeline->requestClipMove(cid2, tid2, 110));
309         // Resize clip, should resize the mix
310         state0();
311         REQUIRE(timeline->mixClip(cid2));
312         state1();
313         // Resize right clip, should resize the mix
314         REQUIRE(timeline->requestItemResize(cid2, 15, false, true) == 15);
315         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 1);
316         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
317         undoStack->undo();
318         state1();
319         // Resize left clip, should resize the mix
320         REQUIRE(timeline->requestItemResize(cid1, 20, true, true) == 20);
321         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 1);
322         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
323         undoStack->undo();
324         state1();
325         // Move clip outside mix zone, should delete the mix
326         REQUIRE(timeline->requestClipMove(cid2, tid2, 200));
327         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 0);
328         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
329         undoStack->undo();
330         state1();
331         // Undo mix
332         undoStack->undo();
333         state0();
334     }
335 
336     SECTION("Create mix on color clip and resize")
337     {
338         state0();
339         // CID 3 length=20, pos=500, CID4 length=20, pos=520
340         // Default mix duration = 25 frames (12 before / 13 after)
341         REQUIRE(timeline->mixClip(cid4));
342         state2();
343         // Resize left clip, should resize the mix
344         REQUIRE(timeline->requestItemResize(cid3, 24, true, true) == 24);
345         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
346         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
347         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
348         undoStack->undo();
349         state2();
350         // Resize left clip outside mix zone, should delete the mix
351         REQUIRE(timeline->requestItemResize(cid3, 4, true, true) == 20);
352         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
353         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
354         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
355         undoStack->undo();
356         state2();
357         // Resize right clip, should resize the mix
358         REQUIRE(timeline->requestItemResize(cid4, 16, false, true) == 16);
359         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
360         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
361         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
362         undoStack->undo();
363         state2();
364         // Resize right clip outside mix zone, should delete the mix
365         REQUIRE(timeline->requestItemResize(cid4, 4, false, true) == 4);
366         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
367         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
368         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 0);
369         undoStack->undo();
370         state2();
371         // Resize right clip before left clip, should limit the resize to left clip position
372         REQUIRE(timeline->requestItemResize(cid4, 50, false, true) == 40);
373         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
374         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
375         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
376         undoStack->undo();
377         state2();
378         // Resize left clip past right clip, should limit the resize to left clip position
379         REQUIRE(timeline->requestItemResize(cid3, 100, true, true) == 40);
380         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
381         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
382         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
383         undoStack->undo();
384         state2();
385 
386         undoStack->undo();
387         state0();
388     }
389 
390     SECTION("Create mix on AV clips and resize")
391     {
392         state0();
393         // CID 1 length=10, pos=100, CID2 length=10, pos=110
394         REQUIRE(timeline->m_allClips[cid1]->getPlaytime() == 10);
395         REQUIRE(timeline->m_allClips[cid2]->getPlaytime() == 10);
396         // Resize clip in to have some space for mix
397         REQUIRE(timeline->requestItemResize(cid2, 90, true, true) == 90);
398         REQUIRE(timeline->requestItemResize(cid2, 30, false, true) == 30);
399         REQUIRE(timeline->requestClipMove(cid2, tid2, 130));
400         REQUIRE(timeline->requestItemResize(cid1, 30, true, true) == 30);
401 
402         REQUIRE(timeline->mixClip(cid2));
403         state3();
404         // CID 1 length=30, pos=100, CID2 length=30, pos=130
405         // Default mix duration = 25 frames (12 before / 13 after)
406         // Resize left clip, should resize the mix
407         REQUIRE(timeline->requestItemResize(cid1, 35, true, true) == 35);
408         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
409         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 1);
410         REQUIRE(timeline->m_allClips[cid1]->getSubPlaylistIndex() == 0);
411         REQUIRE(timeline->m_allClips[cid2]->getSubPlaylistIndex() == 1);
412         undoStack->undo();
413         state3();
414         // Resize left clip outside mix zone, should delete the mix
415         REQUIRE(timeline->requestItemResize(cid1, 10, true, true) == 30);
416         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
417         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 0);
418         REQUIRE(timeline->m_allClips[cid1]->getSubPlaylistIndex() == 0);
419         REQUIRE(timeline->m_allClips[cid2]->getSubPlaylistIndex() == 0);
420         undoStack->undo();
421         state3();
422         // Resize right clip, should resize the mix
423         REQUIRE(timeline->requestItemResize(cid2, 25, false, true) == 25);
424         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
425         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 1);
426         REQUIRE(timeline->m_allClips[cid1]->getSubPlaylistIndex() == 0);
427         REQUIRE(timeline->m_allClips[cid2]->getSubPlaylistIndex() == 1);
428         undoStack->undo();
429         state3();
430         // Resize right clip outside mix zone, should delete the mix
431         REQUIRE(timeline->requestItemResize(cid2, 4, false, true) == 4);
432         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 0);
433         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 0);
434         REQUIRE(timeline->m_allClips[cid1]->getSubPlaylistIndex() == 0);
435         REQUIRE(timeline->m_allClips[cid2]->getSubPlaylistIndex() == 0);
436         undoStack->undo();
437         state3();
438         // Resize right clip before left clip, should limit to left clip position
439         REQUIRE(timeline->requestItemResize(cid2, 80, false, true) == 60);
440         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
441         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 1);
442         REQUIRE(timeline->m_allClips[cid1]->getSubPlaylistIndex() == 0);
443         REQUIRE(timeline->m_allClips[cid2]->getSubPlaylistIndex() == 1);
444         undoStack->undo();
445         state3();
446         // Resize left clip after right clip, should limit to right clip duration
447         REQUIRE(timeline->requestItemResize(cid1, 80, true, true) == 60);
448         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
449         REQUIRE(timeline->getTrackById_const(tid3)->mixCount() == 1);
450         REQUIRE(timeline->m_allClips[cid1]->getSubPlaylistIndex() == 0);
451         REQUIRE(timeline->m_allClips[cid2]->getSubPlaylistIndex() == 1);
452         undoStack->undo();
453         state3();
454         undoStack->undo();
455         undoStack->undo();
456         undoStack->undo();
457         undoStack->undo();
458         undoStack->undo();
459         state0();
460     }
461 
462     SECTION("Test chained mixes on color clips")
463     {
464         // Add 2 more color clips
465         int cid5;
466         int cid6;
467         int cid7;
468         state0();
469         REQUIRE(timeline->requestClipInsertion(binId2, tid2, 540, cid5));
470         REQUIRE(timeline->requestItemResize(cid5, 20, true, true));
471         REQUIRE(timeline->requestClipInsertion(binId2, tid2, 560, cid6));
472         REQUIRE(timeline->requestItemResize(cid6, 40, true, true));
473         REQUIRE(timeline->requestClipInsertion(binId2, tid2, 600, cid7));
474         REQUIRE(timeline->requestItemResize(cid7, 20, true, true));
475 
476         // Cid3 pos=500, duration=20
477         // Cid4 pos=520, duration=20
478         // Cid5 pos=540, duration=20
479         // Cid6 pos=560, duration=40
480         // Cid7 pos=600, duration=20
481 
482         // Mix 3 and 4
483         REQUIRE(timeline->mixClip(cid4));
484         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
485         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
486         REQUIRE(timeline->m_allClips[cid5]->getSubPlaylistIndex() == 0);
487         REQUIRE(timeline->m_allClips[cid6]->getSubPlaylistIndex() == 0);
488         REQUIRE(timeline->m_allClips[cid7]->getSubPlaylistIndex() == 0);
489         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
490 
491         // Mix 6 and 7
492         REQUIRE(timeline->mixClip(cid7));
493         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
494         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
495         REQUIRE(timeline->m_allClips[cid5]->getSubPlaylistIndex() == 0);
496         REQUIRE(timeline->m_allClips[cid6]->getSubPlaylistIndex() == 0);
497         REQUIRE(timeline->m_allClips[cid7]->getSubPlaylistIndex() == 1);
498         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 2);
499 
500         // Mix 5 and 6
501         REQUIRE(timeline->mixClip(cid6));
502         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
503         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
504         REQUIRE(timeline->m_allClips[cid5]->getSubPlaylistIndex() == 0);
505         REQUIRE(timeline->m_allClips[cid6]->getSubPlaylistIndex() == 1);
506         REQUIRE(timeline->m_allClips[cid7]->getSubPlaylistIndex() == 0);
507         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 3);
508 
509         // Undo mix 5 and 6
510         undoStack->undo();
511         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
512         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
513         REQUIRE(timeline->m_allClips[cid5]->getSubPlaylistIndex() == 0);
514         REQUIRE(timeline->m_allClips[cid6]->getSubPlaylistIndex() == 0);
515         REQUIRE(timeline->m_allClips[cid7]->getSubPlaylistIndex() == 1);
516         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 2);
517 
518         // Undo mix 6 and 7
519         undoStack->undo();
520         REQUIRE(timeline->m_allClips[cid3]->getSubPlaylistIndex() == 0);
521         REQUIRE(timeline->m_allClips[cid4]->getSubPlaylistIndex() == 1);
522         REQUIRE(timeline->m_allClips[cid5]->getSubPlaylistIndex() == 0);
523         REQUIRE(timeline->m_allClips[cid6]->getSubPlaylistIndex() == 0);
524         REQUIRE(timeline->m_allClips[cid7]->getSubPlaylistIndex() == 0);
525         REQUIRE(timeline->getTrackById_const(tid2)->mixCount() == 1);
526 
527         // Undo mix 3 and 4
528         undoStack->undo();
529 
530         // Undo insert/resize ops
531         undoStack->undo();
532         undoStack->undo();
533         undoStack->undo();
534         undoStack->undo();
535         undoStack->undo();
536         undoStack->undo();
537 
538         state0();
539     }
540     binModel->clean();
541     pCore->m_projectManager = nullptr;
542 }
543