1 #include "doc/kdenlivedoc.h"
2 #include "test_utils.hpp"
3 
4 using namespace fakeit;
5 Mlt::Profile profile_trimming;
6 
7 TEST_CASE("Simple trimming operations", "[Trimming]")
8 {
9     auto binModel = pCore->projectItemModel();
10     binModel->clean();
11     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
12     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
13 
14     // Here we do some trickery to enable testing.
15     // We mock the project class so that the undoStack function returns our undoStack
16 
17     Mock<ProjectManager> pmMock;
18     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
19     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
20 
21     ProjectManager &mocked = pmMock.get();
22     pCore->m_projectManager = &mocked;
23 
24     // We also mock timeline object to spy few functions and mock others
25     TimelineItemModel tim(&profile_trimming, undoStack);
26     Mock<TimelineItemModel> timMock(tim);
__anonf52080220102(...) 27     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
28     TimelineItemModel::finishConstruct(timeline, guideModel);
29 
30     RESET(timMock)
31 
32     QString binId = createProducer(profile_trimming, "red", binModel);
33     QString binId2 = createProducer(profile_trimming, "blue", binModel);
34     QString binId3 = createProducerWithSound(profile_trimming, binModel);
35 
36     int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
37     int tid1 = TrackModel::construct(timeline);
38     int tid2 = TrackModel::construct(timeline);
39     int tid3 = TrackModel::construct(timeline);
40 
41     // Add an audio track
42     int tid4 = TrackModel::construct(timeline, -1, -1, QString(), true);
43     int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly);
44     int cid3 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
45     int cid4 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
46     int cid5 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
47     int cid6 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
48     int cid7 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
49 
50     int audio1 = ClipModel::construct(timeline, binId3, -1, PlaylistState::VideoOnly);
51     int audio2 = ClipModel::construct(timeline, binId3, -1, PlaylistState::VideoOnly);
52     int audio3 = ClipModel::construct(timeline, binId3, -1, PlaylistState::VideoOnly);
53 
54     timeline->m_allClips[cid1]->m_endlessResize = false;
55     timeline->m_allClips[cid2]->m_endlessResize = false;
56     timeline->m_allClips[cid3]->m_endlessResize = false;
57     timeline->m_allClips[cid4]->m_endlessResize = false;
58     timeline->m_allClips[cid5]->m_endlessResize = false;
59     timeline->m_allClips[cid6]->m_endlessResize = false;
60     timeline->m_allClips[cid7]->m_endlessResize = false;
61 
62     SECTION("Clip cutting")
63     {
64         // Trivial split
65         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
66         int l = timeline->getClipPlaytime(cid2);
67         REQUIRE(timeline->requestItemResize(cid2, l - 3, true) == l - 3);
68         REQUIRE(timeline->requestItemResize(cid2, l - 5, false) == l - 5);
69         REQUIRE(timeline->requestClipMove(cid2, tid1, l));
70         REQUIRE(timeline->requestClipMove(cid3, tid1, l + l - 5));
__anonf52080220202() 71         auto state = [&]() {
72             REQUIRE(timeline->checkConsistency());
73             REQUIRE(timeline->getClipPlaytime(cid1) == l);
74             REQUIRE(timeline->getClipPlaytime(cid2) == l - 5);
75             REQUIRE(timeline->getClipPlaytime(cid3) == l);
76             REQUIRE(timeline->getClipPosition(cid1) == 0);
77             REQUIRE(timeline->getClipPosition(cid2) == l);
78             REQUIRE(timeline->getClipPosition(cid3) == l + l - 5);
79             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 2);
80             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l - 4);
81         };
82         state();
83 
84         // require cut position outside the clip. Should return true and nothing is done
85         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 0));
86         state();
87         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 5 * l));
88         state();
89         // cut on edges doesn't do anything either
90         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l));
91         state();
92         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l + l - 5));
93         state();
94 
95         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l + 4));
96         int splitted = timeline->getClipByPosition(tid1, l + 5);
__anonf52080220302() 97         auto state2 = [&]() {
98             REQUIRE(timeline->checkConsistency());
99             REQUIRE(timeline->getClipPlaytime(cid1) == l);
100             REQUIRE(timeline->getClipPlaytime(cid2) == 4);
101             REQUIRE(timeline->getClipPlaytime(splitted) == l - 9);
102             REQUIRE(timeline->getClipPlaytime(cid3) == l);
103             REQUIRE(timeline->getClipPosition(cid1) == 0);
104             REQUIRE(timeline->getClipPosition(cid2) == l);
105             REQUIRE(timeline->getClipPosition(splitted) == l + 4);
106             REQUIRE(timeline->getClipPosition(cid3) == l + l - 5);
107             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 2);
108             REQUIRE(timeline->getClipPtr(cid2)->getOut() == 5);
109             REQUIRE(timeline->getClipPtr(splitted)->getIn() == 6);
110             REQUIRE(timeline->getClipPtr(splitted)->getOut() == l - 4);
111         };
112         state2();
113 
114         undoStack->undo();
115         state();
116 
117         undoStack->redo();
118         state2();
119     }
120 
121     SECTION("Cut and resize")
122     {
123         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
124         int l = timeline->getClipPlaytime(cid1);
125         timeline->m_allClips[cid1]->m_endlessResize = false;
126 
__anonf52080220402() 127         auto state = [&]() {
128             REQUIRE(timeline->checkConsistency());
129             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
130             REQUIRE(timeline->getClipPlaytime(cid1) == l);
131             REQUIRE(timeline->getClipPosition(cid1) == 5);
132         };
133         state();
134 
135         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid1, 9));
136         int splitted = timeline->getClipByPosition(tid1, 10);
137         timeline->m_allClips[splitted]->m_endlessResize = false;
__anonf52080220502() 138         auto state2 = [&]() {
139             REQUIRE(timeline->checkConsistency());
140             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
141             REQUIRE(timeline->getClipTrackId(splitted) == tid1);
142             REQUIRE(timeline->getClipPlaytime(cid1) == 4);
143             REQUIRE(timeline->getClipPlaytime(splitted) == l - 4);
144             REQUIRE(timeline->getClipPosition(cid1) == 5);
145             REQUIRE(timeline->getClipPosition(splitted) == 9);
146         };
147         state2();
148 
149         REQUIRE(timeline->requestClipMove(splitted, tid2, 9, true, true));
150         REQUIRE(timeline->requestItemResize(splitted, l - 3, true, true) == -1);
151         REQUIRE(timeline->requestItemResize(splitted, l, false, true) == l);
152         REQUIRE(timeline->requestItemResize(cid1, 5, false, true) == -1);
153         REQUIRE(timeline->requestItemResize(cid1, l, true, true) == l);
__anonf52080220602() 154         auto state3 = [&]() {
155             REQUIRE(timeline->checkConsistency());
156             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
157             REQUIRE(timeline->getClipTrackId(splitted) == tid2);
158             REQUIRE(timeline->getClipPlaytime(cid1) == l);
159             REQUIRE(timeline->getClipPlaytime(splitted) == l);
160             REQUIRE(timeline->getClipPosition(cid1) == 5);
161             REQUIRE(timeline->getClipPosition(splitted) == 5);
162         };
163         state3();
164 
165         undoStack->undo();
166         undoStack->undo();
167         undoStack->undo();
168         state2();
169         undoStack->undo();
170         state();
171         undoStack->redo();
172         state2();
173         undoStack->redo();
174         undoStack->redo();
175         undoStack->redo();
176         state3();
177     }
178 
179     SECTION("Clip cutting 2")
180     {
181         // More complex group structure split split
182         int l = timeline->getClipPlaytime(cid2);
183         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
184         REQUIRE(timeline->requestClipMove(cid2, tid1, l));
185         REQUIRE(timeline->requestClipMove(cid3, tid1, 2 * l));
186         REQUIRE(timeline->requestClipMove(cid4, tid2, 0));
187         REQUIRE(timeline->requestClipMove(cid5, tid2, l));
188         REQUIRE(timeline->requestClipMove(cid6, tid2, 2 * l));
189         REQUIRE(timeline->requestClipMove(cid7, tid1, 200));
190         int gid1 = timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid4}), true, GroupType::Normal);
191         int gid2 = timeline->requestClipsGroup(std::unordered_set<int>({cid2, cid5}), true, GroupType::Normal);
192         int gid3 = timeline->requestClipsGroup(std::unordered_set<int>({cid3, cid6}), true, GroupType::Normal);
193         int gid4 = timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5, cid6, cid7}), true, GroupType::Normal);
__anonf52080220702() 194         auto state = [&]() {
195             REQUIRE(timeline->checkConsistency());
196             int p = 0;
197             for (int c : std::vector<int>({cid1, cid2, cid3})) {
198                 REQUIRE(timeline->getClipPlaytime(c) == l);
199                 REQUIRE(timeline->getClipTrackId(c) == tid1);
200                 REQUIRE(timeline->getClipPosition(c) == p);
201                 p += l;
202             }
203             p = 0;
204             for (int c : std::vector<int>({cid4, cid5, cid6})) {
205                 REQUIRE(timeline->getClipPlaytime(c) == l);
206                 REQUIRE(timeline->getClipTrackId(c) == tid2);
207                 REQUIRE(timeline->getClipPosition(c) == p);
208                 p += l;
209             }
210             REQUIRE(timeline->getClipPosition(cid7) == 200);
211             REQUIRE(timeline->getClipTrackId(cid7) == tid1);
212             REQUIRE(timeline->m_groups->getDirectChildren(gid1) == std::unordered_set<int>({cid1, cid4}));
213             REQUIRE(timeline->m_groups->getDirectChildren(gid2) == std::unordered_set<int>({cid2, cid5}));
214             REQUIRE(timeline->m_groups->getDirectChildren(gid3) == std::unordered_set<int>({cid3, cid6}));
215             REQUIRE(timeline->m_groups->getDirectChildren(gid4) == std::unordered_set<int>({gid1, gid2, gid3, cid7}));
216             REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5, cid6, cid7}));
217         };
218         state();
219 
220         // These functions will return true but do nothing
221         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 0));
222         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 5 * l));
223         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l));
224         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, 2 * l));
225         state();
226 
227         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid2, l + 4));
228         int splitted = timeline->getClipByPosition(tid1, l + 5);
229         int splitted2 = timeline->getClipByPosition(tid2, l + 5);
230         REQUIRE(splitted != splitted2);
__anonf52080220802() 231         auto check_groups = [&]() {
232             REQUIRE(timeline->m_groups->getDirectChildren(gid2) == std::unordered_set<int>({splitted, splitted2}));
233             REQUIRE(timeline->m_groups->getDirectChildren(gid3) == std::unordered_set<int>({cid3, cid6}));
234             REQUIRE(timeline->m_groups->getDirectChildren(gid4) == std::unordered_set<int>({gid2, gid3, cid7}));
235             REQUIRE(timeline->getGroupElements(cid3) == std::unordered_set<int>({splitted, splitted2, cid3, cid6, cid7}));
236 
237             int g1b = timeline->m_groups->m_upLink[cid1];
238             int g2b = timeline->m_groups->m_upLink[cid2];
239             int g4b = timeline->m_groups->getRootId(cid1);
240             REQUIRE(timeline->m_groups->getDirectChildren(g1b) == std::unordered_set<int>({cid1, cid4}));
241             REQUIRE(timeline->m_groups->getDirectChildren(g2b) == std::unordered_set<int>({cid2, cid5}));
242             REQUIRE(timeline->m_groups->getDirectChildren(g4b) == std::unordered_set<int>({g1b, g2b}));
243             REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2, cid4, cid5}));
244         };
__anonf52080220902() 245         auto state2 = [&]() {
246             REQUIRE(timeline->checkConsistency());
247             int p = 0;
248             for (int c : std::vector<int>({cid1, cid2, cid3})) {
249                 REQUIRE(timeline->getClipPlaytime(c) == (c == cid2 ? 4 : l));
250                 REQUIRE(timeline->getClipTrackId(c) == tid1);
251                 REQUIRE(timeline->getClipPosition(c) == p);
252                 p += l;
253             }
254             p = 0;
255             for (int c : std::vector<int>({cid4, cid5, cid6})) {
256                 REQUIRE(timeline->getClipPlaytime(c) == (c == cid5 ? 4 : l));
257                 REQUIRE(timeline->getClipTrackId(c) == tid2);
258                 REQUIRE(timeline->getClipPosition(c) == p);
259                 p += l;
260             }
261             REQUIRE(timeline->getClipPosition(cid7) == 200);
262             REQUIRE(timeline->getClipTrackId(cid7) == tid1);
263             REQUIRE(timeline->getClipPosition(splitted) == l + 4);
264             REQUIRE(timeline->getClipPlaytime(splitted) == l - 4);
265             REQUIRE(timeline->getClipTrackId(splitted) == tid1);
266             REQUIRE(timeline->getClipPosition(splitted2) == l + 4);
267             REQUIRE(timeline->getClipPlaytime(splitted2) == l - 4);
268             REQUIRE(timeline->getClipTrackId(splitted2) == tid2);
269             check_groups();
270         };
271         state2();
272 
273         REQUIRE(timeline->requestClipMove(splitted, tid1, l + 4 + 10, true, true));
274         REQUIRE(timeline->requestClipMove(cid1, tid2, 10, true, true));
__anonf52080220a02() 275         auto state3 = [&]() {
276             REQUIRE(timeline->checkConsistency());
277             int p = 0;
278             for (int c : std::vector<int>({cid1, cid2, cid3})) {
279                 REQUIRE(timeline->getClipPlaytime(c) == (c == cid2 ? 4 : l));
280                 REQUIRE(timeline->getClipTrackId(c) == (c == cid3 ? tid1 : tid2));
281                 REQUIRE(timeline->getClipPosition(c) == p + 10);
282                 p += l;
283             }
284             p = 0;
285             for (int c : std::vector<int>({cid4, cid5, cid6})) {
286                 REQUIRE(timeline->getClipPlaytime(c) == (c == cid5 ? 4 : l));
287                 REQUIRE(timeline->getClipTrackId(c) == (c == cid6 ? tid2 : tid3));
288                 REQUIRE(timeline->getClipPosition(c) == p + 10);
289                 p += l;
290             }
291             REQUIRE(timeline->getClipPosition(cid7) == 210);
292             REQUIRE(timeline->getClipTrackId(cid7) == tid1);
293             REQUIRE(timeline->getClipPosition(splitted) == l + 4 + 10);
294             REQUIRE(timeline->getClipPlaytime(splitted) == l - 4);
295             REQUIRE(timeline->getClipTrackId(splitted) == tid1);
296             REQUIRE(timeline->getClipPosition(splitted2) == l + 4 + 10);
297             REQUIRE(timeline->getClipPlaytime(splitted2) == l - 4);
298             REQUIRE(timeline->getClipTrackId(splitted2) == tid2);
299             check_groups();
300         };
301         state3();
302 
303         undoStack->undo();
304         undoStack->undo();
305         state2();
306         undoStack->undo();
307         state();
308         undoStack->redo();
309         state2();
310         undoStack->redo();
311         undoStack->redo();
312         state3();
313     }
314 
315     SECTION("Simple audio split")
316     {
317         int l = timeline->getClipPlaytime(audio1);
318         REQUIRE(timeline->requestClipMove(audio1, tid1, 3));
319 
__anonf52080220b02() 320         auto state = [&]() {
321             REQUIRE(timeline->checkConsistency());
322             REQUIRE(timeline->getClipPlaytime(audio1) == l);
323             REQUIRE(timeline->getClipPosition(audio1) == 3);
324             REQUIRE(timeline->getClipTrackId(audio1) == tid1);
325             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
326             REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
327 
328             REQUIRE(timeline->getGroupElements(audio1) == std::unordered_set<int>({audio1}));
329         };
330         state();
331 
332         REQUIRE(TimelineFunctions::requestSplitAudio(timeline, audio1, tid4));
333         int splitted1 = timeline->getClipByPosition(tid4, 3);
__anonf52080220c02() 334         auto state2 = [&]() {
335             REQUIRE(timeline->checkConsistency());
336             REQUIRE(timeline->getClipPlaytime(audio1) == l);
337             REQUIRE(timeline->getClipPosition(audio1) == 3);
338             REQUIRE(timeline->getClipPlaytime(splitted1) == l);
339             REQUIRE(timeline->getClipPosition(splitted1) == 3);
340             REQUIRE(timeline->getClipTrackId(audio1) == tid1);
341             REQUIRE(timeline->getClipTrackId(splitted1) == tid4);
342             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
343             REQUIRE(timeline->getTrackClipsCount(tid4) == 1);
344 
345             REQUIRE(timeline->getGroupElements(audio1) == std::unordered_set<int>({audio1, splitted1}));
346 
347             int g1 = timeline->m_groups->getDirectAncestor(audio1);
348             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({audio1, splitted1}));
349             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
350         };
351         state2();
352 
353         undoStack->undo();
354         state();
355         undoStack->redo();
356         state2();
357         undoStack->undo();
358         state();
359         undoStack->redo();
360         state2();
361 
362         // We also make sure that clips that are audio only cannot be further splitted
363         REQUIRE(timeline->requestClipMove(cid1, tid1, l + 30));
364         // This is a color clip, shouldn't be splittable
365         REQUIRE_FALSE(TimelineFunctions::requestSplitAudio(timeline, cid1, tid2));
366         // Check we cannot split audio on a video track
367         REQUIRE_FALSE(TimelineFunctions::requestSplitAudio(timeline, audio1, tid2));
368     }
369     SECTION("Split audio on a selection")
370     {
371 
372         int l = timeline->getClipPlaytime(audio2);
373         REQUIRE(timeline->requestClipMove(audio1, tid1, 0));
374         REQUIRE(timeline->requestClipMove(audio2, tid1, l));
375         REQUIRE(timeline->requestClipMove(audio3, tid1, 2 * l));
376 
377         std::unordered_set<int> selection{audio1, audio3, audio2};
378         timeline->requestSetSelection(selection);
379 
__anonf52080220d02() 380         auto state = [&]() {
381             REQUIRE(timeline->checkConsistency());
382             REQUIRE(timeline->getClipPlaytime(audio1) == l);
383             REQUIRE(timeline->getClipPlaytime(audio2) == l);
384             REQUIRE(timeline->getClipPlaytime(audio3) == l);
385             REQUIRE(timeline->getClipPosition(audio1) == 0);
386             REQUIRE(timeline->getClipPosition(audio2) == l);
387             REQUIRE(timeline->getClipPosition(audio3) == l + l);
388             REQUIRE(timeline->getClipTrackId(audio1) == tid1);
389             REQUIRE(timeline->getClipTrackId(audio2) == tid1);
390             REQUIRE(timeline->getClipTrackId(audio3) == tid1);
391             REQUIRE(timeline->getTrackClipsCount(tid1) == 3);
392             REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
393 
394             REQUIRE(timeline->getGroupElements(audio1) == std::unordered_set<int>({audio1, audio2, audio3}));
395 
396             REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>({audio1, audio3, audio2}));
397         };
398         state();
399 
400         REQUIRE(TimelineFunctions::requestSplitAudio(timeline, audio1, tid4));
401         int splitted1 = timeline->getClipByPosition(tid4, 0);
402         int splitted2 = timeline->getClipByPosition(tid4, l);
403         int splitted3 = timeline->getClipByPosition(tid4, 2 * l);
__anonf52080220e02() 404         auto state2 = [&]() {
405             REQUIRE(timeline->checkConsistency());
406             REQUIRE(timeline->getClipPlaytime(audio1) == l);
407             REQUIRE(timeline->getClipPlaytime(audio2) == l);
408             REQUIRE(timeline->getClipPlaytime(audio3) == l);
409             REQUIRE(timeline->getClipPosition(audio1) == 0);
410             REQUIRE(timeline->getClipPosition(audio2) == l);
411             REQUIRE(timeline->getClipPosition(audio3) == l + l);
412             REQUIRE(timeline->getClipPlaytime(splitted1) == l);
413             REQUIRE(timeline->getClipPlaytime(splitted2) == l);
414             REQUIRE(timeline->getClipPlaytime(splitted3) == l);
415             REQUIRE(timeline->getClipPosition(splitted1) == 0);
416             REQUIRE(timeline->getClipPosition(splitted2) == l);
417             REQUIRE(timeline->getClipPosition(splitted3) == l + l);
418             REQUIRE(timeline->getClipTrackId(audio1) == tid1);
419             REQUIRE(timeline->getClipTrackId(audio2) == tid1);
420             REQUIRE(timeline->getClipTrackId(audio3) == tid1);
421             REQUIRE(timeline->getClipTrackId(splitted1) == tid4);
422             REQUIRE(timeline->getClipTrackId(splitted2) == tid4);
423             REQUIRE(timeline->getClipTrackId(splitted3) == tid4);
424             REQUIRE(timeline->getTrackClipsCount(tid1) == 3);
425             REQUIRE(timeline->getTrackClipsCount(tid4) == 3);
426 
427             REQUIRE(timeline->getGroupElements(audio1) == std::unordered_set<int>({audio1, splitted1, audio2, audio3, splitted2, splitted3}));
428             REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>({audio1, splitted1, audio2, audio3, splitted2, splitted3}));
429 
430             int g1 = timeline->m_groups->getDirectAncestor(audio1);
431             int g2 = timeline->m_groups->getDirectAncestor(audio2);
432             int g3 = timeline->m_groups->getDirectAncestor(audio3);
433             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({audio1, splitted1}));
434             REQUIRE(timeline->m_groups->getDirectChildren(g2) == std::unordered_set<int>({audio2, splitted2}));
435             REQUIRE(timeline->m_groups->getDirectChildren(g3) == std::unordered_set<int>({audio3, splitted3}));
436             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
437             REQUIRE(timeline->m_groups->getType(g2) == GroupType::AVSplit);
438             REQUIRE(timeline->m_groups->getType(g3) == GroupType::AVSplit);
439         };
440         state2();
441 
442         undoStack->undo();
443         state();
444         undoStack->redo();
445         state2();
446     }
447     SECTION("Cut should preserve AV groups")
448     {
449         QString binId3 = createProducerWithSound(profile_trimming, binModel);
450 
451         int tid6 = TrackModel::construct(timeline, -1, -1, QString(), true);
452         int tid5 = TrackModel::construct(timeline);
453 
454         // Setup timeline audio drop info
455         QMap <int, QString>audioInfo;
456         audioInfo.insert(1,QStringLiteral("stream1"));
457         timeline->m_binAudioTargets = audioInfo;
458         timeline->m_videoTarget = tid5;
459 
460         int cid6 = -1;
461         int pos = 3;
462         REQUIRE(timeline->requestClipInsertion(binId3, tid5, pos, cid6, true, true, false));
463         int cid7 = timeline->m_groups->getSplitPartner(cid6);
464         int l = timeline->getClipPlaytime(cid6);
465         REQUIRE(l >= 10);
466 
__anonf52080220f02() 467         auto state = [&]() {
468             REQUIRE(timeline->checkConsistency());
469             REQUIRE(timeline->getTrackClipsCount(tid5) == 1);
470             REQUIRE(timeline->getTrackClipsCount(tid6) == 1);
471             REQUIRE(timeline->getClipTrackId(cid6) == tid5);
472             REQUIRE(timeline->getClipTrackId(cid7) == tid6);
473             REQUIRE(timeline->getClipPosition(cid6) == pos);
474             REQUIRE(timeline->getClipPosition(cid7) == pos);
475             REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::VideoOnly);
476             REQUIRE(timeline->getClipPtr(cid7)->clipState() == PlaylistState::AudioOnly);
477 
478             // we check that the av group was correctly created
479             REQUIRE(timeline->getGroupElements(cid6) == std::unordered_set<int>({cid6, cid7}));
480             int g1 = timeline->m_groups->getDirectAncestor(cid6);
481             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid6, cid7}));
482             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
483         };
484         state();
485 
486         REQUIRE(TimelineFunctions::requestClipCut(timeline, cid6, pos + 4));
487 
488         int cid8 = timeline->getClipByPosition(tid5, pos + 5);
489         int cid9 = timeline->getClipByPosition(tid6, pos + 5);
490         REQUIRE(cid8 >= 0);
491         REQUIRE(cid9 >= 0);
492 
__anonf52080221002() 493         auto state2 = [&]() {
494             REQUIRE(timeline->checkConsistency());
495             REQUIRE(timeline->getTrackClipsCount(tid5) == 2);
496             REQUIRE(timeline->getTrackClipsCount(tid6) == 2);
497             REQUIRE(timeline->getClipTrackId(cid6) == tid5);
498             REQUIRE(timeline->getClipTrackId(cid7) == tid6);
499             REQUIRE(timeline->getClipTrackId(cid8) == tid5);
500             REQUIRE(timeline->getClipTrackId(cid9) == tid6);
501 
502             REQUIRE(timeline->getClipPosition(cid6) == pos);
503             REQUIRE(timeline->getClipPosition(cid7) == pos);
504             REQUIRE(timeline->getClipPosition(cid8) == pos + 4);
505             REQUIRE(timeline->getClipPosition(cid9) == pos + 4);
506 
507             REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::VideoOnly);
508             REQUIRE(timeline->getClipPtr(cid7)->clipState() == PlaylistState::AudioOnly);
509             REQUIRE(timeline->getClipPtr(cid8)->clipState() == PlaylistState::VideoOnly);
510             REQUIRE(timeline->getClipPtr(cid9)->clipState() == PlaylistState::AudioOnly);
511 
512             // original AV group
513             REQUIRE(timeline->getGroupElements(cid6) == std::unordered_set<int>({cid6, cid7}));
514             int g1 = timeline->m_groups->getDirectAncestor(cid6);
515             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid6, cid7}));
516             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
517 
518             // new AV group
519             REQUIRE(timeline->getGroupElements(cid8) == std::unordered_set<int>({cid8, cid9}));
520             int g2 = timeline->m_groups->getDirectAncestor(cid8);
521             REQUIRE(timeline->m_groups->getDirectChildren(g2) == std::unordered_set<int>({cid8, cid9}));
522             REQUIRE(timeline->m_groups->getType(g2) == GroupType::AVSplit);
523         };
524         state2();
525 
526         undoStack->undo();
527         state();
528         undoStack->redo();
529         state2();
530     }
531 
532     binModel->clean();
533     pCore->m_projectManager = nullptr;
534 }
535 
536 TEST_CASE("Insert/delete", "[Trimming2]")
537 {
538     auto binModel = pCore->projectItemModel();
539     binModel->clean();
540     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
541     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
542 
543     // Here we do some trickery to enable testing.
544     // We mock the project class so that the undoStack function returns our undoStack
545 
546     Mock<ProjectManager> pmMock;
547     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
548     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
549     When(Method(pmMock, getGuideModel)).AlwaysReturn(guideModel);
550 
551     ProjectManager &mocked = pmMock.get();
552     pCore->m_projectManager = &mocked;
553 
554     // We also mock timeline object to spy few functions and mock others
555     TimelineItemModel tim(&profile_trimming, undoStack);
556     Mock<TimelineItemModel> timMock(tim);
__anonf52080221102(...) 557     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
558     TimelineItemModel::finishConstruct(timeline, guideModel);
559 
560     RESET(timMock);
561 
562     QString binId = createProducerWithSound(profile_trimming, binModel);
563 
564     TrackModel::construct(timeline, -1, -1, QString(), true);
565     int tid2 = TrackModel::construct(timeline, -1, -1, QString(), true);
566     int tid1 = TrackModel::construct(timeline);
567     TrackModel::construct(timeline);
568 
569     // Setup timeline audio drop info
570     QMap <int, QString>audioInfo;
571     audioInfo.insert(1,QStringLiteral("stream1"));
572     timeline->m_binAudioTargets = audioInfo;
573     timeline->m_videoTarget = tid1;
574 
575     SECTION("Remove Space should preserve groups")
576     {
577 
578         int cid1 = -1;
579         REQUIRE(timeline->requestClipInsertion(binId, tid1, 3, cid1, true, true, false));
580         int cid2 = timeline->m_groups->getSplitPartner(cid1);
581 
__anonf52080221202(int pos) 582         auto state = [&](int pos) {
583             REQUIRE(timeline->checkConsistency());
584             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
585             REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
586             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
587             REQUIRE(timeline->getClipTrackId(cid2) == tid2);
588             REQUIRE(timeline->getClipPosition(cid1) == pos);
589             REQUIRE(timeline->getClipPosition(cid2) == pos);
590             REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly);
591             REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly);
592             // we check that the av group was correctly created
593             REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2}));
594             int g1 = timeline->m_groups->getDirectAncestor(cid1);
595             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2}));
596             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
597         };
598         state(3);
599 
600         REQUIRE(TimelineFunctions::requestDeleteBlankAt(timeline, tid1, 1, true));
601         state(0);
602 
603         undoStack->undo();
604         state(3);
605         undoStack->redo();
606         state(0);
607     }
608 
609     SECTION("Insert zone should preserve groups")
610     {
611         int cid1 = -1;
612         REQUIRE(timeline->requestClipInsertion(binId, tid1, 3, cid1, true, true, false));
613         int cid2 = timeline->m_groups->getSplitPartner(cid1);
614 
615         int l = timeline->getClipPlaytime(cid2);
__anonf52080221302() 616         auto state = [&]() {
617             REQUIRE(timeline->checkConsistency());
618             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
619             REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
620             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
621             REQUIRE(timeline->getClipTrackId(cid2) == tid2);
622             REQUIRE(timeline->getClipPosition(cid1) == 3);
623             REQUIRE(timeline->getClipPosition(cid2) == 3);
624             REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly);
625             REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly);
626             // we check that the av group was correctly created
627             REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2}));
628             int g1 = timeline->m_groups->getDirectAncestor(cid1);
629             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2}));
630             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
631         };
632         state();
633 
634         timeline->m_audioTarget.insert(tid2, 0);
635         timeline->m_videoTarget = tid1;
636         // Make tracks active
637         timeline->setTrackProperty(tid1, QStringLiteral("kdenlive:timeline_active"), QStringLiteral("1"));
638         timeline->setTrackProperty(tid2, QStringLiteral("kdenlive:timeline_active"), QStringLiteral("1"));
639         REQUIRE(TimelineFunctions::insertZone(timeline, {tid1, tid2}, binId, 3 + 2, {l / 4, 3 * l / 4}, false));
640         timeline->m_audioTarget.clear();
641         timeline->m_videoTarget = -1;
642         int small_length = 3 * l / 4 - l / 4;
643         int cid3 = timeline->getClipByPosition(tid1, 3 + 2);
644         int cid4 = timeline->getClipByPosition(tid2, 3 + 2);
645         int cid5 = timeline->getClipByPosition(tid1, 3 + 2 + small_length);
646         int cid6 = timeline->getClipByPosition(tid2, 3 + 2 + small_length);
647 
__anonf52080221402() 648         auto state2 = [&]() {
649             REQUIRE(timeline->checkConsistency());
650             REQUIRE(timeline->getTrackClipsCount(tid1) == 3);
651             REQUIRE(timeline->getTrackClipsCount(tid2) == 3);
652             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
653             REQUIRE(timeline->getClipTrackId(cid2) == tid2);
654             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
655             REQUIRE(timeline->getClipTrackId(cid4) == tid2);
656             REQUIRE(timeline->getClipTrackId(cid5) == tid1);
657             REQUIRE(timeline->getClipTrackId(cid6) == tid2);
658             REQUIRE(timeline->getClipPosition(cid1) == 3);
659             REQUIRE(timeline->getClipPosition(cid2) == 3);
660             REQUIRE(timeline->getClipPosition(cid3) == 3 + 2);
661             REQUIRE(timeline->getClipPosition(cid4) == 3 + 2);
662             REQUIRE(timeline->getClipPosition(cid5) == 3 + 2 + small_length);
663             REQUIRE(timeline->getClipPosition(cid6) == 3 + 2 + small_length);
664             REQUIRE(timeline->getClipPlaytime(cid1) + timeline->getClipPlaytime(cid5) == l);
665             REQUIRE(timeline->getClipPlaytime(cid1) == 2);
666             REQUIRE(timeline->getClipPlaytime(cid3) == small_length);
667             REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly);
668             REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly);
669             REQUIRE(timeline->getClipPtr(cid3)->clipState() == PlaylistState::VideoOnly);
670             REQUIRE(timeline->getClipPtr(cid4)->clipState() == PlaylistState::AudioOnly);
671             REQUIRE(timeline->getClipPtr(cid5)->clipState() == PlaylistState::VideoOnly);
672             REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::AudioOnly);
673             // we check that the av group was correctly created
674             REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2}));
675             int g1 = timeline->m_groups->getDirectAncestor(cid1);
676             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2}));
677             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
678 
679             REQUIRE(timeline->getGroupElements(cid3) == std::unordered_set<int>({cid3, cid4}));
680             int g2 = timeline->m_groups->getDirectAncestor(cid3);
681             REQUIRE(timeline->m_groups->getDirectChildren(g2) == std::unordered_set<int>({cid3, cid4}));
682             REQUIRE(timeline->m_groups->getType(g2) == GroupType::AVSplit);
683 
684             int g3 = timeline->m_groups->getDirectAncestor(cid5);
685             REQUIRE(timeline->m_groups->getDirectChildren(g3) == std::unordered_set<int>({cid5, cid6}));
686             REQUIRE(timeline->m_groups->getType(g3) == GroupType::AVSplit);
687         };
688         state2();
689         undoStack->undo();
690         state();
691         undoStack->redo();
692         state2();
693     }
694 
695     binModel->clean();
696     pCore->m_projectManager = nullptr;
697 }
698 
699 TEST_CASE("Copy/paste", "[CP]")
700 {
701     auto binModel = pCore->projectItemModel();
702     binModel->clean();
703     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
704     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
705 
706     // Here we do some trickery to enable testing.
707 
708     // we mock a doc to stub the getDocumentProperty
709 
710     Mock<KdenliveDoc> docMock;
__anonf52080221502(const QString &name, const QString &defaultValue) 711     When(Method(docMock, getDocumentProperty)).AlwaysDo([](const QString &name, const QString &defaultValue) {
712         Q_UNUSED(name) Q_UNUSED(defaultValue)
713         qDebug() << "Intercepted call";
714         return QStringLiteral("dummyId");
715     });
716 
717     KdenliveDoc &mockedDoc = docMock.get();
718 
719     // We mock the project class so that the undoStack function returns our undoStack, and our mocked document
720     Mock<ProjectManager> pmMock;
721     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
722     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
723     When(Method(pmMock, current)).AlwaysReturn(&mockedDoc);
724 
725     ProjectManager &mocked = pmMock.get();
726     pCore->m_projectManager = &mocked;
727 
728     // We also mock timeline object to spy few functions and mock others
729     TimelineItemModel tim(&profile_trimming, undoStack);
730     Mock<TimelineItemModel> timMock(tim);
__anonf52080221602(...) 731     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
732     TimelineItemModel::finishConstruct(timeline, guideModel);
733 
734     RESET(timMock)
735 
736     QString binId = createProducerWithSound(profile_trimming, binModel);
737     QString binId2 = createProducer(profile_trimming, "red", binModel);
738 
739     int tid2b = TrackModel::construct(timeline, -1, -1, QString(), true);
740     int tid2 = TrackModel::construct(timeline, -1, -1, QString(), true);
741     int tid1 = TrackModel::construct(timeline);
742     int tid1b = TrackModel::construct(timeline);
743 
744     // Setup timeline audio drop info
745     QMap <int, QString>audioInfo;
746     audioInfo.insert(1,QStringLiteral("stream1"));
747     timeline->m_binAudioTargets = audioInfo;
748     timeline->m_videoTarget = tid1;
749 
750     SECTION("Simple copy paste of one clip")
751     {
752 
753         int cid1 = -1;
754         REQUIRE(timeline->requestClipInsertion(binId2, tid1, 3, cid1, true, true, false));
755         int l = timeline->getClipPlaytime(cid1);
756         int cid2 = -1;
757         REQUIRE(timeline->requestClipInsertion(binId2, tid1, 3 + l, cid2, true, true, false));
758 
__anonf52080221702() 759         auto state = [&]() {
760             REQUIRE(timeline->checkConsistency());
761             REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
762             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
763             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
764             REQUIRE(timeline->getClipPosition(cid1) == 3);
765             REQUIRE(timeline->getClipPosition(cid2) == 3 + l);
766         };
767         state();
768 
769         QString cpy_str = TimelineFunctions::copyClips(timeline, {cid1});
770 
771         // Try to paste in invalid positions
772         REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0));
773         state();
774         REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 4));
775         state();
776         REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 4 + l));
777         state();
778         // Paste in audio track
779         REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid2, 0));
780         state();
781         REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid2b, 0));
782         state();
783 
784         // Paste after the last clip
785         REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 3 + 2 * l));
786         int cid3 = timeline->getTrackById(tid1)->getClipByPosition(3 + 2 * l + 1);
787         REQUIRE(cid3 != -1);
__anonf52080221802() 788         auto state2 = [&]() {
789             REQUIRE(timeline->checkConsistency());
790             REQUIRE(timeline->getTrackClipsCount(tid1) == 3);
791             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
792             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
793             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
794             REQUIRE(timeline->getClipPosition(cid1) == 3);
795             REQUIRE(timeline->getClipPosition(cid2) == 3 + l);
796             REQUIRE(timeline->getClipPosition(cid3) == 3 + 2 * l);
797         };
798         state2();
799 
800         undoStack->undo();
801         state();
802         undoStack->redo();
803         state2();
804 
805         // Paste in different track
806         REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1b, 0));
807         int cid4 = timeline->getTrackById(tid1b)->getClipByPosition(0);
808         REQUIRE(cid4 != -1);
__anonf52080221902() 809         auto state3 = [&]() {
810             state2();
811             REQUIRE(timeline->getTrackClipsCount(tid1b) == 1);
812             REQUIRE(timeline->getClipTrackId(cid4) == tid1b);
813             REQUIRE(timeline->getClipPosition(cid4) == 0);
814         };
815         state3();
816 
817         undoStack->undo();
818         state2();
819         undoStack->undo();
820         state();
821         undoStack->redo();
822         state2();
823         undoStack->redo();
824         state3();
825     }
826 
827     SECTION("Copy paste groups")
828     {
829 
__anonf52080221a02() 830         auto state0 = [&]() {
831             REQUIRE(timeline->checkConsistency());
832             REQUIRE(timeline->getTrackClipsCount(tid1) == 0);
833             REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
834             REQUIRE(timeline->getTrackClipsCount(tid1b) == 0);
835             REQUIRE(timeline->getTrackClipsCount(tid2b) == 0);
836         };
837         state0();
838         int cid1 = -1;
839         REQUIRE(timeline->requestClipInsertion(binId, tid1, 3, cid1, true, true, false));
840         int l = timeline->getClipPlaytime(cid1);
841         int cid2 = timeline->m_groups->getSplitPartner(cid1);
842 
__anonf52080221b02(int count1, int count2) 843         auto state = [&](int count1, int count2) {
844             REQUIRE(timeline->checkConsistency());
845             REQUIRE(timeline->getTrackClipsCount(tid1) == count1);
846             REQUIRE(timeline->getTrackClipsCount(tid2) == count1);
847             REQUIRE(timeline->getTrackClipsCount(tid1b) == count2);
848             REQUIRE(timeline->getTrackClipsCount(tid2b) == count2);
849             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
850             REQUIRE(timeline->getClipTrackId(cid2) == tid2);
851             REQUIRE(timeline->getClipPosition(cid1) == 3);
852             REQUIRE(timeline->getClipPosition(cid2) == 3);
853             REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly);
854             REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly);
855             // we check that the av group was correctly created
856             REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2}));
857             int g1 = timeline->m_groups->getDirectAncestor(cid1);
858             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2}));
859             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
860         };
861         state(1, 0);
862 
863         QString cpy_str = TimelineFunctions::copyClips(timeline, {cid1});
864 
865         REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0));
866         state(1, 0);
867         REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 4));
868         state(1, 0);
869 
870         // potentially annoying selection
871         REQUIRE(timeline->requestSetSelection({cid1}));
872         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2});
873 
874         // paste on same track, after clip
875         REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 3 + 2 * l));
876         int cid3 = timeline->getTrackById(tid1)->getClipByPosition(3 + 2 * l + 1);
877         REQUIRE(cid3 != -1);
878         int cid4 = timeline->m_groups->getSplitPartner(cid3);
__anonf52080221c02(int count1, int count2) 879         auto state2 = [&](int count1, int count2) {
880             state(count1, count2);
881             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
882             REQUIRE(timeline->getClipTrackId(cid4) == tid2);
883             REQUIRE(timeline->getClipPosition(cid3) == 3 + 2 * l);
884             REQUIRE(timeline->getClipPosition(cid4) == 3 + 2 * l);
885             REQUIRE(timeline->getClipPtr(cid3)->clipState() == PlaylistState::VideoOnly);
886             REQUIRE(timeline->getClipPtr(cid4)->clipState() == PlaylistState::AudioOnly);
887             // we check that the av group was correctly created
888             REQUIRE(timeline->getGroupElements(cid3) == std::unordered_set<int>({cid3, cid4}));
889             int g1 = timeline->m_groups->getDirectAncestor(cid3);
890             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid3, cid4}));
891             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
892         };
893         state2(2, 0);
894 
895         // potentially annoying selection
896         REQUIRE(timeline->requestSetSelection({cid1}));
897         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2});
898         undoStack->undo();
899         REQUIRE(timeline->requestClearSelection());
900         state(1, 0);
901 
902         // potentially annoying selection
903         REQUIRE(timeline->requestSetSelection({cid1}));
904         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2});
905         undoStack->redo();
906         REQUIRE(timeline->requestClearSelection());
907         state2(2, 0);
908 
909         // another potentially annoying selection
910         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
911         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4});
912         undoStack->undo();
913         REQUIRE(timeline->requestClearSelection());
914         state(1, 0);
915         REQUIRE(timeline->requestSetSelection({cid1}));
916         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2});
917         undoStack->redo();
918         REQUIRE(timeline->requestClearSelection());
919         state2(2, 0);
920 
921         // now, we copy the old clips as well as those we just pasted. Let's do it using a selection
922         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
923         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4});
924         // since everything is selected, everything should be copied here
925         cpy_str = TimelineFunctions::copyClips(timeline, {cid1});
926 
927         REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0));
928         state2(2, 0);
929 
930         // parasitic selection
931         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
932         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4});
933 
934         // We paste on the other track
935         REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1b, 0));
936         qDebug() << "track tid1 count" << timeline->getTrackClipsCount(tid1);
937         qDebug() << "track tid2 count" << timeline->getTrackClipsCount(tid2);
938         qDebug() << "track tid1b count" << timeline->getTrackClipsCount(tid1b);
939         qDebug() << "track tid2b count" << timeline->getTrackClipsCount(tid2b);
940         int cid5 = timeline->getTrackById(tid1b)->getClipByPosition(0);
941         REQUIRE(cid5 != -1);
942         int cid6 = timeline->m_groups->getSplitPartner(cid5);
943         REQUIRE(cid6 != -1);
944         int cid7 = timeline->getTrackById(tid1b)->getClipByPosition(2 * l + 1);
945         REQUIRE(cid7 != -1);
946         int cid8 = timeline->m_groups->getSplitPartner(cid7);
947         REQUIRE(cid8 != -1);
__anonf52080221d02(int count1, int count2) 948         auto state3 = [&](int count1, int count2) {
949             state2(count1, count2);
950             REQUIRE(timeline->getClipTrackId(cid5) == tid1b);
951             REQUIRE(timeline->getClipTrackId(cid7) == tid1b);
952             REQUIRE(timeline->getClipTrackId(cid6) == tid2b);
953             REQUIRE(timeline->getClipTrackId(cid8) == tid2b);
954             REQUIRE(timeline->getClipPosition(cid5) == 0);
955             REQUIRE(timeline->getClipPosition(cid6) == 0);
956             REQUIRE(timeline->getClipPosition(cid7) == 2 * l);
957             REQUIRE(timeline->getClipPosition(cid8) == 2 * l);
958             REQUIRE(timeline->getClipPtr(cid5)->clipState() == PlaylistState::VideoOnly);
959             REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::AudioOnly);
960             REQUIRE(timeline->getClipPtr(cid7)->clipState() == PlaylistState::VideoOnly);
961             REQUIRE(timeline->getClipPtr(cid8)->clipState() == PlaylistState::AudioOnly);
962             // we check that the av group was correctly created
963             REQUIRE(timeline->getGroupElements(cid5) == std::unordered_set<int>({cid5, cid6}));
964             int g1 = timeline->m_groups->getDirectAncestor(cid5);
965             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid5, cid6}));
966             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
967 
968             REQUIRE(timeline->getGroupElements(cid7) == std::unordered_set<int>({cid7, cid8}));
969             int g2 = timeline->m_groups->getDirectAncestor(cid7);
970             REQUIRE(timeline->m_groups->getDirectChildren(g2) == std::unordered_set<int>({cid7, cid8}));
971             REQUIRE(timeline->m_groups->getType(g2) == GroupType::AVSplit);
972         };
973         state3(2, 2);
974 
975         // parasitic selection
976         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
977         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4});
978         undoStack->undo();
979         REQUIRE(timeline->requestClearSelection());
980         state2(2, 0);
981         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
982         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3, cid4});
983         undoStack->redo();
984         REQUIRE(timeline->requestClearSelection());
985         state3(2, 2);
986     }
987 
988     SECTION("Paste when tracks get deleted")
989     {
__anonf52080221e02() 990         auto state0 = [&]() {
991             REQUIRE(timeline->checkConsistency());
992             REQUIRE(timeline->getTrackClipsCount(tid1) == 0);
993             REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
994             REQUIRE(timeline->getTrackClipsCount(tid1b) == 0);
995             REQUIRE(timeline->getTrackClipsCount(tid2b) == 0);
996         };
997         state0();
998         int cid1 = -1;
999         REQUIRE(timeline->requestClipInsertion(binId, tid1, 3, cid1, true, true, false));
1000         timeline->getClipPlaytime(cid1);
1001         int cid2 = timeline->m_groups->getSplitPartner(cid1);
1002 
__anonf52080221f02() 1003         auto state = [&]() {
1004             REQUIRE(timeline->checkConsistency());
1005             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1006             REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
1007             REQUIRE(timeline->getTrackClipsCount(tid1b) == 0);
1008             REQUIRE(timeline->getTrackClipsCount(tid2b) == 0);
1009             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1010             REQUIRE(timeline->getClipTrackId(cid2) == tid2);
1011             REQUIRE(timeline->getClipPosition(cid1) == 3);
1012             REQUIRE(timeline->getClipPosition(cid2) == 3);
1013             REQUIRE(timeline->getClipPtr(cid1)->clipState() == PlaylistState::VideoOnly);
1014             REQUIRE(timeline->getClipPtr(cid2)->clipState() == PlaylistState::AudioOnly);
1015             // we check that the av group was correctly created
1016             REQUIRE(timeline->getGroupElements(cid1) == std::unordered_set<int>({cid1, cid2}));
1017             int g1 = timeline->m_groups->getDirectAncestor(cid1);
1018             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid1, cid2}));
1019             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
1020         };
1021         state();
1022 
1023         QString cpy_str = TimelineFunctions::copyClips(timeline, {cid1});
1024 
1025         // we delete origin of the copy, paste should still be possible
1026         REQUIRE(timeline->requestItemDeletion(cid1));
1027         state0();
1028 
1029         REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0));
1030         int cid3 = timeline->getTrackById(tid1)->getClipByPosition(0);
1031         REQUIRE(cid3 != -1);
1032         int cid4 = timeline->m_groups->getSplitPartner(cid3);
__anonf52080222002(int audio) 1033         auto state2 = [&](int audio) {
1034             REQUIRE(timeline->checkConsistency());
1035             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1036             REQUIRE(timeline->getTrackClipsCount(audio) == 1);
1037             REQUIRE(timeline->getTrackClipsCount(tid1b) == 0);
1038             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
1039             REQUIRE(timeline->getClipTrackId(cid4) == audio);
1040             REQUIRE(timeline->getClipPosition(cid3) == 0);
1041             REQUIRE(timeline->getClipPosition(cid4) == 0);
1042             REQUIRE(timeline->getClipPtr(cid3)->clipState() == PlaylistState::VideoOnly);
1043             REQUIRE(timeline->getClipPtr(cid4)->clipState() == PlaylistState::AudioOnly);
1044             // we check that the av group was correctly created
1045             REQUIRE(timeline->getGroupElements(cid3) == std::unordered_set<int>({cid3, cid4}));
1046             int g1 = timeline->m_groups->getDirectAncestor(cid3);
1047             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid3, cid4}));
1048             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
1049         };
1050         state2(tid2);
1051 
1052         undoStack->undo();
1053         state0();
1054         undoStack->redo();
1055         state2(tid2);
1056         undoStack->undo();
1057         state0();
1058 
1059         // now, we remove all audio tracks, making paste impossible
1060         REQUIRE(timeline->requestTrackDeletion(tid2));
1061         REQUIRE(timeline->requestTrackDeletion(tid2b));
1062         REQUIRE_FALSE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0));
1063 
1064         // undo one deletion
1065         undoStack->undo();
1066         // now, tid2b should be a valid audio track
1067         REQUIRE(TimelineFunctions::pasteClips(timeline, cpy_str, tid1, 0));
1068         cid3 = timeline->getTrackById(tid1)->getClipByPosition(0);
1069         REQUIRE(cid3 != -1);
1070         cid4 = timeline->m_groups->getSplitPartner(cid3);
1071         state2(tid2b);
1072     }
1073     binModel->clean();
1074     pCore->m_projectManager = nullptr;
1075 }
1076 
1077 TEST_CASE("Advanced trimming operations: Slip", "[TrimmingSlip]")
1078 {
1079     auto binModel = pCore->projectItemModel();
1080     binModel->clean();
1081     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
1082     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
1083 
1084     // Here we do some trickery to enable testing.
1085     // We mock the project class so that the undoStack function returns our undoStack
1086 
1087     Mock<ProjectManager> pmMock;
1088     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
1089     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
1090 
1091     ProjectManager &mocked = pmMock.get();
1092     pCore->m_projectManager = &mocked;
1093 
1094     // We also mock timeline object to spy few functions and mock others
1095     TimelineItemModel tim(&profile_trimming, undoStack);
1096     Mock<TimelineItemModel> timMock(tim);
__anonf52080222102(...) 1097     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
1098     TimelineItemModel::finishConstruct(timeline, guideModel);
1099 
1100     RESET(timMock)
1101 
1102     QString binId = createProducer(profile_trimming, "red", binModel);
1103     QString binId2 = createProducer(profile_trimming, "blue", binModel);
1104 
1105     int tid1 = TrackModel::construct(timeline);
1106     int tid2 = TrackModel::construct(timeline);
1107 
1108     int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1109     int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly);
1110     int cid3 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1111     int cid4 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1112     int cid5 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1113 
1114     timeline->m_allClips[cid1]->m_endlessResize = false;
1115     timeline->m_allClips[cid2]->m_endlessResize = false;
1116     timeline->m_allClips[cid3]->m_endlessResize = false;
1117     timeline->m_allClips[cid4]->m_endlessResize = false;
1118     timeline->m_allClips[cid5]->m_endlessResize = false;
1119 
1120     // sliping a fullsized clips should not to anything
1121     SECTION("Slip single fullsized clip")
1122     {
1123         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1124         int l = timeline->getClipPlaytime(cid1);
__anonf52080222202() 1125         auto state = [&]() {
1126             REQUIRE(timeline->checkConsistency());
1127             REQUIRE(timeline->getClipPlaytime(cid1) == l);
1128             REQUIRE(timeline->getClipPosition(cid1) == 5);
1129             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0);
1130             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1);
1131         };
1132         state();
1133 
1134         REQUIRE(timeline->requestClipSlip(cid1, 3) == 3);
1135         state();
1136 
1137         REQUIRE(timeline->requestClipSlip(cid1, -3) == -3);
1138         state();
1139 
1140         undoStack->undo();
1141         state();
1142         undoStack->undo();
1143         state();
1144 
1145         undoStack->redo();
1146         state();
1147         undoStack->redo();
1148         state();
1149     }
1150 
1151     // slipping a downsized clip should only change the in and out point
1152     SECTION("Slip single cutted clip")
1153     {
1154         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1155         int l = timeline->getClipPlaytime(cid1);
1156         REQUIRE(timeline->requestItemResize(cid1, l - 5, true) == l - 5);
1157         REQUIRE(timeline->requestItemResize(cid1, l - 11, false) == l - 11);
1158 
__anonf52080222302() 1159         auto state = [&]() {
1160             REQUIRE(timeline->checkConsistency());
1161             REQUIRE(timeline->getClipPlaytime(cid1) == l - 11);
1162             REQUIRE(timeline->getClipPosition(cid1) == 5 + 6);
1163             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 6);
1164             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 6);
1165         };
1166         state();
1167 
1168         REQUIRE(timeline->requestClipSlip(cid1, 3) == 3);
__anonf52080222402() 1169         auto state2 = [&]() {
1170             REQUIRE(timeline->checkConsistency());
1171             REQUIRE(timeline->getClipPlaytime(cid1) == l - 11);
1172             REQUIRE(timeline->getClipPosition(cid1) == 5 + 6);
1173             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 3);
1174             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 9);
1175         };
1176         state2();
1177 
1178         REQUIRE(timeline->requestClipSlip(cid1, -3) == -3);
1179         state();
1180 
1181         undoStack->undo();
1182         state2();
1183         undoStack->undo();
1184         state();
1185 
1186         undoStack->redo();
1187         state2();
1188         undoStack->redo();
1189         state();
1190 
1191     }
1192 
1193     // if offset is bigger than the borders use the biggest possible offset without going beyond the borders
1194     SECTION("Slip beyond borders")
1195     {
1196         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1197         int l = timeline->getClipPlaytime(cid1);
1198 
1199         REQUIRE(timeline->getClipPlaytime(cid1) == l);
1200         REQUIRE(timeline->requestItemResize(cid1, l - 5, true) == l - 5);
1201         REQUIRE(timeline->requestItemResize(cid1, l - 11, false) == l - 11);
1202         REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 6);
1203 
1204 
__anonf52080222502() 1205         auto state = [&]() {
1206             REQUIRE(timeline->checkConsistency());
1207             REQUIRE(timeline->getClipPlaytime(cid1) == l - 11);
1208             REQUIRE(timeline->getClipPosition(cid1) == 5 + 6);
1209             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 6);
1210             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 6);
1211         };
1212         state();
1213 
1214         // left border
1215         REQUIRE(timeline->requestClipSlip(cid1, 30) == 30);
__anonf52080222602() 1216         auto state2 = [&]() {
1217             REQUIRE(timeline->checkConsistency());
1218             REQUIRE(timeline->getClipPlaytime(cid1) == l - 11);
1219             REQUIRE(timeline->getClipPosition(cid1) == 5 + 6);
1220             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0);
1221             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 12);
1222         };
1223         state2();
1224 
1225         // right border
1226         REQUIRE(timeline->requestClipSlip(cid1, -30) == -30);
__anonf52080222702() 1227         auto state3 = [&]() {
1228             REQUIRE(timeline->checkConsistency());
1229             REQUIRE(timeline->getClipPlaytime(cid1) == l - 11);
1230             REQUIRE(timeline->getClipPosition(cid1) == 5 + 6);
1231             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 11);
1232             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l - 1);
1233         };
1234         state3();
1235 
1236         undoStack->undo();
1237         state2();
1238         undoStack->undo();
1239         state();
1240 
1241         undoStack->redo();
1242         state2();
1243         undoStack->redo();
1244         state3();
1245     }
1246 
1247     // slipping one clip of a group should slip all members
1248     SECTION("Slip group")
1249     {
1250         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1251         int l1 = timeline->getClipPlaytime(cid1);
1252         REQUIRE(timeline->requestItemResize(cid1, l1 - 5, true) == l1 - 5);
1253         REQUIRE(timeline->requestItemResize(cid1, l1 - 11, false) == l1 - 11);
1254 
1255         REQUIRE(timeline->requestClipMove(cid2, tid1, 50));
1256         int l2 = timeline->getClipPlaytime(cid2);
1257         REQUIRE(timeline->requestItemResize(cid2, l2 - 11, false) == l2 - 11);
1258 
1259         REQUIRE(timeline->requestClipMove(cid3, tid2, 25));
1260         int l3 = timeline->getClipPlaytime(cid3);
1261         REQUIRE(timeline->requestItemResize(cid3, l3 - 5, true) == l3 - 5);
1262 
1263         REQUIRE(timeline->requestClipMove(cid4, tid2, 0));
1264         int l4 = timeline->getClipPlaytime(cid4);
1265         REQUIRE(timeline->requestItemResize(cid4, l4 - 9, true) == l4 - 9);
1266         REQUIRE(timeline->requestItemResize(cid4, l4 - 17, false) == l4 - 17);
1267 
1268         REQUIRE(timeline->requestClipMove(cid5, tid2, 60));
1269         int l5 = timeline->getClipPlaytime(cid5);
1270         int gid1 = timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5}), true, GroupType::Normal);
1271         REQUIRE(gid1 > -1);
1272 
__anonf52080222802() 1273         auto state = [&]() {
1274             REQUIRE(timeline->checkConsistency());
1275             REQUIRE(timeline->getClipPlaytime(cid1) == l1 - 11);
1276             REQUIRE(timeline->getClipPosition(cid1) == 5 + 6);
1277             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 6);
1278             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 6);
1279             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1280 
1281             REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 11);
1282             REQUIRE(timeline->getClipPosition(cid2) == 50 + 11);
1283             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 11);
1284             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 -1);
1285             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
1286 
1287             REQUIRE(timeline->getClipPlaytime(cid3) == l3 - 5);
1288             REQUIRE(timeline->getClipPosition(cid3) == 25);
1289             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1290             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 6);
1291             REQUIRE(timeline->getClipTrackId(cid3) == tid2);
1292 
1293             REQUIRE(timeline->getClipPlaytime(cid4) == l4 - 17);
1294             REQUIRE(timeline->getClipPosition(cid4) == 8);
1295             REQUIRE(timeline->getClipPtr(cid4)->getIn() == 8);
1296             REQUIRE(timeline->getClipPtr(cid4)->getOut() == l4 - 10);
1297             REQUIRE(timeline->getClipTrackId(cid4) == tid2);
1298 
1299             REQUIRE(timeline->getClipPlaytime(cid5) == l5);
1300             REQUIRE(timeline->getClipPosition(cid5) == 60);
1301             REQUIRE(timeline->getClipPtr(cid5)->getIn() == 0);
1302             REQUIRE(timeline->getClipPtr(cid5)->getOut() == l5 - 1);
1303             REQUIRE(timeline->getClipTrackId(cid5) == tid2);
1304 
1305             REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5}));
1306         };
1307         state();
1308 
1309         REQUIRE(timeline->requestClipSlip(cid1, 3) == 3);
1310 
__anonf52080222902() 1311         auto state2 = [&]() {
1312             REQUIRE(timeline->checkConsistency());
1313             REQUIRE(timeline->getClipPlaytime(cid1) == l1 - 11);
1314             REQUIRE(timeline->getClipPosition(cid1) == 5 + 6);
1315             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 3);
1316             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 9);
1317             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1318 
1319             REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 11);
1320             REQUIRE(timeline->getClipPosition(cid2) == 50 + 11);
1321             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 8);
1322             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 4);
1323             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
1324 
1325             REQUIRE(timeline->getClipPlaytime(cid3) == l3 - 5);
1326             REQUIRE(timeline->getClipPosition(cid3) == 25);
1327             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1328             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 6);
1329             REQUIRE(timeline->getClipTrackId(cid3) == tid2);
1330 
1331             REQUIRE(timeline->getClipPlaytime(cid4) == l4 - 17);
1332             REQUIRE(timeline->getClipPosition(cid4) == 8);
1333             REQUIRE(timeline->getClipPtr(cid4)->getIn() == 5);
1334             REQUIRE(timeline->getClipPtr(cid4)->getOut() == l4 - 13);
1335             REQUIRE(timeline->getClipTrackId(cid4) == tid2);
1336 
1337             REQUIRE(timeline->getClipPlaytime(cid5) == l5);
1338             REQUIRE(timeline->getClipPosition(cid5) == 60);
1339             REQUIRE(timeline->getClipPtr(cid5)->getIn() == 0);
1340             REQUIRE(timeline->getClipPtr(cid5)->getOut() == l5 - 1);
1341             REQUIRE(timeline->getClipTrackId(cid5) == tid2);
1342 
1343             REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5}));
1344         };
1345         state2();
1346 
1347         REQUIRE(timeline->requestClipSlip(cid4, 30) == 30);
1348 
__anonf52080222a02() 1349         auto state3 = [&]() {
1350             REQUIRE(timeline->checkConsistency());
1351             REQUIRE(timeline->getClipPlaytime(cid1) == l1 - 11);
1352             REQUIRE(timeline->getClipPosition(cid1) == 5 + 6);
1353             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0);
1354             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 12);
1355             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1356 
1357             REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 11);
1358             REQUIRE(timeline->getClipPosition(cid2) == 50 + 11);
1359             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0);
1360             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 12);
1361             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
1362 
1363             REQUIRE(timeline->getClipPlaytime(cid3) == l3 - 5);
1364             REQUIRE(timeline->getClipPosition(cid3) == 25);
1365             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1366             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 6);
1367             REQUIRE(timeline->getClipTrackId(cid3) == tid2);
1368 
1369             REQUIRE(timeline->getClipPlaytime(cid4) == l4 - 17);
1370             REQUIRE(timeline->getClipPosition(cid4) == 8);
1371             REQUIRE(timeline->getClipPtr(cid4)->getIn() == 0);
1372             REQUIRE(timeline->getClipPtr(cid4)->getOut() == l4 - 18);
1373             REQUIRE(timeline->getClipTrackId(cid4) == tid2);
1374 
1375             REQUIRE(timeline->getClipPlaytime(cid5) == l5);
1376             REQUIRE(timeline->getClipPosition(cid5) == 60);
1377             REQUIRE(timeline->getClipPtr(cid5)->getIn() == 0);
1378             REQUIRE(timeline->getClipPtr(cid5)->getOut() == l5 - 1);
1379             REQUIRE(timeline->getClipTrackId(cid5) == tid2);
1380 
1381             REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3, cid4, cid5}));
1382         };
1383         state3();
1384 
1385         undoStack->undo();
1386         state2();
1387         undoStack->undo();
1388         state();
1389 
1390         undoStack->redo();
1391         state2();
1392         undoStack->redo();
1393         state3();
1394     }
1395 
1396     binModel->clean();
1397     pCore->m_projectManager = nullptr;
1398 }
1399 
1400 TEST_CASE("Advanced trimming operations: Ripple", "[TrimmingRipple]")
1401 {
1402     auto binModel = pCore->projectItemModel();
1403     binModel->clean();
1404     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
1405     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
1406 
1407     // Here we do some trickery to enable testing.
1408     // We mock the project class so that the undoStack function returns our undoStack
1409 
1410     Mock<ProjectManager> pmMock;
1411     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
1412     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
1413 
1414     ProjectManager &mocked = pmMock.get();
1415     pCore->m_projectManager = &mocked;
1416 
1417     // We also mock timeline object to spy few functions and mock others
1418     TimelineItemModel tim(&profile_trimming, undoStack);
1419     Mock<TimelineItemModel> timMock(tim);
__anonf52080222b02(...) 1420     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
1421     TimelineItemModel::finishConstruct(timeline, guideModel);
1422 
1423     RESET(timMock)
1424 
1425     QString binId = createProducer(profile_trimming, "red", binModel);
1426     QString binId2 = createProducer(profile_trimming, "blue", binModel);
1427 
1428     int tid1 = TrackModel::construct(timeline);
1429     int tid2 = TrackModel::construct(timeline);
1430 
1431     int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1432     int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly);
1433     int cid3 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1434     int cid4 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1435     int cid5 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1436     int cid6 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1437 
1438     timeline->m_allClips[cid1]->m_endlessResize = false;
1439     timeline->m_allClips[cid2]->m_endlessResize = false;
1440     timeline->m_allClips[cid3]->m_endlessResize = false;
1441     timeline->m_allClips[cid4]->m_endlessResize = false;
1442     timeline->m_allClips[cid5]->m_endlessResize = false;
1443 
1444     // ripple resize a fullsized clip longer should not to anything
1445     SECTION("Ripple resize single fullsized clip (longer)")
1446     {
1447         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1448         int l1 = timeline->getClipPlaytime(cid1);
1449 
1450         REQUIRE(timeline->requestClipMove(cid2, tid1, 50));
1451         int l2 = timeline->getClipPlaytime(cid2);
1452 
1453         REQUIRE(timeline->requestClipMove(cid3, tid1, 80));
1454         int l3 = timeline->getClipPlaytime(cid3);
1455 
__anonf52080222c02() 1456         auto state = [&]() {
1457             REQUIRE(timeline->checkConsistency());
1458             REQUIRE(timeline->getClipPlaytime(cid1) == l1);
1459             REQUIRE(timeline->getClipPosition(cid1) == 5);
1460             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0);
1461             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 1);
1462             REQUIRE(timeline->getClipPlaytime(cid2) == l2);
1463             REQUIRE(timeline->getClipPosition(cid2) == 50);
1464             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0);
1465             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 1);
1466             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1467             REQUIRE(timeline->getClipPosition(cid3) == 80);
1468             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1469             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1470         };
1471         state();
1472 
1473         REQUIRE(timeline->requestItemRippleResize(timeline, cid1, l1 + 5, true));
1474         state();
1475 
1476         REQUIRE(timeline->requestItemRippleResize(timeline, cid1, l1 + 5, false));
1477         state();
1478 
1479         REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 + 5, true));
1480         REQUIRE(timeline->requestItemRippleResize(timeline, cid1, l2 + 5, false));
1481         state();
1482 
1483         REQUIRE(timeline->requestItemRippleResize(timeline, cid3, l3 + 5, true));
1484         REQUIRE(timeline->requestItemRippleResize(timeline, cid3, l3 + 5, false));
1485         state();
1486 
1487         undoStack->undo();
1488         state();
1489         undoStack->undo();
1490         state();
1491 
1492         undoStack->redo();
1493         state();
1494         undoStack->redo();
1495         state();
1496     }
1497 
1498     // ripple resize a fullsized clip shorter should resize the clip and move following clips
1499     SECTION("Ripple resize single fullsized clip (shorter)")
1500     {
1501         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1502         int l1 = timeline->getClipPlaytime(cid1);
1503 
1504         REQUIRE(timeline->requestClipMove(cid2, tid1, 50));
1505         int l2 = timeline->getClipPlaytime(cid2);
1506 
1507         REQUIRE(timeline->requestClipMove(cid3, tid1, 80));
1508         int l3 = timeline->getClipPlaytime(cid3);
1509 
__anonf52080222d02() 1510         auto stateA1 = [&]() {
1511             REQUIRE(timeline->checkConsistency());
1512             REQUIRE(timeline->getClipPlaytime(cid1) == l1);
1513             REQUIRE(timeline->getClipPosition(cid1) == 5);
1514             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0);
1515             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 1);
1516         };
__anonf52080222e02() 1517         auto stateA2 = [&]() {
1518             REQUIRE(timeline->checkConsistency());
1519             REQUIRE(timeline->getClipPlaytime(cid2) == l2);
1520             REQUIRE(timeline->getClipPosition(cid2) == 50);
1521             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0);
1522             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 1);
1523 
1524             REQUIRE(timeline->checkConsistency());
1525             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1526             REQUIRE(timeline->getClipPosition(cid3) == 80);
1527             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1528             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1529         };
1530         stateA1();
1531         stateA2();
1532 
__anonf52080222f02() 1533         auto stateB = [&]() {
1534             REQUIRE(timeline->checkConsistency());
1535             REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 5);
1536             REQUIRE(timeline->getClipPosition(cid2) == 50);
1537             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0);
1538             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6);
1539 
1540             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1541             REQUIRE(timeline->getClipPosition(cid3) == 75);
1542             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1543             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1544         };
1545         REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 5, true) == l2 - 5);
1546         stateA1();
1547         stateB();
1548 
__anonf52080223002() 1549         auto stateC = [&]() {
1550             REQUIRE(timeline->checkConsistency());
1551             REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 8);
1552             REQUIRE(timeline->getClipPosition(cid2) == 50);
1553             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 3);
1554             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6);
1555 
1556             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1557             REQUIRE(timeline->getClipPosition(cid3) == 72);
1558             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1559             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1560         };
1561 
1562         REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 8, false));
1563         stateA1();
1564         stateC();
1565 
1566         undoStack->undo();
1567         stateA1();
1568         stateB();
1569 
1570         undoStack->undo();
1571         stateA1();
1572         stateA2();
1573 
1574         undoStack->redo();
1575         stateA1();
1576         stateB();
1577 
1578         undoStack->redo();
1579         stateA1();
1580         stateC();
1581     }
1582 
1583     // ripple resize a grouped clip should move the affect all group partners on other tracks with same position as well
1584     SECTION("Ripple resize fullsized multitrack group (shorter)")
1585     {
1586         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1587         int l1 = timeline->getClipPlaytime(cid1);
1588 
1589         REQUIRE(timeline->requestClipMove(cid2, tid1, 50));
1590         int l2 = timeline->getClipPlaytime(cid2);
1591 
1592         REQUIRE(timeline->requestClipMove(cid3, tid1, 80));
1593         int l3 = timeline->getClipPlaytime(cid3);
1594 
1595         REQUIRE(timeline->requestClipMove(cid4, tid2, 5));
1596         int l4 = timeline->getClipPlaytime(cid4);
1597         REQUIRE(l4 == l1);
1598         int gid1 = timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid4}), true, GroupType::Normal);
1599 
1600         REQUIRE(timeline->requestClipMove(cid5, tid2, 50));
1601         int l5 = timeline->getClipPlaytime(cid5);
1602         REQUIRE(l5 == l2);
1603         int gid2 = timeline->requestClipsGroup(std::unordered_set<int>({cid2, cid5}), true, GroupType::Normal);
1604 
1605         REQUIRE(timeline->requestClipMove(cid6, tid2, 80));
1606         int l6 = timeline->getClipPlaytime(cid6);
1607         REQUIRE(l6 == l3);
1608         int gid3 = timeline->requestClipsGroup(std::unordered_set<int>({cid3, cid6}), true, GroupType::Normal);
1609 
__anonf52080223102() 1610         auto stateA1 = [&]() {
1611             REQUIRE(timeline->checkConsistency());
1612             REQUIRE(timeline->getClipPlaytime(cid1) == l1);
1613             REQUIRE(timeline->getClipPosition(cid1) == 5);
1614             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0);
1615             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 1);
1616 
1617             REQUIRE(timeline->checkConsistency());
1618             REQUIRE(timeline->getClipPlaytime(cid4) == timeline->getClipPlaytime(cid1));
1619             REQUIRE(timeline->getClipPosition(cid4) == timeline->getClipPosition(cid1));
1620             REQUIRE(timeline->getClipPtr(cid4)->getIn() == timeline->getClipPtr(cid1)->getIn());
1621             REQUIRE(timeline->getClipPtr(cid4)->getOut() == timeline->getClipPtr(cid1)->getOut());
1622         };
__anonf52080223202() 1623         auto stateA2 = [&]() {
1624             REQUIRE(timeline->checkConsistency());
1625             REQUIRE(timeline->getClipPlaytime(cid2) == l2);
1626             REQUIRE(timeline->getClipPosition(cid2) == 50);
1627             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0);
1628             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 1);
1629 
1630             REQUIRE(timeline->checkConsistency());
1631             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1632             REQUIRE(timeline->getClipPosition(cid3) == 80);
1633             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1634             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1635 
1636             REQUIRE(timeline->checkConsistency());
1637             REQUIRE(timeline->getClipPlaytime(cid5) == timeline->getClipPlaytime(cid2));
1638             REQUIRE(timeline->getClipPosition(cid5) == timeline->getClipPosition(cid2));
1639             REQUIRE(timeline->getClipPtr(cid5)->getIn() == timeline->getClipPtr(cid2)->getIn());
1640             REQUIRE(timeline->getClipPtr(cid5)->getOut() == timeline->getClipPtr(cid2)->getOut());
1641 
1642             REQUIRE(timeline->checkConsistency());
1643             REQUIRE(timeline->getClipPlaytime(cid6) == timeline->getClipPlaytime(cid3));
1644             REQUIRE(timeline->getClipPosition(cid6) == timeline->getClipPosition(cid3));
1645             REQUIRE(timeline->getClipPtr(cid6)->getIn() == timeline->getClipPtr(cid3)->getIn());
1646             REQUIRE(timeline->getClipPtr(cid6)->getOut() == timeline->getClipPtr(cid3)->getOut());
1647         };
1648         stateA1();
1649         stateA2();
1650 
__anonf52080223302() 1651         auto stateB = [&]() {
1652             REQUIRE(timeline->checkConsistency());
1653             REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 5);
1654             REQUIRE(timeline->getClipPosition(cid2) == 50);
1655             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0);
1656             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6);
1657 
1658             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1659             REQUIRE(timeline->getClipPosition(cid3) == 75);
1660             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1661             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1662 
1663             REQUIRE(timeline->checkConsistency());
1664             REQUIRE(timeline->getClipPlaytime(cid5) == timeline->getClipPlaytime(cid2));
1665             REQUIRE(timeline->getClipPosition(cid5) == timeline->getClipPosition(cid2));
1666             REQUIRE(timeline->getClipPtr(cid5)->getIn() == timeline->getClipPtr(cid2)->getIn());
1667             REQUIRE(timeline->getClipPtr(cid5)->getOut() == timeline->getClipPtr(cid2)->getOut());
1668 
1669             REQUIRE(timeline->checkConsistency());
1670             REQUIRE(timeline->getClipPlaytime(cid6) == timeline->getClipPlaytime(cid3));
1671             REQUIRE(timeline->getClipPosition(cid6) == timeline->getClipPosition(cid3));
1672             REQUIRE(timeline->getClipPtr(cid6)->getIn() == timeline->getClipPtr(cid3)->getIn());
1673             REQUIRE(timeline->getClipPtr(cid6)->getOut() == timeline->getClipPtr(cid3)->getOut());
1674         };
1675         REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 5, true) == l2 - 5);
1676         stateA1();
1677         stateB();
1678 
__anonf52080223402() 1679         auto stateC = [&]() {
1680             REQUIRE(timeline->checkConsistency());
1681             REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 8);
1682             REQUIRE(timeline->getClipPosition(cid2) == 50);
1683             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 3);
1684             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6);
1685 
1686             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1687             REQUIRE(timeline->getClipPosition(cid3) == 72);
1688             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1689             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1690 
1691             REQUIRE(timeline->checkConsistency());
1692             REQUIRE(timeline->getClipPlaytime(cid5) == timeline->getClipPlaytime(cid2));
1693             REQUIRE(timeline->getClipPosition(cid5) == timeline->getClipPosition(cid2));
1694             REQUIRE(timeline->getClipPtr(cid5)->getIn() == timeline->getClipPtr(cid2)->getIn());
1695             REQUIRE(timeline->getClipPtr(cid5)->getOut() == timeline->getClipPtr(cid2)->getOut());
1696 
1697             REQUIRE(timeline->checkConsistency());
1698             REQUIRE(timeline->getClipPlaytime(cid6) == timeline->getClipPlaytime(cid3));
1699             REQUIRE(timeline->getClipPosition(cid6) == timeline->getClipPosition(cid3));
1700             REQUIRE(timeline->getClipPtr(cid6)->getIn() == timeline->getClipPtr(cid3)->getIn());
1701             REQUIRE(timeline->getClipPtr(cid6)->getOut() == timeline->getClipPtr(cid3)->getOut());
1702         };
1703 
1704         REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 8, false));
1705         stateA1();
1706         stateC();
1707 
1708         undoStack->undo();
1709         stateA1();
1710         stateB();
1711 
1712         undoStack->undo();
1713         stateA1();
1714         stateA2();
1715 
1716         undoStack->redo();
1717         stateA1();
1718         stateB();
1719 
1720         undoStack->redo();
1721         stateA1();
1722         stateC();
1723     }
1724 
1725     SECTION("Ripple resize fullsized single track group (shorter)")
1726     {
1727         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1728         int l1 = timeline->getClipPlaytime(cid1);
1729 
1730         REQUIRE(timeline->requestClipMove(cid2, tid1, 50));
1731         int l2 = timeline->getClipPlaytime(cid2);
1732 
1733         REQUIRE(timeline->requestClipMove(cid3, tid1, 80));
1734         int l3 = timeline->getClipPlaytime(cid3);
1735 
1736         int gid1 = timeline->requestClipsGroup(std::unordered_set<int>({cid1, cid2, cid3}), true, GroupType::Normal);
1737 
__anonf52080223502() 1738         auto stateA1 = [&]() {
1739             REQUIRE(timeline->checkConsistency());
1740             REQUIRE(timeline->getClipPlaytime(cid1) == l1);
1741             REQUIRE(timeline->getClipPosition(cid1) == 5);
1742             REQUIRE(timeline->getClipPtr(cid1)->getIn() == 0);
1743             REQUIRE(timeline->getClipPtr(cid1)->getOut() == l1 - 1);
1744 
1745             REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3}));
1746         };
__anonf52080223602() 1747         auto stateA2 = [&]() {
1748             REQUIRE(timeline->checkConsistency());
1749             REQUIRE(timeline->getClipPlaytime(cid2) == l2);
1750             REQUIRE(timeline->getClipPosition(cid2) == 50);
1751             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0);
1752             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 1);
1753 
1754             REQUIRE(timeline->checkConsistency());
1755             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1756             REQUIRE(timeline->getClipPosition(cid3) == 80);
1757             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1758             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1759 
1760             REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3}));
1761         };
1762         stateA1();
1763         stateA2();
1764 
__anonf52080223702() 1765         auto stateB = [&]() {
1766             REQUIRE(timeline->checkConsistency());
1767             REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 5);
1768             REQUIRE(timeline->getClipPosition(cid2) == 50);
1769             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 0);
1770             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6);
1771 
1772             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1773             REQUIRE(timeline->getClipPosition(cid3) == 75);
1774             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1775             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1776 
1777             REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3}));
1778         };
1779         REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 5, true) == l2 - 5);
1780         stateA1();
1781         stateB();
1782 
__anonf52080223802() 1783         auto stateC = [&]() {
1784             REQUIRE(timeline->checkConsistency());
1785             REQUIRE(timeline->getClipPlaytime(cid2) == l2 - 8);
1786             REQUIRE(timeline->getClipPosition(cid2) == 50);
1787             REQUIRE(timeline->getClipPtr(cid2)->getIn() == 3);
1788             REQUIRE(timeline->getClipPtr(cid2)->getOut() == l2 - 6);
1789 
1790             REQUIRE(timeline->getClipPlaytime(cid3) == l3);
1791             REQUIRE(timeline->getClipPosition(cid3) == 72);
1792             REQUIRE(timeline->getClipPtr(cid3)->getIn() == 0);
1793             REQUIRE(timeline->getClipPtr(cid3)->getOut() == l3 - 1);
1794 
1795             REQUIRE(timeline->m_groups->getLeaves(gid1) == std::unordered_set<int>({cid1, cid2, cid3}));
1796         };
1797 
1798         REQUIRE(timeline->requestItemRippleResize(timeline, cid2, l2 - 8, false));
1799         stateA1();
1800         stateC();
1801 
1802         undoStack->undo();
1803         stateA1();
1804         stateB();
1805 
1806         undoStack->undo();
1807         stateA1();
1808         stateA2();
1809 
1810         undoStack->redo();
1811         stateA1();
1812         stateB();
1813 
1814         undoStack->redo();
1815         stateA1();
1816         stateC();
1817     }
1818 
1819     binModel->clean();
1820     pCore->m_projectManager = nullptr;
1821 }
1822 
1823