@@ -1102,6 +1102,102 @@ TEST_SUITE("tracktion_engine")
11021102 }
11031103 }
11041104
1105+ TEST_CASE (" Clipboard::AutomationPoints" )
1106+ {
1107+ auto & engine = *tracktion::engine::Engine::getEngines ()[0 ];
1108+ auto context = AutomationCurveListTestContext::create (engine);
1109+
1110+ context->edit ->ensureNumberOfAudioTracks (2 );
1111+ auto audioTracks = getAudioTracks (*context->edit );
1112+ auto at1 = audioTracks[0 ];
1113+ auto at2 = audioTracks[1 ];
1114+
1115+ auto volParam1 = at1->getVolumePlugin ()->volParam ;
1116+ auto panParam1 = at1->getVolumePlugin ()->panParam ;
1117+ auto volParam2 = at2->getVolumePlugin ()->volParam ;
1118+
1119+ // Add some automation points to volParam1
1120+ auto & curve1 = volParam1->getCurve ();
1121+ curve1.addPoint (0_tp, 0 .0f , 0 .0f , nullptr );
1122+ curve1.addPoint (1_tp, 1 .0f , 0 .0f , nullptr );
1123+ curve1.addPoint (2_tp, 0 .5f , 0 .0f , nullptr );
1124+
1125+ SUBCASE (" Single-curve constructor populates curves vector" )
1126+ {
1127+ // Test the AutomatableParameter& constructor
1128+ Clipboard::AutomationPoints content (*volParam1, curve1, TimeRange (0_tp, 2_tp));
1129+
1130+ // Verify curves[0] is populated (not legacy fields)
1131+ CHECK_EQ (content.curves .size (), 1 );
1132+ CHECK_EQ (content.curves [0 ].points .size (), 3 );
1133+ CHECK_EQ (content.curves [0 ].valueRange , volParam1->getValueRange ());
1134+ CHECK_EQ (content.curves [0 ].paramID , volParam1->paramID );
1135+ }
1136+
1137+ SUBCASE (" Empty AutomationPoints returns false on paste" )
1138+ {
1139+ // Create empty content by constructing with empty track array
1140+ juce::Array<Track*> emptyTracks;
1141+ Clipboard::AutomationPoints emptyContent (emptyTracks, TimeRange (0_tp, 2_tp));
1142+
1143+ CHECK (emptyContent.curves .empty ());
1144+
1145+ // All paste methods should return false for empty content
1146+ auto & curve2 = volParam2->getCurve ();
1147+ CHECK_FALSE (emptyContent.pasteAutomationCurve (*volParam2, curve2, TimeRange (0_tp, 2_tp)));
1148+ CHECK_FALSE (emptyContent.pasteAutomationCurveAtIndex (*volParam2, curve2, TimeRange (0_tp, 2_tp), 0 ));
1149+
1150+ juce::Array<Track*> targetTracks;
1151+ targetTracks.add (at2);
1152+ CHECK_FALSE (emptyContent.pasteIntoTracks (targetTracks, 0_tp));
1153+ }
1154+
1155+ SUBCASE (" pasteAutomationCurveAtIndex clamps out-of-range index" )
1156+ {
1157+ Clipboard::AutomationPoints content (*volParam1, curve1, TimeRange (0_tp, 2_tp));
1158+ CHECK_EQ (content.curves .size (), 1 );
1159+
1160+ auto & curve2 = volParam2->getCurve ();
1161+ auto & curve2b = at2->getVolumePlugin ()->panParam ->getCurve ();
1162+
1163+ // Both index 0 and index 100 should paste from curves[0]
1164+ bool result0 = content.pasteAutomationCurveAtIndex (*volParam2, curve2, TimeRange (0_tp, 2_tp), 0 );
1165+ bool result100 = content.pasteAutomationCurveAtIndex (*at2->getVolumePlugin ()->panParam , curve2b, TimeRange (0_tp, 2_tp), 100 );
1166+
1167+ CHECK (result0);
1168+ CHECK (result100);
1169+
1170+ // Both should have pasted something (exact counts depend on mergeCurve behavior)
1171+ CHECK (curve2.getNumPoints () > 0 );
1172+ CHECK (curve2b.getNumPoints () > 0 );
1173+ }
1174+
1175+ SUBCASE (" Multi-parameter constructor populates multiple curves" )
1176+ {
1177+ // Add automation to panParam1 as well
1178+ auto & panCurve1 = panParam1->getCurve ();
1179+ panCurve1.addPoint (0_tp, 0 .0f , 0 .0f , nullptr );
1180+ panCurve1.addPoint (1_tp, 0 .5f , 0 .0f , nullptr );
1181+
1182+ juce::Array<AutomatableParameter*> params;
1183+ params.add (volParam1.get ());
1184+ params.add (panParam1.get ());
1185+
1186+ Clipboard::AutomationPoints content (params, TimeRange (0_tp, 2_tp));
1187+
1188+ // Should have 2 curves with correct metadata
1189+ CHECK_EQ (content.curves .size (), 2 );
1190+ CHECK_EQ (content.curves [0 ].valueRange , volParam1->getValueRange ());
1191+ CHECK_EQ (content.curves [1 ].valueRange , panParam1->getValueRange ());
1192+
1193+ // pasteAutomationCurve should succeed (uses curves[0])
1194+ auto & curve2 = volParam2->getCurve ();
1195+ bool result = content.pasteAutomationCurve (*volParam2, curve2, TimeRange (0_tp, 2_tp));
1196+ CHECK (result);
1197+ CHECK (curve2.getNumPoints () > 0 );
1198+ }
1199+ }
1200+
11051201 TEST_CASE (" AutomationCurveList: Clip plugin" )
11061202 {
11071203 auto & engine = *tracktion::engine::Engine::getEngines ()[0 ];
0 commit comments