1 #include "test_utils.hpp"
2 
3 using namespace fakeit;
4 std::default_random_engine g(42);
5 Mlt::Profile profile_model;
6 
7 TEST_CASE("Basic creation/deletion of a track", "[TrackModel]")
8 {
9     auto binModel = pCore->projectItemModel();
10     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
11     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
12 
13     // Here we do some trickery to enable testing.
14     // We mock the project class so that the undoStack function returns our undoStack
15 
16     Mock<ProjectManager> pmMock;
17     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
18     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
19     ProjectManager &mocked = pmMock.get();
20     pCore->m_projectManager = &mocked;
21 
22     // We also mock timeline object to spy few functions and mock others
23     TimelineItemModel tim(&profile_model, undoStack);
24     Mock<TimelineItemModel> timMock(tim);
__anond6fdc6cc0102(...) 25     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
26     TimelineItemModel::finishConstruct(timeline, guideModel);
27 
28     Fake(Method(timMock, adjustAssetRange));
29 
30     // This is faked to allow to count calls
31 
32     int id1, id2, id3;
33     REQUIRE(timeline->requestTrackInsertion(-1, id1));
34     REQUIRE(timeline->checkConsistency());
35     REQUIRE(timeline->getTracksCount() == 1);
36     REQUIRE(timeline->getTrackPosition(id1) == 0);
37     RESET(timMock);
38 
39     REQUIRE(timeline->requestTrackInsertion(-1, id2));
40     REQUIRE(timeline->checkConsistency());
41     REQUIRE(timeline->getTracksCount() == 2);
42     REQUIRE(timeline->getTrackPosition(id2) == 1);
43     RESET(timMock);
44 
45     REQUIRE(timeline->requestTrackInsertion(-1, id3));
46     REQUIRE(timeline->checkConsistency());
47     REQUIRE(timeline->getTracksCount() == 3);
48     REQUIRE(timeline->getTrackPosition(id3) == 2);
49     RESET(timMock);
50 
51     int id4;
52     REQUIRE(timeline->requestTrackInsertion(1, id4));
53     REQUIRE(timeline->checkConsistency());
54     REQUIRE(timeline->getTracksCount() == 4);
55     REQUIRE(timeline->getTrackPosition(id1) == 0);
56     REQUIRE(timeline->getTrackPosition(id4) == 1);
57     REQUIRE(timeline->getTrackPosition(id2) == 2);
58     REQUIRE(timeline->getTrackPosition(id3) == 3);
59     RESET(timMock);
60 
61     // Test deletion
62     REQUIRE(timeline->requestTrackDeletion(id3));
63     REQUIRE(timeline->checkConsistency());
64     REQUIRE(timeline->getTracksCount() == 3);
65     RESET(timMock);
66 
67     REQUIRE(timeline->requestTrackDeletion(id1));
68     REQUIRE(timeline->checkConsistency());
69     REQUIRE(timeline->getTracksCount() == 2);
70     RESET(timMock);
71 
72     REQUIRE(timeline->requestTrackDeletion(id4));
73     REQUIRE(timeline->checkConsistency());
74     REQUIRE(timeline->getTracksCount() == 1);
75     RESET(timMock);
76 
77     // We are not allowed to delete the last track
78     REQUIRE_FALSE(timeline->requestTrackDeletion(id2));
79     REQUIRE(timeline->checkConsistency());
80     REQUIRE(timeline->getTracksCount() == 1);
81     RESET(timMock);
82 
83     SECTION("Delete a track with groups")
84     {
85         int tid1, tid2;
86         REQUIRE(timeline->requestTrackInsertion(-1, tid1));
87         REQUIRE(timeline->requestTrackInsertion(-1, tid2));
88         REQUIRE(timeline->checkConsistency());
89 
90         QString binId = createProducer(profile_model, "red", binModel);
91         int length = 20;
92         int cid1, cid2, cid3, cid4;
93         REQUIRE(timeline->requestClipInsertion(binId, tid1, 2, cid1));
94         REQUIRE(timeline->requestClipInsertion(binId, tid2, 0, cid2));
95         REQUIRE(timeline->requestClipInsertion(binId, tid2, length, cid3));
96         REQUIRE(timeline->requestClipInsertion(binId, tid2, 2 * length, cid4));
97         REQUIRE(timeline->checkConsistency());
98         REQUIRE(timeline->getClipsCount() == 4);
99         REQUIRE(timeline->getTracksCount() == 3);
100 
101         auto g1 = std::unordered_set<int>({cid1, cid3});
102         auto g2 = std::unordered_set<int>({cid2, cid4});
103         auto g3 = std::unordered_set<int>({cid1, cid4});
104         REQUIRE(timeline->requestClipsGroup(g1));
105         REQUIRE(timeline->requestClipsGroup(g2));
106         REQUIRE(timeline->requestClipsGroup(g3));
107         REQUIRE(timeline->checkConsistency());
108 
109         REQUIRE(timeline->requestTrackDeletion(tid1));
110         REQUIRE(timeline->getClipsCount() == 3);
111         REQUIRE(timeline->getTracksCount() == 2);
112         REQUIRE(timeline->checkConsistency());
113     }
114     binModel->clean();
115     pCore->m_projectManager = nullptr;
116 }
117 
118 TEST_CASE("Basic creation/deletion of a clip", "[ClipModel]")
119 {
120 
121     auto binModel = pCore->projectItemModel();
122     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
123     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
124     std::shared_ptr<TimelineItemModel> timeline = TimelineItemModel::construct(&profile_model, guideModel, undoStack);
125 
126     // Here we do some trickery to enable testing.
127     // We mock the project class so that the undoStack function returns our undoStack
128 
129     Mock<ProjectManager> pmMock;
130     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
131     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
132 
133     ProjectManager &mocked = pmMock.get();
134     pCore->m_projectManager = &mocked;
135 
136     QString binId = createProducer(profile_model, "red", binModel);
137     QString binId2 = createProducer(profile_model, "green", binModel);
138 
139     REQUIRE(timeline->getClipsCount() == 0);
140     int id1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
141     REQUIRE(timeline->getClipsCount() == 1);
142     REQUIRE(timeline->checkConsistency());
143 
144     int id2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly);
145     REQUIRE(timeline->getClipsCount() == 2);
146     REQUIRE(timeline->checkConsistency());
147 
148     int id3 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
149     REQUIRE(timeline->getClipsCount() == 3);
150     REQUIRE(timeline->checkConsistency());
151 
152     // Test deletion
153     REQUIRE(timeline->requestItemDeletion(id2));
154     REQUIRE(timeline->checkConsistency());
155     REQUIRE(timeline->getClipsCount() == 2);
156     REQUIRE(timeline->requestItemDeletion(id3));
157     REQUIRE(timeline->checkConsistency());
158     REQUIRE(timeline->getClipsCount() == 1);
159     REQUIRE(timeline->requestItemDeletion(id1));
160     REQUIRE(timeline->checkConsistency());
161     REQUIRE(timeline->getClipsCount() == 0);
162     binModel->clean();
163     pCore->m_projectManager = nullptr;
164 }
165 
166 TEST_CASE("Clip manipulation", "[ClipModel]")
167 {
168     auto binModel = pCore->projectItemModel();
169     binModel->clean();
170     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
171     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
172 
173     // Here we do some trickery to enable testing.
174     // We mock the project class so that the undoStack function returns our undoStack
175 
176     Mock<ProjectManager> pmMock;
177     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
178     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
179 
180     ProjectManager &mocked = pmMock.get();
181     pCore->m_projectManager = &mocked;
182 
183     // We also mock timeline object to spy few functions and mock others
184     TimelineItemModel tim(&profile_model, undoStack);
185     Mock<TimelineItemModel> timMock(tim);
__anond6fdc6cc0202(...) 186     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
187     TimelineItemModel::finishConstruct(timeline, guideModel);
188 
189     Fake(Method(timMock, adjustAssetRange));
190 
191     // This is faked to allow to count calls
192     Fake(Method(timMock, _beginInsertRows));
193     Fake(Method(timMock, _beginRemoveRows));
194     Fake(Method(timMock, _endInsertRows));
195     Fake(Method(timMock, _endRemoveRows));
196 
197     QString binId = createProducer(profile_model, "red", binModel);
198     QString binId2 = createProducer(profile_model, "blue", binModel);
199     QString binId3 = createProducer(profile_model, "green", binModel);
200     QString binId_unlimited = createProducer(profile_model, "green", binModel, 20, false);
201 
202     int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
203     int tid1, tid2, tid3;
204     REQUIRE(timeline->requestTrackInsertion(-1, tid1));
205     REQUIRE(timeline->requestTrackInsertion(-1, tid2));
206     REQUIRE(timeline->requestTrackInsertion(-1, tid3));
207     int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly);
208     int cid3 = ClipModel::construct(timeline, binId3, -1, PlaylistState::VideoOnly);
209     int cid4 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly);
210     int cid5 = ClipModel::construct(timeline, binId_unlimited, -1, PlaylistState::VideoOnly);
211 
212     RESET(timMock);
213 
214     SECTION("Endless clips can be resized both sides")
215     {
216 
217         REQUIRE(timeline->checkConsistency());
218         REQUIRE(timeline->getTrackClipsCount(tid1) == 0);
219         REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
220         int l = timeline->getClipPlaytime(cid5);
221 
222         // try resizing uninserted clip
223         REQUIRE(timeline->requestItemResize(cid5, l + 2, false) == l + 2);
224         REQUIRE(timeline->getClipPlaytime(cid5) == l + 2);
225         undoStack->undo();
226         REQUIRE(timeline->getClipPlaytime(cid5) == l);
227         undoStack->redo();
228         REQUIRE(timeline->getClipPlaytime(cid5) == l + 2);
229         undoStack->undo();
230         REQUIRE(timeline->getClipPlaytime(cid5) == l);
231 
232         REQUIRE(timeline->requestItemResize(cid5, 3 * l, true) == 3 * l);
233         REQUIRE(timeline->getClipPlaytime(cid5) == 3 * l);
234         undoStack->undo();
235         REQUIRE(timeline->getClipPlaytime(cid5) == l);
236         undoStack->redo();
237         REQUIRE(timeline->getClipPlaytime(cid5) == 3 * l);
238         undoStack->undo();
239         REQUIRE(timeline->getClipPlaytime(cid5) == l);
240 
241         // try resizing inserted clip
242         int pos = 10;
243         REQUIRE(timeline->requestClipMove(cid5, tid1, pos));
244 
__anond6fdc6cc0302(int s, int p) 245         auto state = [&](int s, int p) {
246             REQUIRE(timeline->checkConsistency());
247             REQUIRE(timeline->getClipTrackId(cid5) == tid1);
248             REQUIRE(timeline->getClipPosition(cid5) == p);
249             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
250             REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
251             REQUIRE(timeline->getClipPlaytime(cid5) == s);
252         };
253         state(l, pos);
254 
255         // too big
256         REQUIRE(timeline->requestItemResize(cid5, l + pos + 2, false) == -1);
257 
258         REQUIRE(timeline->requestItemResize(cid5, l + 2, false) == l + 2);
259         state(l + 2, pos - 2);
260         undoStack->undo();
261         state(l, pos);
262         undoStack->redo();
263         state(l + 2, pos - 2);
264         undoStack->undo();
265         state(l, pos);
266 
267         REQUIRE(timeline->requestItemResize(cid5, 3 * l, true) == 3 * l);
268         state(3 * l, pos);
269         undoStack->undo();
270         state(l, pos);
271         undoStack->redo();
272         state(3 * l, pos);
273         undoStack->undo();
274         state(l, pos);
275     }
276 
277     SECTION("Insert a clip in a track and change track")
278     {
279         REQUIRE(timeline->checkConsistency());
280         REQUIRE(timeline->getTrackClipsCount(tid1) == 0);
281         REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
282 
283         REQUIRE(timeline->getClipTrackId(cid1) == -1);
284         REQUIRE(timeline->getClipPosition(cid1) == -1);
285 
286         int pos = 10;
287         REQUIRE(timeline->requestClipMove(cid1, tid1, pos));
288         REQUIRE(timeline->checkConsistency());
289         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
290         REQUIRE(timeline->getClipPosition(cid1) == pos);
291         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
292         REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
293         // Check that the model was correctly notified
294         CHECK_INSERT(Once);
295 
296         pos = 1;
297         REQUIRE(timeline->requestClipMove(cid1, tid2, pos));
298         REQUIRE(timeline->checkConsistency());
299         REQUIRE(timeline->getClipTrackId(cid1) == tid2);
300         REQUIRE(timeline->getClipPosition(cid1) == pos);
301         REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
302         REQUIRE(timeline->getTrackClipsCount(tid1) == 0);
303         CHECK_MOVE(Once);
304 
305         // Check conflicts
306         int pos2 = binModel->getClipByBinID(binId)->frameDuration();
307         REQUIRE(timeline->requestClipMove(cid2, tid1, pos2));
308         REQUIRE(timeline->checkConsistency());
309         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
310         REQUIRE(timeline->getClipPosition(cid2) == pos2);
311         REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
312         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
313         CHECK_INSERT(Once);
314 
315         REQUIRE_FALSE(timeline->requestClipMove(cid1, tid1, pos2 + 2));
316         REQUIRE(timeline->checkConsistency());
317         REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
318         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
319         REQUIRE(timeline->getClipTrackId(cid1) == tid2);
320         REQUIRE(timeline->getClipPosition(cid1) == pos);
321         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
322         REQUIRE(timeline->getClipPosition(cid2) == pos2);
323         CHECK_MOVE(Once);
324 
325         REQUIRE_FALSE(timeline->requestClipMove(cid1, tid1, pos2 - 2));
326         REQUIRE(timeline->checkConsistency());
327         REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
328         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
329         REQUIRE(timeline->getClipTrackId(cid1) == tid2);
330         REQUIRE(timeline->getClipPosition(cid1) == pos);
331         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
332         REQUIRE(timeline->getClipPosition(cid2) == pos2);
333         CHECK_MOVE(Once);
334 
335         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
336         REQUIRE(timeline->checkConsistency());
337         REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
338         REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
339         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
340         REQUIRE(timeline->getClipPosition(cid1) == 0);
341         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
342         REQUIRE(timeline->getClipPosition(cid2) == pos2);
343         CHECK_MOVE(Once);
344     }
345 
346     int length = binModel->getClipByBinID(binId)->frameDuration();
347     SECTION("Insert consecutive clips")
348     {
349         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
350         REQUIRE(timeline->checkConsistency());
351         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
352         REQUIRE(timeline->getClipPosition(cid1) == 0);
353         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
354         CHECK_INSERT(Once);
355 
356         REQUIRE(timeline->requestClipMove(cid2, tid1, length));
357         REQUIRE(timeline->checkConsistency());
358         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
359         REQUIRE(timeline->getClipPosition(cid2) == length);
360         REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
361         CHECK_INSERT(Once);
362     }
363 
364     SECTION("Resize orphan clip")
365     {
366         REQUIRE(timeline->getClipPlaytime(cid2) == length);
367         REQUIRE(timeline->requestItemResize(cid2, 5, true) == 5);
368         REQUIRE(timeline->checkConsistency());
369         REQUIRE(binModel->getClipByBinID(binId)->frameDuration() == length);
370         auto inOut = std::pair<int, int>{0, 4};
371         REQUIRE(timeline->m_allClips[cid2]->getInOut() == inOut);
372         REQUIRE(timeline->getClipPlaytime(cid2) == 5);
373         REQUIRE(timeline->requestItemResize(cid2, 10, false) == -1);
374         REQUIRE(timeline->requestItemResize(cid2, length + 1, true) == -1);
375         REQUIRE(timeline->checkConsistency());
376         REQUIRE(timeline->getClipPlaytime(cid2) == 5);
377         REQUIRE(timeline->getClipPlaytime(cid2) == 5);
378         REQUIRE(timeline->requestItemResize(cid2, 2, false) == 2);
379         REQUIRE(timeline->checkConsistency());
380         inOut = std::pair<int, int>{3, 4};
381         REQUIRE(timeline->m_allClips[cid2]->getInOut() == inOut);
382         REQUIRE(timeline->getClipPlaytime(cid2) == 2);
383         REQUIRE(timeline->requestItemResize(cid2, length, true) == -1);
384         REQUIRE(timeline->checkConsistency());
385         REQUIRE(timeline->getClipPlaytime(cid2) == 2);
386         CAPTURE(timeline->m_allClips[cid2]->m_producer->get_in());
387         REQUIRE(timeline->requestItemResize(cid2, length - 2, true) == -1);
388         REQUIRE(timeline->checkConsistency());
389         REQUIRE(timeline->requestItemResize(cid2, length - 3, true) == length - 3);
390         REQUIRE(timeline->checkConsistency());
391         REQUIRE(timeline->getClipPlaytime(cid2) == length - 3);
392     }
393 
394     SECTION("Resize inserted clips")
395     {
396         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
397         REQUIRE(timeline->checkConsistency());
398         CHECK_INSERT(Once);
399 
400         REQUIRE(timeline->requestItemResize(cid1, 5, true) == 5);
401         REQUIRE(timeline->checkConsistency());
402         REQUIRE(timeline->getClipPlaytime(cid1) == 5);
403         REQUIRE(timeline->getClipPosition(cid1) == 0);
404         CHECK_RESIZE(Once);
405 
406         REQUIRE(timeline->requestClipMove(cid2, tid1, 5));
407         REQUIRE(timeline->checkConsistency());
408         REQUIRE(binModel->getClipByBinID(binId)->frameDuration() == length);
409         CHECK_INSERT(Once);
410 
411         REQUIRE(timeline->requestItemResize(cid1, 6, true) == -1);
412         REQUIRE(timeline->requestItemResize(cid1, 6, false) == -1);
413         REQUIRE(timeline->checkConsistency());
414         NO_OTHERS();
415 
416         REQUIRE(timeline->requestItemResize(cid2, length - 5, false) == length - 5);
417         REQUIRE(timeline->checkConsistency());
418         REQUIRE(timeline->getClipPosition(cid2) == 10);
419         CHECK_RESIZE(Once);
420 
421         REQUIRE(timeline->requestItemResize(cid1, 10, true) == 10);
422         REQUIRE(timeline->checkConsistency());
423         REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
424         CHECK_RESIZE(Once);
425     }
426 
427     SECTION("Change track of resized clips")
428     {
429         // // REQUIRE(timeline->allowClipMove(cid2, tid1, 5));
430         REQUIRE(timeline->requestClipMove(cid2, tid1, 5));
431         REQUIRE(timeline->checkConsistency());
432         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
433 
434         // // REQUIRE(timeline->allowClipMove(cid1, tid2, 10));
435         REQUIRE(timeline->requestClipMove(cid1, tid2, 10));
436         REQUIRE(timeline->checkConsistency());
437         REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
438 
439         REQUIRE(timeline->requestItemResize(cid1, 5, false) == 5);
440         REQUIRE(timeline->checkConsistency());
441 
442         // // REQUIRE(timeline->allowClipMove(cid1, tid1, 0));
443         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
444         REQUIRE(timeline->checkConsistency());
445         REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
446         REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
447     }
448 
449     SECTION("Clip Move")
450     {
451         REQUIRE(timeline->requestClipMove(cid2, tid1, 5));
452         REQUIRE(timeline->checkConsistency());
453         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
454         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
455         REQUIRE(timeline->getClipPosition(cid2) == 5);
456 
457         REQUIRE(timeline->requestClipMove(cid1, tid1, 5 + length));
__anond6fdc6cc0402() 458         auto state = [&]() {
459             REQUIRE(timeline->checkConsistency());
460             REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
461             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
462             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
463             REQUIRE(timeline->getClipPosition(cid1) == 5 + length);
464             REQUIRE(timeline->getClipPosition(cid2) == 5);
465         };
466         state();
467 
468         REQUIRE_FALSE(timeline->requestClipMove(cid1, tid1, 3 + length));
469         state();
470 
471         REQUIRE_FALSE(timeline->requestClipMove(cid1, tid1, 0));
472         state();
473 
474         REQUIRE(timeline->requestClipMove(cid2, tid1, 0));
__anond6fdc6cc0502() 475         auto state2 = [&]() {
476             REQUIRE(timeline->checkConsistency());
477             REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
478             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
479             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
480             REQUIRE(timeline->getClipPosition(cid1) == 5 + length);
481             REQUIRE(timeline->getClipPosition(cid2) == 0);
482         };
483         state2();
484 
485         REQUIRE_FALSE(timeline->requestClipMove(cid1, tid1, 0));
486         state2();
487 
488         REQUIRE_FALSE(timeline->requestClipMove(cid1, tid1, length - 5));
489         state2();
490 
491         REQUIRE(timeline->requestClipMove(cid1, tid1, length));
492         REQUIRE(timeline->checkConsistency());
493         REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
494         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
495         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
496         REQUIRE(timeline->getClipPosition(cid1) == length);
497         REQUIRE(timeline->getClipPosition(cid2) == 0);
498 
499         REQUIRE(timeline->requestItemResize(cid2, length - 5, true) == length - 5);
500         REQUIRE(timeline->checkConsistency());
501         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
502         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
503         REQUIRE(timeline->getClipPosition(cid1) == length);
504         REQUIRE(timeline->getClipPosition(cid2) == 0);
505 
506         REQUIRE(timeline->requestClipMove(cid1, tid1, length - 5));
507         REQUIRE(timeline->checkConsistency());
508         REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
509         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
510         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
511         REQUIRE(timeline->getClipPosition(cid1) == length - 5);
512         REQUIRE(timeline->getClipPosition(cid2) == 0);
513 
514         REQUIRE(timeline->requestItemResize(cid2, length - 10, false) == length - 10);
515         REQUIRE(timeline->checkConsistency());
516         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
517         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
518         REQUIRE(timeline->getClipPosition(cid1) == length - 5);
519         REQUIRE(timeline->getClipPosition(cid2) == 5);
520 
521         REQUIRE_FALSE(timeline->requestClipMove(cid1, tid1, 0));
522         REQUIRE(timeline->checkConsistency());
523         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
524         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
525         REQUIRE(timeline->getClipPosition(cid1) == length - 5);
526         REQUIRE(timeline->getClipPosition(cid2) == 5);
527 
528         REQUIRE(timeline->requestClipMove(cid2, tid1, 0));
529         REQUIRE(timeline->checkConsistency());
530         REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
531         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
532         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
533         REQUIRE(timeline->getClipPosition(cid1) == length - 5);
534         REQUIRE(timeline->getClipPosition(cid2) == 0);
535     }
536 
537     SECTION("Move and resize")
538     {
539         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
540         REQUIRE(timeline->requestItemResize(cid1, length - 2, false) == length - 2);
541         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
__anond6fdc6cc0602() 542         auto state = [&]() {
543             REQUIRE(timeline->checkConsistency());
544             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
545             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
546             REQUIRE(timeline->getClipPosition(cid1) == 0);
547             REQUIRE(timeline->getClipPlaytime(cid1) == length - 2);
548         };
549         state();
550 
551         // try to resize past the left end
552         REQUIRE(timeline->requestItemResize(cid1, length, false) == -1);
553         state();
554 
555         REQUIRE(timeline->requestItemResize(cid1, length - 4, true) == length - 4);
556         REQUIRE(timeline->requestClipMove(cid2, tid1, length - 4 + 1));
557         REQUIRE(timeline->requestItemResize(cid2, length - 2, false) == length - 2);
558         REQUIRE(timeline->requestClipMove(cid2, tid1, length - 4 + 1));
__anond6fdc6cc0702() 559         auto state2 = [&]() {
560             REQUIRE(timeline->checkConsistency());
561             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
562             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
563             REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
564             REQUIRE(timeline->getClipPosition(cid1) == 0);
565             REQUIRE(timeline->getClipPlaytime(cid1) == length - 4);
566             REQUIRE(timeline->getClipPosition(cid2) == length - 4 + 1);
567             REQUIRE(timeline->getClipPlaytime(cid2) == length - 2);
568         };
569         state2();
570 
571         // the gap between the two clips is 1 frame, we try to resize them by 2 frames
572         // It will only be resized by one frame
573         REQUIRE(timeline->requestItemResize(cid1, length - 2, true) == length - 3);
574         undoStack->undo();
575         state2();
576         // Resize a clip over another clip will resize it to fill the gap
577         REQUIRE(timeline->requestItemResize(cid2, length, false) == length - 1);
578         undoStack->undo();
579         state2();
580 
581         REQUIRE(timeline->requestClipMove(cid2, tid1, length - 4));
__anond6fdc6cc0802() 582         auto state3 = [&]() {
583             REQUIRE(timeline->checkConsistency());
584             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
585             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
586             REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
587             REQUIRE(timeline->getClipPosition(cid1) == 0);
588             REQUIRE(timeline->getClipPlaytime(cid1) == length - 4);
589             REQUIRE(timeline->getClipPosition(cid2) == length - 4);
590             REQUIRE(timeline->getClipPlaytime(cid2) == length - 2);
591         };
592         state3();
593 
594         // Now the gap is 0 frames, the resize should still fail
595         REQUIRE(timeline->requestItemResize(cid1, length - 2, true) == -1);
596         state3();
597         REQUIRE(timeline->requestItemResize(cid2, length, false) == -1);
598         state3();
599 
600         // We move cid1 out of the way
601         REQUIRE(timeline->requestClipMove(cid1, tid2, 0));
602         // now resize should work
603         REQUIRE(timeline->requestItemResize(cid1, length - 2, true) == length - 2);
604         REQUIRE(timeline->requestItemResize(cid2, length, false) == length);
605         REQUIRE(timeline->checkConsistency());
606     }
607 
608     SECTION("Group and selection")
609     {
610         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
611         REQUIRE(timeline->requestClipMove(cid2, tid1, length + 3));
612         REQUIRE(timeline->requestClipMove(cid3, tid1, 2 * length + 5));
__anond6fdc6cc0902() 613         auto pos_state = [&]() {
614             REQUIRE(timeline->checkConsistency());
615             REQUIRE(timeline->getTrackClipsCount(tid1) == 3);
616             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
617             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
618             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
619             REQUIRE(timeline->getClipPosition(cid1) == 0);
620             REQUIRE(timeline->getClipPosition(cid2) == length + 3);
621             REQUIRE(timeline->getClipPosition(cid3) == 2 * length + 5);
622         };
__anond6fdc6cc0a02() 623         auto state0 = [&]() {
624             pos_state();
625             REQUIRE_FALSE(timeline->m_groups->isInGroup(cid1));
626             REQUIRE_FALSE(timeline->m_groups->isInGroup(cid2));
627             REQUIRE_FALSE(timeline->m_groups->isInGroup(cid3));
628         };
629         state0();
630 
631         REQUIRE(timeline->requestClipsGroup({cid1, cid2}));
__anond6fdc6cc0b02() 632         auto state = [&]() {
633             pos_state();
634             REQUIRE_FALSE(timeline->m_groups->isInGroup(cid3));
635             REQUIRE(timeline->m_groups->isInGroup(cid1));
636             int gid = timeline->m_groups->getRootId(cid1);
637             REQUIRE(timeline->m_groups->getLeaves(gid) == std::unordered_set<int>{cid1, cid2});
638         };
639         state();
640 
641         // undo/redo should work fine
642         undoStack->undo();
643         state0();
644         undoStack->redo();
645         state();
646 
647         // Tricky case, we do a non-trivial selection before undoing
648         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
649         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3});
650         undoStack->undo();
651         state0();
652         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
653         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid3});
654         undoStack->redo();
655         state();
656 
657         // same thing, but when ungrouping manually
658         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
659         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3});
660         REQUIRE(timeline->requestClipUngroup(cid1));
661         state0();
662 
663         // normal undo/redo
664         undoStack->undo();
665         state();
666         undoStack->redo();
667         state0();
668 
669         // undo/redo mixed with selections
670         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
671         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid3});
672         undoStack->undo();
673         state();
674         REQUIRE(timeline->requestSetSelection({cid1, cid3}));
675         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid1, cid2, cid3});
676         undoStack->redo();
677         state0();
678     }
679 
680     SECTION("Group move")
681     {
682         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
683         REQUIRE(timeline->requestClipMove(cid2, tid1, length + 3));
684         REQUIRE(timeline->requestClipMove(cid3, tid1, 2 * length + 5));
685         REQUIRE(timeline->requestClipMove(cid4, tid2, 4));
686 
687         REQUIRE(timeline->checkConsistency());
688         REQUIRE(timeline->getTrackClipsCount(tid1) == 3);
689         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
690         REQUIRE(timeline->getClipTrackId(cid2) == tid1);
691         REQUIRE(timeline->getClipTrackId(cid3) == tid1);
692         REQUIRE(timeline->getClipTrackId(cid4) == tid2);
693         REQUIRE(timeline->getClipPosition(cid1) == 0);
694         REQUIRE(timeline->getClipPosition(cid2) == length + 3);
695         REQUIRE(timeline->getClipPosition(cid3) == 2 * length + 5);
696         REQUIRE(timeline->getClipPosition(cid4) == 4);
697 
698         // check that move is possible without groups
699         REQUIRE(timeline->requestClipMove(cid3, tid1, 2 * length + 3));
700         REQUIRE(timeline->checkConsistency());
701         undoStack->undo();
702         REQUIRE(timeline->checkConsistency());
703         // check that move is possible without groups
704         REQUIRE(timeline->requestClipMove(cid4, tid2, 9));
705         REQUIRE(timeline->checkConsistency());
706         undoStack->undo();
707         REQUIRE(timeline->checkConsistency());
708 
__anond6fdc6cc0c02() 709         auto state = [&]() {
710             REQUIRE(timeline->checkConsistency());
711             REQUIRE(timeline->getTrackClipsCount(tid1) == 3);
712             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
713             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
714             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
715             REQUIRE(timeline->getClipTrackId(cid4) == tid2);
716             REQUIRE(timeline->getClipPosition(cid1) == 0);
717             REQUIRE(timeline->getClipPosition(cid2) == length + 3);
718             REQUIRE(timeline->getClipPosition(cid3) == 2 * length + 5);
719             REQUIRE(timeline->getClipPosition(cid4) == 4);
720         };
721         state();
722 
723         // grouping
724         REQUIRE(timeline->requestClipsGroup({cid1, cid3}));
725         REQUIRE(timeline->requestClipsGroup({cid1, cid4}));
726 
727         // move left is now forbidden, because clip1 is at position 0
728         REQUIRE_FALSE(timeline->requestClipMove(cid3, tid1, 2 * length + 3));
729         state();
730 
731         // this move is impossible, because clip1 runs into clip2
732         REQUIRE_FALSE(timeline->requestClipMove(cid4, tid2, 9));
733         state();
734 
735         // this move is possible
736         REQUIRE(timeline->requestClipMove(cid3, tid1, 2 * length + 8));
__anond6fdc6cc0d02() 737         auto state1 = [&]() {
738             REQUIRE(timeline->checkConsistency());
739             REQUIRE(timeline->getTrackClipsCount(tid1) == 3);
740             REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
741             REQUIRE(timeline->getTrackClipsCount(tid3) == 0);
742             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
743             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
744             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
745             REQUIRE(timeline->getClipTrackId(cid4) == tid2);
746             REQUIRE(timeline->getClipPosition(cid1) == 3);
747             REQUIRE(timeline->getClipPosition(cid2) == length + 3);
748             REQUIRE(timeline->getClipPosition(cid3) == 2 * length + 8);
749             REQUIRE(timeline->getClipPosition(cid4) == 7);
750         };
751         state1();
752 
753         // this move is possible
754         REQUIRE(timeline->requestClipMove(cid1, tid2, 8));
__anond6fdc6cc0e02() 755         auto state2 = [&]() {
756             REQUIRE(timeline->checkConsistency());
757             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
758             REQUIRE(timeline->getTrackClipsCount(tid2) == 2);
759             REQUIRE(timeline->getTrackClipsCount(tid3) == 1);
760             REQUIRE(timeline->getClipTrackId(cid1) == tid2);
761             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
762             REQUIRE(timeline->getClipTrackId(cid3) == tid2);
763             REQUIRE(timeline->getClipTrackId(cid4) == tid3);
764             REQUIRE(timeline->getClipPosition(cid1) == 8);
765             REQUIRE(timeline->getClipPosition(cid2) == length + 3);
766             REQUIRE(timeline->getClipPosition(cid3) == 2 * length + 5 + 8);
767             REQUIRE(timeline->getClipPosition(cid4) == 4 + 8);
768         };
769         state2();
770 
771         undoStack->undo();
772         state1();
773 
774         undoStack->redo();
775         state2();
776 
777         REQUIRE(timeline->requestClipMove(cid1, tid1, 3));
778         state1();
779     }
780 
781     SECTION("Group move consecutive clips")
782     {
783         REQUIRE(timeline->requestClipMove(cid1, tid1, 7));
784         REQUIRE(timeline->requestClipMove(cid2, tid1, 7 + length));
785         REQUIRE(timeline->requestClipMove(cid3, tid1, 7 + 2 * length));
786         REQUIRE(timeline->requestClipMove(cid4, tid1, 7 + 3 * length));
787         REQUIRE(timeline->requestClipsGroup({cid1, cid2, cid3, cid4}));
788 
__anond6fdc6cc0f02(int tid, int start) 789         auto state = [&](int tid, int start) {
790             REQUIRE(timeline->checkConsistency());
791             REQUIRE(timeline->getTrackClipsCount(tid) == 4);
792             int i = 0;
793             for (int cid : std::vector<int>({cid1, cid2, cid3, cid4})) {
794                 REQUIRE(timeline->getClipTrackId(cid) == tid);
795                 REQUIRE(timeline->getClipPosition(cid) == start + i * length);
796                 REQUIRE(timeline->getClipPlaytime(cid) == length);
797                 i++;
798             }
799         };
800         state(tid1, 7);
801 
__anond6fdc6cc1002(int target, int tid, int oldTid) 802         auto check_undo = [&](int target, int tid, int oldTid) {
803             state(tid, target);
804             undoStack->undo();
805             state(oldTid, 7);
806             undoStack->redo();
807             state(tid, target);
808             undoStack->undo();
809             state(oldTid, 7);
810         };
811 
812         REQUIRE(timeline->requestClipMove(cid1, tid1, 6));
813         qDebug() << "state1";
814         state(tid1, 6);
815         undoStack->undo();
816         state(tid1, 7);
817         undoStack->redo();
818         state(tid1, 6);
819         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
820         qDebug() << "state2";
821         state(tid1, 0);
822         undoStack->undo();
823         state(tid1, 6);
824         undoStack->redo();
825         state(tid1, 0);
826         undoStack->undo();
827         state(tid1, 6);
828         undoStack->undo();
829         state(tid1, 7);
830 
831         REQUIRE(timeline->requestClipMove(cid3, tid1, 1 + 2 * length));
832         qDebug() << "state3";
833         check_undo(1, tid1, tid1);
834 
835         REQUIRE(timeline->requestClipMove(cid4, tid1, 4 + 3 * length));
836         qDebug() << "state4";
837         check_undo(4, tid1, tid1);
838 
839         REQUIRE(timeline->requestClipMove(cid4, tid1, 11 + 3 * length));
840         qDebug() << "state5";
841         check_undo(11, tid1, tid1);
842 
843         REQUIRE(timeline->requestClipMove(cid2, tid1, 13 + length));
844         qDebug() << "state6";
845         check_undo(13, tid1, tid1);
846 
847         REQUIRE(timeline->requestClipMove(cid1, tid1, 20));
848         qDebug() << "state7";
849         check_undo(20, tid1, tid1);
850 
851         REQUIRE(timeline->requestClipMove(cid4, tid1, 7 + 4 * length));
852         qDebug() << "state8";
853         check_undo(length + 7, tid1, tid1);
854 
855         REQUIRE(timeline->requestClipMove(cid2, tid1, 7 + 2 * length));
856         qDebug() << "state9";
857         check_undo(length + 7, tid1, tid1);
858 
859         REQUIRE(timeline->requestClipMove(cid1, tid1, 7 + length));
860         qDebug() << "state10";
861         check_undo(length + 7, tid1, tid1);
862 
863         REQUIRE(timeline->requestClipMove(cid2, tid2, 8 + length));
864         qDebug() << "state11";
865         check_undo(8, tid2, tid1);
866     }
867 
868     SECTION("Group move to unavailable track")
869     {
870         REQUIRE(timeline->requestClipMove(cid1, tid1, 10));
871         REQUIRE(timeline->requestClipMove(cid2, tid2, 12));
872         REQUIRE(timeline->requestClipsGroup({cid1, cid2}));
__anond6fdc6cc1102() 873         auto state = [&]() {
874             REQUIRE(timeline->checkConsistency());
875             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
876             REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
877             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
878             REQUIRE(timeline->getClipTrackId(cid2) == tid2);
879         };
880         state();
881 
882         // Moving clips on an unavailable track will do a same track move
883         REQUIRE(timeline->requestClipMove(cid2, tid1, 10));
884         REQUIRE(timeline->getClipPosition(cid1) == 8);
885         REQUIRE(timeline->getClipPosition(cid2) == 10);
886         state();
887         REQUIRE(timeline->requestClipMove(cid2, tid1, 100));
888         REQUIRE(timeline->getClipPosition(cid1) == 98);
889         REQUIRE(timeline->getClipPosition(cid2) == 100);
890         state();
891         REQUIRE(timeline->requestClipMove(cid1, tid3, 100));
892         REQUIRE(timeline->getClipPosition(cid1) == 100);
893         REQUIRE(timeline->getClipPosition(cid2) == 102);
894         state();
895     }
896 
897     SECTION("Group move with non-consecutive track ids")
898     {
899         int tid5 = TrackModel::construct(timeline);
900         int cid6 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
901         Q_UNUSED(cid6);
902         int tid6 = TrackModel::construct(timeline);
903         REQUIRE(tid5 + 1 != tid6);
904 
905         REQUIRE(timeline->requestClipMove(cid1, tid5, 10));
906         REQUIRE(timeline->requestClipMove(cid2, tid5, length + 10));
907         REQUIRE(timeline->requestClipsGroup({cid1, cid2}));
__anond6fdc6cc1202(int t) 908         auto state = [&](int t) {
909             REQUIRE(timeline->checkConsistency());
910             REQUIRE(timeline->getTrackClipsCount(t) == 2);
911             REQUIRE(timeline->getClipTrackId(cid1) == t);
912             REQUIRE(timeline->getClipTrackId(cid2) == t);
913             REQUIRE(timeline->getClipPosition(cid1) == 10);
914             REQUIRE(timeline->getClipPosition(cid2) == 10 + length);
915         };
916         state(tid5);
917         REQUIRE(timeline->requestClipMove(cid1, tid6, 10));
918         state(tid6);
919     }
920 
921     SECTION("Creation and movement of AV groups")
922     {
923         int tid6b = TrackModel::construct(timeline, -1, -1, QString(), true);
924         int tid6 = TrackModel::construct(timeline, -1, -1, QString(), true);
925         int tid5 = TrackModel::construct(timeline);
926         int tid5b = TrackModel::construct(timeline);
__anond6fdc6cc1302() 927         auto state0 = [&]() {
928             REQUIRE(timeline->checkConsistency());
929             REQUIRE(timeline->getTrackClipsCount(tid5) == 0);
930             REQUIRE(timeline->getTrackClipsCount(tid6) == 0);
931         };
932         state0();
933         QString binId3 = createProducerWithSound(profile_model, binModel);
934 
935         int cid6 = -1;
936         // Setup insert stream data
937         QMap <int, QString>audioInfo;
938         audioInfo.insert(1,QStringLiteral("stream1"));
939         timeline->m_binAudioTargets = audioInfo;
940         REQUIRE(timeline->requestClipInsertion(binId3, tid5, 3, cid6, true, true, false));
941         int cid7 = timeline->m_groups->getSplitPartner(cid6);
942 
__anond6fdc6cc1402() 943         auto check_group = [&]() {
944             // we check that the av group was correctly created
945             REQUIRE(timeline->getGroupElements(cid6) == std::unordered_set<int>({cid6, cid7}));
946             int g1 = timeline->m_groups->getDirectAncestor(cid6);
947             REQUIRE(timeline->m_groups->getDirectChildren(g1) == std::unordered_set<int>({cid6, cid7}));
948             REQUIRE(timeline->m_groups->getType(g1) == GroupType::AVSplit);
949         };
950 
__anond6fdc6cc1502(int pos) 951         auto state = [&](int pos) {
952             REQUIRE(timeline->checkConsistency());
953             REQUIRE(timeline->getTrackClipsCount(tid5) == 1);
954             REQUIRE(timeline->getTrackClipsCount(tid6) == 1);
955             REQUIRE(timeline->getClipTrackId(cid6) == tid5);
956             REQUIRE(timeline->getClipTrackId(cid7) == tid6);
957             REQUIRE(timeline->getClipPosition(cid6) == pos);
958             REQUIRE(timeline->getClipPosition(cid7) == pos);
959             REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::VideoOnly);
960             REQUIRE(timeline->getClipPtr(cid7)->clipState() == PlaylistState::AudioOnly);
961             check_group();
962         };
963         state(3);
964         undoStack->undo();
965         state0();
966         undoStack->redo();
967         state(3);
968 
969         // test deletion + undo after selection
970         REQUIRE(timeline->requestSetSelection({cid6}));
971         REQUIRE(timeline->getCurrentSelection() == std::unordered_set<int>{cid6, cid7});
972 
973         REQUIRE(timeline->requestItemDeletion(cid6, true));
974         state0();
975         undoStack->undo();
976         state(3);
977         undoStack->redo();
978         state0();
979         undoStack->undo();
980         state(3);
981 
982         // simple translation on the right
983         REQUIRE(timeline->requestClipMove(cid6, tid5, 10, true, true, true));
984 
985         state(10);
986         undoStack->undo();
987         state(3);
988         undoStack->redo();
989         state(10);
990 
991         // simple translation on the left, moving the audio clip this time
992         REQUIRE(timeline->requestClipMove(cid7, tid6, 1, true, true, true));
993         state(1);
994         undoStack->undo();
995         state(10);
996         undoStack->redo();
997         state(1);
998 
999         // change track, moving video
1000         REQUIRE(timeline->requestClipMove(cid6, tid5b, 7, true, true, true));
__anond6fdc6cc1602(int pos) 1001         auto state2 = [&](int pos) {
1002             REQUIRE(timeline->checkConsistency());
1003             REQUIRE(timeline->getTrackClipsCount(tid5b) == 1);
1004             REQUIRE(timeline->getTrackClipsCount(tid6b) == 1);
1005             REQUIRE(timeline->getClipTrackId(cid6) == tid5b);
1006             REQUIRE(timeline->getClipTrackId(cid7) == tid6b);
1007             REQUIRE(timeline->getClipPosition(cid6) == pos);
1008             REQUIRE(timeline->getClipPosition(cid7) == pos);
1009             REQUIRE(timeline->getClipPtr(cid6)->clipState() == PlaylistState::VideoOnly);
1010             REQUIRE(timeline->getClipPtr(cid7)->clipState() == PlaylistState::AudioOnly);
1011             check_group();
1012         };
1013         state2(7);
1014         undoStack->undo();
1015         state(1);
1016         undoStack->redo();
1017         state2(7);
1018 
1019         // change track, moving audio
1020         REQUIRE(timeline->requestClipMove(cid7, tid6b, 2, true, true, true));
1021         state2(2);
1022         undoStack->undo();
1023         state2(7);
1024         undoStack->redo();
1025         state2(2);
1026 
1027         undoStack->undo();
1028         undoStack->undo();
1029         state(1);
1030     }
1031 
1032     SECTION("Clip clone")
1033     {
1034         int cid6 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1035         int l = timeline->getClipPlaytime(cid6);
1036         REQUIRE(timeline->requestItemResize(cid6, l - 3, true, true, -1) == l - 3);
1037         REQUIRE(timeline->requestItemResize(cid6, l - 7, false, true, -1) == l - 7);
1038 
1039         int newId;
1040 
__anond6fdc6cc1702() 1041         std::function<bool(void)> undo = []() { return true; };
__anond6fdc6cc1802() 1042         std::function<bool(void)> redo = []() { return true; };
1043         REQUIRE(TimelineFunctions::cloneClip(timeline, cid6, newId, PlaylistState::VideoOnly, undo, redo));
1044         REQUIRE(timeline->m_allClips[cid6]->binId() == timeline->m_allClips[newId]->binId());
1045         // TODO check effects
1046     }
1047     binModel->clean();
1048     pCore->m_projectManager = nullptr;
1049 }
1050 
1051 TEST_CASE("Check id unicity", "[ClipModel]")
1052 {
1053     auto binModel = pCore->projectItemModel();
1054     binModel->clean();
1055     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
1056     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
1057 
1058     // Here we do some trickery to enable testing.
1059     // We mock the project class so that the undoStack function returns our undoStack
1060 
1061     Mock<ProjectManager> pmMock;
1062     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
1063     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
1064 
1065     ProjectManager &mocked = pmMock.get();
1066     pCore->m_projectManager = &mocked;
1067 
1068     // We also mock timeline object to spy few functions and mock others
1069     TimelineItemModel tim(&profile_model, undoStack);
1070     Mock<TimelineItemModel> timMock(tim);
__anond6fdc6cc1902(...) 1071     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
1072     TimelineItemModel::finishConstruct(timeline, guideModel);
1073 
1074     RESET(timMock);
1075 
1076     QString binId = createProducer(profile_model, "red", binModel);
1077 
1078     std::vector<int> track_ids;
1079     std::unordered_set<int> all_ids;
1080 
1081     std::bernoulli_distribution coin(0.5);
1082 
1083     const int nbr = 20;
1084 
1085     for (int i = 0; i < nbr; i++) {
1086         if (coin(g)) {
1087             int tid = TrackModel::construct(timeline);
1088             REQUIRE(all_ids.count(tid) == 0);
1089             all_ids.insert(tid);
1090             track_ids.push_back(tid);
1091             REQUIRE(timeline->getTracksCount() == track_ids.size());
1092         } else {
1093             int cid = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1094             REQUIRE(all_ids.count(cid) == 0);
1095             all_ids.insert(cid);
1096             REQUIRE(timeline->getClipsCount() == all_ids.size() - track_ids.size());
1097         }
1098     }
1099 
1100     REQUIRE(timeline->checkConsistency());
1101     REQUIRE(all_ids.size() == nbr);
1102     REQUIRE(all_ids.size() != track_ids.size());
1103     binModel->clean();
1104     pCore->m_projectManager = nullptr;
1105 }
1106 
1107 TEST_CASE("Undo and Redo", "[ClipModel]")
1108 {
1109     auto binModel = pCore->projectItemModel();
1110     binModel->clean();
1111     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
1112     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
1113 
1114     // Here we do some trickery to enable testing.
1115     // We mock the project class so that the undoStack function returns our undoStack
1116 
1117     Mock<ProjectManager> pmMock;
1118     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
1119     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
1120 
1121     ProjectManager &mocked = pmMock.get();
1122     pCore->m_projectManager = &mocked;
1123 
1124     // We also mock timeline object to spy few functions and mock others
1125     TimelineItemModel tim(&profile_model, undoStack);
1126     Mock<TimelineItemModel> timMock(tim);
__anond6fdc6cc1a02(...) 1127     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
1128     TimelineItemModel::finishConstruct(timeline, guideModel);
1129 
1130     RESET(timMock);
1131 
1132     QString binId = createProducer(profile_model, "red", binModel);
1133     QString binId2 = createProducer(profile_model, "blue", binModel);
1134 
1135     int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1136     int tid1 = TrackModel::construct(timeline);
1137     int tid2 = TrackModel::construct(timeline);
1138     int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly);
1139 
1140     int length = 20;
1141     int nclips = timeline->m_allClips.size();
1142 
1143     SECTION("requestCreateClip")
1144     {
1145         // an invalid clip id shouldn't get created
1146         {
1147             int temp;
__anond6fdc6cc1b02() 1148             Fun undo = []() { return true; };
__anond6fdc6cc1c02() 1149             Fun redo = []() { return true; };
1150             REQUIRE_FALSE(timeline->requestClipCreation("impossible bin id", temp, PlaylistState::VideoOnly, 1, 1., false, undo, redo));
1151         }
1152 
__anond6fdc6cc1d02() 1153         auto state0 = [&]() {
1154             REQUIRE(timeline->checkConsistency());
1155             REQUIRE(timeline->m_allClips.size() == nclips);
1156         };
1157         state0();
1158 
1159         QString binId3 = createProducer(profile_model, "green", binModel);
1160         int cid3;
1161         {
__anond6fdc6cc1e02() 1162             Fun undo = []() { return true; };
__anond6fdc6cc1f02() 1163             Fun redo = []() { return true; };
1164             REQUIRE(timeline->requestClipCreation(binId3, cid3, PlaylistState::VideoOnly, 1, 1., false, undo, redo));
1165             pCore->pushUndo(undo, redo, QString());
1166         }
1167 
__anond6fdc6cc2002() 1168         auto state1 = [&]() {
1169             REQUIRE(timeline->checkConsistency());
1170             REQUIRE(timeline->m_allClips.size() == nclips + 1);
1171             REQUIRE(timeline->getClipPlaytime(cid3) == length);
1172             REQUIRE(timeline->getClipTrackId(cid3) == -1);
1173         };
1174         state1();
1175 
1176         QString binId4 = binId3 + "/1/10";
1177         int cid4;
1178         {
__anond6fdc6cc2102() 1179             Fun undo = []() { return true; };
__anond6fdc6cc2202() 1180             Fun redo = []() { return true; };
1181             REQUIRE(timeline->requestClipCreation(binId4, cid4, PlaylistState::VideoOnly, 1, 1., false, undo, redo));
1182             pCore->pushUndo(undo, redo, QString());
1183         }
1184 
__anond6fdc6cc2302() 1185         auto state2 = [&]() {
1186             REQUIRE(timeline->checkConsistency());
1187             REQUIRE(timeline->m_allClips.size() == nclips + 2);
1188             REQUIRE(timeline->getClipPlaytime(cid4) == 10);
1189             REQUIRE(timeline->getClipTrackId(cid4) == -1);
1190             auto inOut = std::pair<int, int>({1, 10});
1191             REQUIRE(timeline->m_allClips.at(cid4)->getInOut() == inOut);
1192             REQUIRE(timeline->getClipPlaytime(cid3) == length);
1193             REQUIRE(timeline->getClipTrackId(cid3) == -1);
1194         };
1195         state2();
1196         undoStack->undo();
1197         state1();
1198         undoStack->undo();
1199         state0();
1200         undoStack->redo();
1201         state1();
1202         undoStack->redo();
1203         state2();
1204     }
1205 
1206     SECTION("requestInsertClip")
1207     {
__anond6fdc6cc2402() 1208         auto state0 = [&]() {
1209             REQUIRE(timeline->checkConsistency());
1210             REQUIRE(timeline->m_allClips.size() == nclips);
1211         };
1212         state0();
1213 
1214         QString binId3 = createProducer(profile_model, "green", binModel);
1215         int cid3;
1216         REQUIRE(timeline->requestClipInsertion(binId3, tid1, 12, cid3, true));
1217 
__anond6fdc6cc2502() 1218         auto state1 = [&]() {
1219             REQUIRE(timeline->checkConsistency());
1220             REQUIRE(timeline->m_allClips.size() == nclips + 1);
1221             REQUIRE(timeline->getClipPlaytime(cid3) == length);
1222             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
1223             REQUIRE(timeline->getClipPosition(cid3) == 12);
1224         };
1225         state1();
1226 
1227         QString binId4 = binId3 + "/1/10";
1228         int cid4;
1229         REQUIRE(timeline->requestClipInsertion(binId4, tid2, 17, cid4, true));
1230 
__anond6fdc6cc2602() 1231         auto state2 = [&]() {
1232             REQUIRE(timeline->checkConsistency());
1233             REQUIRE(timeline->m_allClips.size() == nclips + 2);
1234             REQUIRE(timeline->getClipPlaytime(cid4) == 10);
1235             REQUIRE(timeline->getClipTrackId(cid4) == tid2);
1236             REQUIRE(timeline->getClipPosition(cid4) == 17);
1237             auto inOut = std::pair<int, int>({1, 10});
1238             REQUIRE(timeline->m_allClips.at(cid4)->getInOut() == inOut);
1239             REQUIRE(timeline->getClipPlaytime(cid3) == length);
1240             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
1241             REQUIRE(timeline->getClipPosition(cid3) == 12);
1242         };
1243         state2();
1244         undoStack->undo();
1245         state1();
1246         undoStack->undo();
1247         state0();
1248         undoStack->redo();
1249         state1();
1250         undoStack->redo();
1251         state2();
1252     }
1253     int init_index = undoStack->index();
1254 
1255     SECTION("Basic move undo")
1256     {
1257         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1258         REQUIRE(timeline->checkConsistency());
1259         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1260         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1261         REQUIRE(timeline->getClipPosition(cid1) == 5);
1262         REQUIRE(undoStack->index() == init_index + 1);
1263         CHECK_INSERT(Once);
1264 
1265         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
1266         REQUIRE(timeline->checkConsistency());
1267         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1268         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1269         REQUIRE(timeline->getClipPosition(cid1) == 0);
1270         REQUIRE(undoStack->index() == init_index + 2);
1271         // Move on same track does not trigger insert/remove row
1272         CHECK_MOVE(0);
1273 
1274         undoStack->undo();
1275         REQUIRE(timeline->checkConsistency());
1276         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1277         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1278         REQUIRE(timeline->getClipPosition(cid1) == 5);
1279         REQUIRE(undoStack->index() == init_index + 1);
1280         CHECK_MOVE(0);
1281 
1282         undoStack->redo();
1283         REQUIRE(timeline->checkConsistency());
1284         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1285         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1286         REQUIRE(timeline->getClipPosition(cid1) == 0);
1287         REQUIRE(undoStack->index() == init_index + 2);
1288         CHECK_MOVE(0);
1289 
1290         undoStack->undo();
1291         REQUIRE(timeline->checkConsistency());
1292         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1293         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1294         REQUIRE(timeline->getClipPosition(cid1) == 5);
1295         REQUIRE(undoStack->index() == init_index + 1);
1296         CHECK_MOVE(0);
1297 
1298         REQUIRE(timeline->requestClipMove(cid1, tid1, 2 * length));
1299         REQUIRE(timeline->checkConsistency());
1300         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1301         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1302         REQUIRE(timeline->getClipPosition(cid1) == 2 * length);
1303         REQUIRE(undoStack->index() == init_index + 2);
1304         CHECK_MOVE(0);
1305 
1306         undoStack->undo();
1307         REQUIRE(timeline->checkConsistency());
1308         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1309         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1310         REQUIRE(timeline->getClipPosition(cid1) == 5);
1311         REQUIRE(undoStack->index() == init_index + 1);
1312         CHECK_MOVE(0);
1313 
1314         undoStack->redo();
1315         REQUIRE(timeline->checkConsistency());
1316         REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1317         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1318         REQUIRE(timeline->getClipPosition(cid1) == 2 * length);
1319         REQUIRE(undoStack->index() == init_index + 2);
1320         CHECK_MOVE(0);
1321 
1322         undoStack->undo();
1323         CHECK_MOVE(0);
1324         undoStack->undo();
1325         REQUIRE(timeline->checkConsistency());
1326         REQUIRE(timeline->getTrackClipsCount(tid1) == 0);
1327         REQUIRE(timeline->getClipTrackId(cid1) == -1);
1328         REQUIRE(undoStack->index() == init_index);
1329         CHECK_REMOVE(Once);
1330     }
1331 
1332     SECTION("Basic resize orphan clip undo")
1333     {
1334         REQUIRE(timeline->getClipPlaytime(cid2) == length);
1335 
1336         REQUIRE(timeline->requestItemResize(cid2, length - 5, true) == length - 5);
1337         REQUIRE(undoStack->index() == init_index + 1);
1338         REQUIRE(timeline->getClipPlaytime(cid2) == length - 5);
1339 
1340         REQUIRE(timeline->requestItemResize(cid2, length - 10, false) == length - 10);
1341         REQUIRE(undoStack->index() == init_index + 2);
1342         REQUIRE(timeline->getClipPlaytime(cid2) == length - 10);
1343 
1344         REQUIRE(timeline->requestItemResize(cid2, length, false) == -1);
1345         REQUIRE(undoStack->index() == init_index + 2);
1346         REQUIRE(timeline->getClipPlaytime(cid2) == length - 10);
1347 
1348         undoStack->undo();
1349         REQUIRE(undoStack->index() == init_index + 1);
1350         REQUIRE(timeline->getClipPlaytime(cid2) == length - 5);
1351 
1352         undoStack->redo();
1353         REQUIRE(undoStack->index() == init_index + 2);
1354         REQUIRE(timeline->getClipPlaytime(cid2) == length - 10);
1355 
1356         undoStack->undo();
1357         REQUIRE(undoStack->index() == init_index + 1);
1358         REQUIRE(timeline->getClipPlaytime(cid2) == length - 5);
1359 
1360         undoStack->undo();
1361         REQUIRE(undoStack->index() == init_index);
1362         REQUIRE(timeline->getClipPlaytime(cid2) == length);
1363     }
1364     SECTION("Basic resize inserted clip undo")
1365     {
1366         REQUIRE(timeline->getClipPlaytime(cid2) == length);
1367 
__anond6fdc6cc2702(int pos, int l) 1368         auto check = [&](int pos, int l) {
1369             REQUIRE(timeline->checkConsistency());
1370             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1371             REQUIRE(timeline->getClipTrackId(cid2) == tid1);
1372             REQUIRE(timeline->getClipPlaytime(cid2) == l);
1373             REQUIRE(timeline->getClipPosition(cid2) == pos);
1374         };
1375         REQUIRE(timeline->requestClipMove(cid2, tid1, 5));
1376         INFO("Test 1");
1377         check(5, length);
1378         REQUIRE(undoStack->index() == init_index + 1);
1379 
1380         REQUIRE(timeline->requestItemResize(cid2, length - 5, true) == length - 5);
1381         INFO("Test 2");
1382         check(5, length - 5);
1383         REQUIRE(undoStack->index() == init_index + 2);
1384 
1385         REQUIRE(timeline->requestItemResize(cid2, length - 10, false) == length - 10);
1386         INFO("Test 3");
1387         check(10, length - 10);
1388         REQUIRE(undoStack->index() == init_index + 3);
1389 
1390         REQUIRE(timeline->requestItemResize(cid2, length, false) == -1);
1391         INFO("Test 4");
1392         check(10, length - 10);
1393         REQUIRE(undoStack->index() == init_index + 3);
1394 
1395         undoStack->undo();
1396         INFO("Test 5");
1397         check(5, length - 5);
1398         REQUIRE(undoStack->index() == init_index + 2);
1399 
1400         undoStack->redo();
1401         INFO("Test 6");
1402         check(10, length - 10);
1403         REQUIRE(undoStack->index() == init_index + 3);
1404 
1405         undoStack->undo();
1406         INFO("Test 7");
1407         check(5, length - 5);
1408         REQUIRE(undoStack->index() == init_index + 2);
1409 
1410         undoStack->undo();
1411         INFO("Test 8");
1412         check(5, length);
1413         REQUIRE(undoStack->index() == init_index + 1);
1414     }
1415     SECTION("Clip Insertion Undo")
1416     {
1417         QString binId3 = createProducer(profile_model, "red", binModel);
1418 
1419         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
__anond6fdc6cc2802() 1420         auto state1 = [&]() {
1421             REQUIRE(timeline->checkConsistency());
1422             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1423             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1424             REQUIRE(timeline->getClipPosition(cid1) == 5);
1425             REQUIRE(undoStack->index() == init_index + 1);
1426         };
1427         state1();
1428 
1429         int cid3;
1430         REQUIRE_FALSE(timeline->requestClipInsertion(binId3, tid1, 5, cid3));
1431         state1();
1432 
1433         REQUIRE_FALSE(timeline->requestClipInsertion(binId3, tid1, 6, cid3));
1434         state1();
1435 
1436         REQUIRE(timeline->requestClipInsertion(binId3, tid1, 5 + length, cid3));
__anond6fdc6cc2902() 1437         auto state2 = [&]() {
1438             REQUIRE(timeline->checkConsistency());
1439             REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
1440             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1441             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
1442             REQUIRE(timeline->getClipPosition(cid1) == 5);
1443             REQUIRE(timeline->getClipPosition(cid3) == 5 + length);
1444             REQUIRE(timeline->m_allClips[cid3]->isValid());
1445             REQUIRE(undoStack->index() == init_index + 2);
1446         };
1447         state2();
1448 
1449         REQUIRE(timeline->requestClipMove(cid3, tid1, 10 + length));
__anond6fdc6cc2a02() 1450         auto state3 = [&]() {
1451             REQUIRE(timeline->checkConsistency());
1452             REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
1453             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1454             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
1455             REQUIRE(timeline->getClipPosition(cid1) == 5);
1456             REQUIRE(timeline->getClipPosition(cid3) == 10 + length);
1457             REQUIRE(undoStack->index() == init_index + 3);
1458         };
1459         state3();
1460 
1461         REQUIRE(timeline->requestItemResize(cid3, 1, true) == 1);
__anond6fdc6cc2b02() 1462         auto state4 = [&]() {
1463             REQUIRE(timeline->checkConsistency());
1464             REQUIRE(timeline->getTrackClipsCount(tid1) == 2);
1465             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1466             REQUIRE(timeline->getClipTrackId(cid3) == tid1);
1467             REQUIRE(timeline->getClipPosition(cid1) == 5);
1468             REQUIRE(timeline->getClipPlaytime(cid3) == 1);
1469             REQUIRE(timeline->getClipPosition(cid3) == 10 + length);
1470             REQUIRE(undoStack->index() == init_index + 4);
1471         };
1472         state4();
1473 
1474         undoStack->undo();
1475         state3();
1476 
1477         undoStack->undo();
1478         state2();
1479 
1480         undoStack->undo();
1481         state1();
1482 
1483         undoStack->redo();
1484         state2();
1485 
1486         undoStack->redo();
1487         state3();
1488 
1489         undoStack->redo();
1490         state4();
1491 
1492         undoStack->undo();
1493         state3();
1494 
1495         undoStack->undo();
1496         state2();
1497 
1498         undoStack->undo();
1499         state1();
1500     }
1501 
1502     SECTION("Clip Deletion undo")
1503     {
1504         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
__anond6fdc6cc2c02() 1505         auto state1 = [&]() {
1506             REQUIRE(timeline->checkConsistency());
1507             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1508             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1509             REQUIRE(timeline->getClipPosition(cid1) == 5);
1510             REQUIRE(undoStack->index() == init_index + 1);
1511         };
1512         state1();
1513 
1514         int nbClips = timeline->getClipsCount();
1515         REQUIRE(timeline->requestItemDeletion(cid1));
__anond6fdc6cc2d02() 1516         auto state2 = [&]() {
1517             REQUIRE(timeline->checkConsistency());
1518             REQUIRE(timeline->getTrackClipsCount(tid1) == 0);
1519             REQUIRE(timeline->getClipsCount() == nbClips - 1);
1520             REQUIRE(undoStack->index() == init_index + 2);
1521         };
1522         state2();
1523 
1524         undoStack->undo();
1525         state1();
1526 
1527         undoStack->redo();
1528         state2();
1529 
1530         undoStack->undo();
1531         state1();
1532     }
1533 
1534     SECTION("Select then delete")
1535     {
1536         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
1537         REQUIRE(timeline->requestClipMove(cid2, tid2, 1));
__anond6fdc6cc2e02() 1538         auto state1 = [&]() {
1539             REQUIRE(timeline->checkConsistency());
1540             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1541             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1542             REQUIRE(timeline->getClipPosition(cid1) == 5);
1543             REQUIRE(timeline->getTrackClipsCount(tid2) == 1);
1544             REQUIRE(timeline->getClipTrackId(cid2) == tid2);
1545             REQUIRE(timeline->getClipPosition(cid2) == 1);
1546         };
1547         state1();
1548 
1549         REQUIRE(timeline->requestSetSelection({cid1, cid2}));
1550         int nbClips = timeline->getClipsCount();
1551         REQUIRE(timeline->requestItemDeletion(cid1));
__anond6fdc6cc2f02() 1552         auto state2 = [&]() {
1553             REQUIRE(timeline->checkConsistency());
1554             REQUIRE(timeline->getTrackClipsCount(tid1) == 0);
1555             REQUIRE(timeline->getTrackClipsCount(tid2) == 0);
1556             REQUIRE(timeline->getClipsCount() == nbClips - 2);
1557         };
1558         state2();
1559 
1560         undoStack->undo();
1561         state1();
1562 
1563         undoStack->redo();
1564         state2();
1565 
1566         undoStack->undo();
1567         state1();
1568     }
1569 
1570     SECTION("Track insertion undo")
1571     {
1572         std::map<int, int> orig_trackPositions, final_trackPositions;
1573         for (const auto &it : timeline->m_iteratorTable) {
1574             int track = it.first;
1575             int pos = timeline->getTrackPosition(track);
1576             orig_trackPositions[track] = pos;
1577             if (pos >= 1) pos++;
1578             final_trackPositions[track] = pos;
1579         }
__anond6fdc6cc3002(const std::map<int, int> &pos) 1580         auto checkPositions = [&](const std::map<int, int> &pos) {
1581             for (const auto &p : pos) {
1582                 REQUIRE(timeline->getTrackPosition(p.first) == p.second);
1583             }
1584         };
1585         checkPositions(orig_trackPositions);
1586         int new_tid;
1587         REQUIRE(timeline->requestTrackInsertion(1, new_tid));
1588         checkPositions(final_trackPositions);
1589 
1590         undoStack->undo();
1591         checkPositions(orig_trackPositions);
1592 
1593         undoStack->redo();
1594         checkPositions(final_trackPositions);
1595 
1596         undoStack->undo();
1597         checkPositions(orig_trackPositions);
1598     }
1599 
1600     SECTION("Track deletion undo")
1601     {
1602         int nb_clips = timeline->getClipsCount();
1603         int nb_tracks = timeline->getTracksCount();
1604         REQUIRE(timeline->requestClipMove(cid1, tid1, 5));
__anond6fdc6cc3102() 1605         auto state1 = [&]() {
1606             REQUIRE(timeline->checkConsistency());
1607             REQUIRE(timeline->getTrackClipsCount(tid1) == 1);
1608             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1609             REQUIRE(timeline->getClipPosition(cid1) == 5);
1610             REQUIRE(undoStack->index() == init_index + 1);
1611             REQUIRE(timeline->getClipsCount() == nb_clips);
1612             REQUIRE(timeline->getTracksCount() == nb_tracks);
1613         };
1614         state1();
1615 
1616         REQUIRE(timeline->requestTrackDeletion(tid1));
1617         REQUIRE(timeline->getClipsCount() == nb_clips - 1);
1618         REQUIRE(timeline->getTracksCount() == nb_tracks - 1);
1619 
1620         undoStack->undo();
1621         state1();
1622 
1623         undoStack->redo();
1624         REQUIRE(timeline->getClipsCount() == nb_clips - 1);
1625         REQUIRE(timeline->getTracksCount() == nb_tracks - 1);
1626 
1627         undoStack->undo();
1628         state1();
1629     }
1630 
1631     int clipCount = timeline->m_allClips.size();
1632     SECTION("Clip creation and resize")
1633     {
1634         int cid6;
__anond6fdc6cc3202() 1635         auto state0 = [&]() {
1636             REQUIRE(timeline->m_allClips.size() == clipCount);
1637             REQUIRE(timeline->checkConsistency());
1638         };
1639         state0();
1640 
1641         {
__anond6fdc6cc3302() 1642             std::function<bool(void)> undo = []() { return true; };
__anond6fdc6cc3402() 1643             std::function<bool(void)> redo = []() { return true; };
1644             REQUIRE(timeline->requestClipCreation(binId, cid6, PlaylistState::VideoOnly, 1, 1., false, undo, redo));
1645             pCore->pushUndo(undo, redo, QString());
1646         }
1647         int l = timeline->getClipPlaytime(cid6);
1648 
__anond6fdc6cc3502() 1649         auto state1 = [&]() {
1650             REQUIRE(timeline->m_allClips.size() == clipCount + 1);
1651             REQUIRE(timeline->isClip(cid6));
1652             REQUIRE(timeline->getClipTrackId(cid6) == -1);
1653             REQUIRE(timeline->getClipPlaytime(cid6) == l);
1654         };
1655         state1();
1656 
1657         {
__anond6fdc6cc3602() 1658             std::function<bool(void)> undo = []() { return true; };
__anond6fdc6cc3702() 1659             std::function<bool(void)> redo = []() { return true; };
1660             int size = l - 5;
1661             REQUIRE(timeline->requestItemResize(cid6, size, true, true, undo, redo, false));
1662             pCore->pushUndo(undo, redo, QString());
1663         }
__anond6fdc6cc3802() 1664         auto state2 = [&]() {
1665             REQUIRE(timeline->m_allClips.size() == clipCount + 1);
1666             REQUIRE(timeline->isClip(cid6));
1667             REQUIRE(timeline->getClipTrackId(cid6) == -1);
1668             REQUIRE(timeline->getClipPlaytime(cid6) == l - 5);
1669         };
1670         state2();
1671 
1672         {
__anond6fdc6cc3902() 1673             std::function<bool(void)> undo = []() { return true; };
__anond6fdc6cc3a02() 1674             std::function<bool(void)> redo = []() { return true; };
1675             REQUIRE(timeline->requestClipMove(cid6, tid1, 7, true, true, true, true, undo, redo));
1676             pCore->pushUndo(undo, redo, QString());
1677         }
__anond6fdc6cc3b02() 1678         auto state3 = [&]() {
1679             REQUIRE(timeline->m_allClips.size() == clipCount + 1);
1680             REQUIRE(timeline->isClip(cid6));
1681             REQUIRE(timeline->getClipTrackId(cid6) == tid1);
1682             REQUIRE(timeline->getClipPosition(cid6) == 7);
1683             REQUIRE(timeline->getClipPlaytime(cid6) == l - 5);
1684         };
1685         state3();
1686 
1687         {
__anond6fdc6cc3c02() 1688             std::function<bool(void)> undo = []() { return true; };
__anond6fdc6cc3d02() 1689             std::function<bool(void)> redo = []() { return true; };
1690             int size = l - 6;
1691             REQUIRE(timeline->requestItemResize(cid6, size, false, true, undo, redo, false));
1692             pCore->pushUndo(undo, redo, QString());
1693         }
__anond6fdc6cc3e02() 1694         auto state4 = [&]() {
1695             REQUIRE(timeline->m_allClips.size() == clipCount + 1);
1696             REQUIRE(timeline->isClip(cid6));
1697             REQUIRE(timeline->getClipTrackId(cid6) == tid1);
1698             REQUIRE(timeline->getClipPosition(cid6) == 8);
1699             REQUIRE(timeline->getClipPlaytime(cid6) == l - 6);
1700         };
1701         state4();
1702 
1703         undoStack->undo();
1704         state3();
1705         undoStack->undo();
1706         state2();
1707         undoStack->undo();
1708         state1();
1709         undoStack->undo();
1710         state0();
1711         undoStack->redo();
1712         state1();
1713         undoStack->redo();
1714         state2();
1715         undoStack->redo();
1716         state3();
1717         undoStack->redo();
1718         state4();
1719     }
1720     binModel->clean();
1721     pCore->m_projectManager = nullptr;
1722 }
1723 
1724 TEST_CASE("Snapping", "[Snapping]")
1725 {
1726     auto binModel = pCore->projectItemModel();
1727     binModel->clean();
1728     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
1729     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
1730 
1731     // Here we do some trickery to enable testing.
1732     // We mock the project class so that the undoStack function returns our undoStack
1733 
1734     Mock<ProjectManager> pmMock;
1735     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
1736     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
1737 
1738     ProjectManager &mocked = pmMock.get();
1739     pCore->m_projectManager = &mocked;
1740 
1741     // We also mock timeline object to spy few functions and mock others
1742     TimelineItemModel tim(&profile_model, undoStack);
1743     Mock<TimelineItemModel> timMock(tim);
__anond6fdc6cc3f02(...) 1744     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
1745     TimelineItemModel::finishConstruct(timeline, guideModel);
1746 
1747     RESET(timMock);
1748 
1749     QString binId = createProducer(profile_model, "red", binModel, 50);
1750     QString binId2 = createProducer(profile_model, "blue", binModel);
1751 
1752     int tid1 = TrackModel::construct(timeline);
1753     int cid1 = ClipModel::construct(timeline, binId, -1, PlaylistState::VideoOnly);
1754     int tid2 = TrackModel::construct(timeline);
1755     int cid2 = ClipModel::construct(timeline, binId2, -1, PlaylistState::VideoOnly);
1756 
1757     int length = timeline->getClipPlaytime(cid1);
1758     int length2 = timeline->getClipPlaytime(cid2);
1759     SECTION("getBlankSizeNearClip")
1760     {
1761         REQUIRE(timeline->requestClipMove(cid1, tid1, 0));
1762 
1763         // before
1764         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid1, false) == 0);
1765         // after
1766         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid1, true) == INT_MAX);
1767         REQUIRE(timeline->requestClipMove(cid1, tid1, 10));
1768         // before
1769         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid1, false) == 10);
1770         // after
1771         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid1, true) == INT_MAX);
1772         REQUIRE(timeline->requestClipMove(cid2, tid1, 25 + length));
1773         // before
1774         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid1, false) == 10);
1775         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid2, false) == 15);
1776         // after
1777         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid1, true) == 15);
1778         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid2, true) == INT_MAX);
1779 
1780         REQUIRE(timeline->requestClipMove(cid2, tid1, 10 + length));
1781         // before
1782         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid1, false) == 10);
1783         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid2, false) == 0);
1784         // after
1785         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid1, true) == 0);
1786         REQUIRE(timeline->getTrackById(tid1)->getBlankSizeNearClip(cid2, true) == INT_MAX);
1787     }
1788     SECTION("Snap move to a single clip")
1789     {
1790         int beg = 30;
1791         // in the absence of other clips, a valid move shouldn't be modified
1792         for (int snap = -1; snap <= 5; ++snap) {
1793             REQUIRE(timeline->suggestClipMove(cid2, tid2, beg, -1, snap).at(0) == beg);
1794             REQUIRE(timeline->suggestClipMove(cid2, tid2, beg + length, -1, snap).at(0) == beg + length);
1795             REQUIRE(timeline->checkConsistency());
1796         }
1797 
1798         // We add a clip in first track to create snap points
1799         REQUIRE(timeline->requestClipMove(cid1, tid1, beg));
1800 
1801         // Now a clip in second track should snap to beginning
__anond6fdc6cc4002(int pos, int perturb, int snap) 1802         auto check_snap = [&](int pos, int perturb, int snap) {
1803             if (snap >= perturb) {
1804                 REQUIRE(timeline->suggestClipMove(cid2, tid2, pos + perturb, -1, snap).at(0) == pos);
1805                 REQUIRE(timeline->suggestClipMove(cid2, tid2, pos - perturb, -1, snap).at(0) == pos);
1806             } else {
1807                 REQUIRE(timeline->suggestClipMove(cid2, tid2, pos + perturb, -1, snap).at(0) == pos + perturb);
1808                 REQUIRE(timeline->suggestClipMove(cid2, tid2, pos - perturb, -1, snap).at(0) == pos - perturb);
1809             }
1810         };
1811         for (int snap = -1; snap <= 5; ++snap) {
1812             for (int perturb = 0; perturb <= 6; ++perturb) {
1813                 // snap to beginning
1814                 check_snap(beg, perturb, snap);
1815                 check_snap(beg + length, perturb, snap);
1816                 // snap to end
1817                 check_snap(beg - length2, perturb, snap);
1818                 check_snap(beg + length - length2, perturb, snap);
1819                 REQUIRE(timeline->checkConsistency());
1820             }
1821         }
1822 
1823         // Same test, but now clip is moved in position 0 first
1824         REQUIRE(timeline->requestClipMove(cid2, tid2, 0));
1825         for (int snap = -1; snap <= 5; ++snap) {
1826             for (int perturb = 0; perturb <= 6; ++perturb) {
1827                 // snap to beginning
1828                 check_snap(beg, perturb, snap);
1829                 check_snap(beg + length, perturb, snap);
1830                 // snap to end
1831                 check_snap(beg - length2, perturb, snap);
1832                 check_snap(beg + length - length2, perturb, snap);
1833                 REQUIRE(timeline->checkConsistency());
1834             }
1835         }
1836     }
1837     binModel->clean();
1838     pCore->m_projectManager = nullptr;
1839 }
1840 
1841 TEST_CASE("Operations under locked tracks", "[Locked]")
1842 {
1843 
1844     QString aCompo;
1845     // Look for a compo
1846     QVector<QPair<QString, QString>> transitions = TransitionsRepository::get()->getNames();
1847     for (const auto &trans : qAsConst(transitions)) {
1848         if (TransitionsRepository::get()->isComposition(trans.first)) {
1849             aCompo = trans.first;
1850             break;
1851         }
1852     }
1853     REQUIRE(!aCompo.isEmpty());
1854 
1855     auto binModel = pCore->projectItemModel();
1856     binModel->clean();
1857     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
1858     std::shared_ptr<MarkerListModel> guideModel = std::make_shared<MarkerListModel>(undoStack);
1859 
1860     // Here we do some trickery to enable testing.
1861     // We mock the project class so that the undoStack function returns our undoStack
1862 
1863     Mock<ProjectManager> pmMock;
1864     When(Method(pmMock, undoStack)).AlwaysReturn(undoStack);
1865     When(Method(pmMock, cacheDir)).AlwaysReturn(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
1866 
1867     ProjectManager &mocked = pmMock.get();
1868     pCore->m_projectManager = &mocked;
1869 
1870     // We also mock timeline object to spy few functions and mock others
1871     TimelineItemModel tim(&profile_model, undoStack);
1872     Mock<TimelineItemModel> timMock(tim);
__anond6fdc6cc4102(...) 1873     auto timeline = std::shared_ptr<TimelineItemModel>(&timMock.get(), [](...) {});
1874     TimelineItemModel::finishConstruct(timeline, guideModel);
1875 
1876     Fake(Method(timMock, adjustAssetRange));
1877 
1878     // This is faked to allow to count calls
1879     Fake(Method(timMock, _beginInsertRows));
1880     Fake(Method(timMock, _beginRemoveRows));
1881     Fake(Method(timMock, _endInsertRows));
1882     Fake(Method(timMock, _endRemoveRows));
1883 
1884     QString binId = createProducer(profile_model, "red", binModel);
1885     QString binId3 = createProducerWithSound(profile_model, binModel);
1886 
1887     int tid1, tid2, tid3;
1888     REQUIRE(timeline->requestTrackInsertion(-1, tid1));
1889     REQUIRE(timeline->requestTrackInsertion(-1, tid2));
1890     REQUIRE(timeline->requestTrackInsertion(-1, tid3));
1891 
1892     RESET(timMock);
1893 
1894     SECTION("Locked track can't receive insertion")
1895     {
1896         timeline->setTrackLockedState(tid1, true);
1897         REQUIRE(timeline->getTrackById(tid1)->isLocked());
1898         REQUIRE(timeline->getClipsCount() == 0);
1899         REQUIRE(timeline->checkConsistency());
1900         int cid1 = -1;
1901         REQUIRE_FALSE(timeline->requestClipInsertion(binId, tid1, 2, cid1));
1902         REQUIRE(timeline->getClipsCount() == 0);
1903         REQUIRE(timeline->checkConsistency());
1904         REQUIRE(cid1 == -1);
1905 
1906         // now unlock and check that insertion becomes possible again
1907         timeline->setTrackLockedState(tid1, false);
1908         REQUIRE_FALSE(timeline->getTrackById(tid1)->isLocked());
1909         REQUIRE(timeline->getClipsCount() == 0);
1910         REQUIRE(timeline->checkConsistency());
1911         REQUIRE(timeline->requestClipInsertion(binId, tid1, 2, cid1));
1912         REQUIRE(timeline->getClipsCount() == 1);
1913         REQUIRE(timeline->checkConsistency());
1914         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1915         REQUIRE(timeline->getClipPosition(cid1) == 2);
1916     }
1917     SECTION("Can't move clip on locked track")
1918     {
1919         int cid1 = -1;
1920         REQUIRE(timeline->requestClipInsertion(binId, tid1, 2, cid1));
1921         REQUIRE(timeline->getClipsCount() == 1);
1922         REQUIRE(timeline->checkConsistency());
1923         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1924         REQUIRE(timeline->getClipPosition(cid1) == 2);
1925         // not yet locked, move should work
1926         REQUIRE(timeline->requestClipMove(cid1, tid1, 4));
1927         REQUIRE(timeline->getClipPosition(cid1) == 4);
1928         REQUIRE(timeline->checkConsistency());
1929         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1930 
1931         timeline->setTrackLockedState(tid1, true);
1932         REQUIRE(timeline->getTrackById(tid1)->isLocked());
1933         REQUIRE(timeline->checkConsistency());
1934         REQUIRE(timeline->getClipsCount() == 1);
1935         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1936         REQUIRE(timeline->getClipPosition(cid1) == 4);
1937 
1938         REQUIRE_FALSE(timeline->requestClipMove(cid1, tid1, 6));
1939 
1940         REQUIRE(timeline->getTrackById(tid1)->isLocked());
1941         REQUIRE(timeline->checkConsistency());
1942         REQUIRE(timeline->getClipsCount() == 1);
1943         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1944         REQUIRE(timeline->getClipPosition(cid1) == 4);
1945 
1946         // unlock, move should work again
1947         timeline->setTrackLockedState(tid1, false);
1948         REQUIRE_FALSE(timeline->getTrackById(tid1)->isLocked());
1949         REQUIRE(timeline->checkConsistency());
1950         REQUIRE(timeline->requestClipMove(cid1, tid1, 6));
1951         REQUIRE(timeline->getClipsCount() == 1);
1952         REQUIRE(timeline->getClipTrackId(cid1) == tid1);
1953         REQUIRE(timeline->getClipPosition(cid1) == 6);
1954         REQUIRE(timeline->checkConsistency());
1955     }
1956     SECTION("Can't move composition on locked track")
1957     {
1958         int compo = CompositionModel::construct(timeline, aCompo, QString());
1959         timeline->setTrackLockedState(tid1, true);
1960         REQUIRE(timeline->getTrackById(tid1)->isLocked());
1961         REQUIRE(timeline->checkConsistency());
1962 
1963         REQUIRE(timeline->getCompositionTrackId(compo) == -1);
1964         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 0);
1965         int pos = 10;
1966         REQUIRE_FALSE(timeline->requestCompositionMove(compo, tid1, pos));
1967         REQUIRE(timeline->checkConsistency());
1968         REQUIRE(timeline->getCompositionTrackId(compo) == -1);
1969         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 0);
1970 
1971         // unlock to be able to insert
1972         timeline->setTrackLockedState(tid1, false);
1973         REQUIRE_FALSE(timeline->getTrackById(tid1)->isLocked());
1974         REQUIRE(timeline->checkConsistency());
1975         REQUIRE(timeline->requestCompositionMove(compo, tid1, pos));
1976         REQUIRE(timeline->checkConsistency());
1977         REQUIRE(timeline->getCompositionTrackId(compo) == tid1);
1978         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
1979         REQUIRE(timeline->getCompositionPosition(compo) == pos);
1980 
1981         // relock
1982         timeline->setTrackLockedState(tid1, true);
1983         REQUIRE(timeline->getTrackById(tid1)->isLocked());
1984         REQUIRE(timeline->checkConsistency());
1985         REQUIRE_FALSE(timeline->requestCompositionMove(compo, tid1, pos + 10));
1986         REQUIRE(timeline->checkConsistency());
1987         REQUIRE(timeline->getCompositionTrackId(compo) == tid1);
1988         REQUIRE(timeline->getTrackCompositionsCount(tid1) == 1);
1989         REQUIRE(timeline->getCompositionPosition(compo) == pos);
1990     }
1991     SECTION("Can't resize clip on locked track")
1992     {
1993         int cid1 = -1;
1994         REQUIRE(timeline->requestClipInsertion(binId, tid1, 2, cid1));
1995         REQUIRE(timeline->getClipsCount() == 1);
1996 
__anond6fdc6cc4202(int l) 1997         auto check = [&](int l) {
1998             REQUIRE(timeline->checkConsistency());
1999             REQUIRE(timeline->getClipTrackId(cid1) == tid1);
2000             REQUIRE(timeline->getClipPosition(cid1) == 2);
2001             REQUIRE(timeline->getClipPlaytime(cid1) == l);
2002         };
2003         check(20);
2004 
2005         // not yet locked, resize should work
2006         REQUIRE(timeline->requestItemResize(cid1, 18, true) == 18);
2007         check(18);
2008 
2009         // lock
2010         timeline->setTrackLockedState(tid1, true);
2011         REQUIRE(timeline->getTrackById(tid1)->isLocked());
2012         check(18);
2013         REQUIRE(timeline->requestItemResize(cid1, 17, true) == -1);
2014         check(18);
2015         REQUIRE(timeline->requestItemResize(cid1, 17, false) == -1);
2016         check(18);
2017         REQUIRE(timeline->requestItemResize(cid1, 19, true) == -1);
2018         check(18);
2019         REQUIRE(timeline->requestItemResize(cid1, 19, false) == -1);
2020         check(18);
2021 
2022         // unlock, resize should work again
2023         timeline->setTrackLockedState(tid1, false);
2024         REQUIRE_FALSE(timeline->getTrackById(tid1)->isLocked());
2025         check(18);
2026         REQUIRE(timeline->requestItemResize(cid1, 17, true) == 17);
2027         check(17);
2028     }
2029     SECTION("Can't resize composition on locked track")
2030     {
2031         int compo = CompositionModel::construct(timeline, aCompo, QString());
2032         REQUIRE(timeline->requestCompositionMove(compo, tid1, 2));
2033         REQUIRE(timeline->requestItemResize(compo, 20, true) == 20);
2034 
__anond6fdc6cc4302(int l) 2035         auto check = [&](int l) {
2036             REQUIRE(timeline->checkConsistency());
2037             REQUIRE(timeline->getCompositionsCount() == 1);
2038             REQUIRE(timeline->getCompositionTrackId(compo) == tid1);
2039             REQUIRE(timeline->getCompositionPosition(compo) == 2);
2040             REQUIRE(timeline->getCompositionPlaytime(compo) == l);
2041         };
2042         check(20);
2043 
2044         // not yet locked, resize should work
2045         REQUIRE(timeline->requestItemResize(compo, 18, true) == 18);
2046         check(18);
2047 
2048         // lock
2049         timeline->setTrackLockedState(tid1, true);
2050         REQUIRE(timeline->getTrackById(tid1)->isLocked());
2051         check(18);
2052         REQUIRE(timeline->requestItemResize(compo, 17, true) == -1);
2053         check(18);
2054         REQUIRE(timeline->requestItemResize(compo, 17, false) == -1);
2055         check(18);
2056         REQUIRE(timeline->requestItemResize(compo, 19, true) == -1);
2057         check(18);
2058         REQUIRE(timeline->requestItemResize(compo, 19, false) == -1);
2059         check(18);
2060 
2061         // unlock, resize should work again
2062         timeline->setTrackLockedState(tid1, false);
2063         REQUIRE_FALSE(timeline->getTrackById(tid1)->isLocked());
2064         check(18);
2065         REQUIRE(timeline->requestItemResize(compo, 17, true) == 17);
2066         check(17);
2067     }
2068 
2069     binModel->clean();
2070     pCore->m_projectManager = nullptr;
2071 }
2072 
2073