22#include < scratchcpp/dev/compiler.h>
33#include < scratchcpp/dev/test/scriptbuilder.h>
44#include < scratchcpp/sprite.h>
5+ #include < scratchcpp/stage.h>
56#include < scratchcpp/block.h>
67#include < scratchcpp/input.h>
78#include < scratchcpp/field.h>
@@ -22,6 +23,8 @@ using namespace libscratchcpp;
2223using namespace libscratchcpp ::test;
2324
2425using ::testing::Return;
26+ using ::testing::SaveArg;
27+ using ::testing::_;
2528
2629class ControlBlocksTest : public testing ::Test
2730{
@@ -767,3 +770,296 @@ TEST_F(ControlBlocksTest, StartAsClone)
767770 EXPECT_CALL (m_engineMock, addCloneInitScript (block));
768771 compiler.compile (block);
769772}
773+
774+ TEST_F (ControlBlocksTest, CreateCloneOfSprite)
775+ {
776+ EXPECT_CALL (m_engineMock, cloneLimit ()).WillRepeatedly (Return (-1 ));
777+ EXPECT_CALL (m_engineMock, requestRedraw ()).WillRepeatedly (Return ());
778+ auto target = std::make_shared<Sprite>();
779+ target->setEngine (&m_engineMock);
780+
781+ // create clone of [Sprite1]
782+ {
783+ ScriptBuilder builder (m_extension.get (), m_engine, target);
784+
785+ builder.addBlock (" control_create_clone_of" );
786+ builder.addDropdownInput (" CLONE_OPTION" , " Sprite1" );
787+ auto block = builder.currentBlock ();
788+
789+ EXPECT_CALL (m_engineMock, findTarget (" Sprite1" )).WillOnce (Return (4 ));
790+ Compiler compiler (&m_engineMock, target.get ());
791+ auto code = compiler.compile (block);
792+ Script script (target.get (), block, &m_engineMock);
793+ script.setCode (code);
794+ Thread thread (target.get (), &m_engineMock, &script);
795+
796+ Sprite sprite;
797+ sprite.setEngine (&m_engineMock);
798+ std::shared_ptr<Sprite> clone;
799+ EXPECT_CALL (m_engineMock, targetAt (4 )).WillOnce (Return (&sprite));
800+ EXPECT_CALL (m_engineMock, initClone (_)).WillOnce (SaveArg<0 >(&clone));
801+ EXPECT_CALL (m_engineMock, moveDrawableBehindOther (_, &sprite));
802+ thread.run ();
803+ ASSERT_TRUE (clone);
804+ ASSERT_EQ (clone->cloneSprite (), &sprite);
805+ }
806+
807+ m_engine->clear ();
808+ target = std::make_shared<Sprite>();
809+ target->setEngine (&m_engineMock);
810+
811+ // create clone of [myself]
812+ {
813+ ScriptBuilder builder (m_extension.get (), m_engine, target);
814+
815+ builder.addBlock (" control_create_clone_of" );
816+ builder.addDropdownInput (" CLONE_OPTION" , " _myself_" );
817+ auto block = builder.currentBlock ();
818+
819+ EXPECT_CALL (m_engineMock, findTarget).Times (0 );
820+ Compiler compiler (&m_engineMock, target.get ());
821+ auto code = compiler.compile (block);
822+ Script script (target.get (), block, &m_engineMock);
823+ script.setCode (code);
824+ Thread thread (target.get (), &m_engineMock, &script);
825+
826+ std::shared_ptr<Sprite> clone;
827+ EXPECT_CALL (m_engineMock, initClone (_)).WillOnce (SaveArg<0 >(&clone));
828+ EXPECT_CALL (m_engineMock, moveDrawableBehindOther (_, target.get ()));
829+ thread.run ();
830+ ASSERT_TRUE (clone);
831+ ASSERT_EQ (clone->cloneSprite (), target.get ());
832+ }
833+
834+ m_engine->clear ();
835+ target = std::make_shared<Sprite>();
836+ target->setEngine (&m_engineMock);
837+
838+ // create clone of ["_mYself_"]
839+ {
840+ ScriptBuilder builder (m_extension.get (), m_engine, target);
841+
842+ builder.addBlock (" control_create_clone_of" );
843+ builder.addDropdownInput (" CLONE_OPTION" , " _mYself_" );
844+ auto block = builder.currentBlock ();
845+
846+ EXPECT_CALL (m_engineMock, findTarget (" _mYself_" )).WillOnce (Return (4 ));
847+ Compiler compiler (&m_engineMock, target.get ());
848+ auto code = compiler.compile (block);
849+ Script script (target.get (), block, &m_engineMock);
850+ script.setCode (code);
851+ Thread thread (target.get (), &m_engineMock, &script);
852+
853+ Sprite sprite;
854+ sprite.setEngine (&m_engineMock);
855+ std::shared_ptr<Sprite> clone;
856+ EXPECT_CALL (m_engineMock, targetAt (4 )).WillOnce (Return (&sprite));
857+ EXPECT_CALL (m_engineMock, initClone (_)).WillOnce (SaveArg<0 >(&clone));
858+ EXPECT_CALL (m_engineMock, moveDrawableBehindOther (_, &sprite));
859+ thread.run ();
860+ ASSERT_TRUE (clone);
861+ ASSERT_EQ (clone->cloneSprite (), &sprite);
862+ }
863+
864+ m_engine->clear ();
865+ target = std::make_shared<Sprite>();
866+ target->setEngine (&m_engineMock);
867+
868+ // create clone of (null block)
869+ {
870+ ScriptBuilder builder (m_extension.get (), m_engine, target);
871+
872+ builder.addBlock (" control_create_clone_of" );
873+ builder.addNullObscuredInput (" CLONE_OPTION" );
874+ auto block = builder.currentBlock ();
875+
876+ EXPECT_CALL (m_engineMock, findTarget).Times (0 );
877+ Compiler compiler (&m_engineMock, target.get ());
878+ auto code = compiler.compile (block);
879+ Script script (target.get (), block, &m_engineMock);
880+ script.setCode (code);
881+ Thread thread (target.get (), &m_engineMock, &script);
882+
883+ Sprite sprite;
884+ sprite.setEngine (&m_engineMock);
885+ std::shared_ptr<Sprite> clone;
886+ EXPECT_CALL (m_engineMock, findTarget (" 0" )).WillOnce (Return (2 ));
887+ EXPECT_CALL (m_engineMock, targetAt (2 )).WillOnce (Return (&sprite));
888+ EXPECT_CALL (m_engineMock, initClone (_)).WillOnce (SaveArg<0 >(&clone));
889+ EXPECT_CALL (m_engineMock, moveDrawableBehindOther (_, &sprite));
890+ thread.run ();
891+ ASSERT_TRUE (clone);
892+ ASSERT_EQ (clone->cloneSprite (), &sprite);
893+ }
894+
895+ m_engine->clear ();
896+ target = std::make_shared<Sprite>();
897+ target->setEngine (&m_engineMock);
898+
899+ // create clone of ("_myself_")
900+ {
901+ ScriptBuilder builder (m_extension.get (), m_engine, target);
902+
903+ builder.addBlock (" control_create_clone_of" );
904+ auto valueBlock = std::make_shared<Block>(" " , " test_input" );
905+ auto input = std::make_shared<Input>(" INPUT" , Input::Type::Shadow);
906+ input->setPrimaryValue (" _myself_" );
907+ valueBlock->addInput (input);
908+ builder.addObscuredInput (" CLONE_OPTION" , valueBlock);
909+ auto block = builder.currentBlock ();
910+
911+ EXPECT_CALL (m_engineMock, findTarget).Times (0 );
912+ Compiler compiler (&m_engineMock, target.get ());
913+ auto code = compiler.compile (block);
914+ Script script (target.get (), block, &m_engineMock);
915+ script.setCode (code);
916+ Thread thread (target.get (), &m_engineMock, &script);
917+
918+ std::shared_ptr<Sprite> clone;
919+ EXPECT_CALL (m_engineMock, findTarget).Times (0 );
920+ EXPECT_CALL (m_engineMock, initClone (_)).WillOnce (SaveArg<0 >(&clone));
921+ EXPECT_CALL (m_engineMock, moveDrawableBehindOther (_, target.get ()));
922+ thread.run ();
923+ ASSERT_TRUE (clone);
924+ ASSERT_EQ (clone->cloneSprite (), target.get ());
925+ }
926+
927+ // create clone of ("_mYself_")
928+ {
929+ ScriptBuilder builder (m_extension.get (), m_engine, target);
930+
931+ builder.addBlock (" control_create_clone_of" );
932+ auto valueBlock = std::make_shared<Block>(" " , " test_input" );
933+ auto input = std::make_shared<Input>(" INPUT" , Input::Type::Shadow);
934+ input->setPrimaryValue (" _mYself_" );
935+ valueBlock->addInput (input);
936+ builder.addObscuredInput (" CLONE_OPTION" , valueBlock);
937+ auto block = builder.currentBlock ();
938+
939+ EXPECT_CALL (m_engineMock, findTarget).Times (0 );
940+ Compiler compiler (&m_engineMock, target.get ());
941+ auto code = compiler.compile (block);
942+ Script script (target.get (), block, &m_engineMock);
943+ script.setCode (code);
944+ Thread thread (target.get (), &m_engineMock, &script);
945+
946+ Sprite sprite;
947+ sprite.setEngine (&m_engineMock);
948+ std::shared_ptr<Sprite> clone;
949+ EXPECT_CALL (m_engineMock, findTarget (" _mYself_" )).WillOnce (Return (2 ));
950+ EXPECT_CALL (m_engineMock, targetAt (2 )).WillOnce (Return (&sprite));
951+ EXPECT_CALL (m_engineMock, initClone (_)).WillOnce (SaveArg<0 >(&clone));
952+ EXPECT_CALL (m_engineMock, moveDrawableBehindOther (_, &sprite));
953+ thread.run ();
954+ ASSERT_TRUE (clone);
955+ ASSERT_EQ (clone->cloneSprite (), &sprite);
956+ }
957+ }
958+
959+ TEST_F (ControlBlocksTest, CreateCloneOfStage)
960+ {
961+ EXPECT_CALL (m_engineMock, cloneLimit ()).WillRepeatedly (Return (-1 ));
962+ EXPECT_CALL (m_engineMock, requestRedraw ()).WillRepeatedly (Return ());
963+ auto target = std::make_shared<Stage>();
964+ target->setEngine (&m_engineMock);
965+
966+ // create clone of [Stage]
967+ {
968+ ScriptBuilder builder (m_extension.get (), m_engine, target);
969+
970+ builder.addBlock (" control_create_clone_of" );
971+ builder.addDropdownInput (" CLONE_OPTION" , " _stage_" );
972+ auto block = builder.currentBlock ();
973+
974+ EXPECT_CALL (m_engineMock, findTarget (" _stage_" )).WillOnce (Return (8 ));
975+ Compiler compiler (&m_engineMock, target.get ());
976+ auto code = compiler.compile (block);
977+ Script script (target.get (), block, &m_engineMock);
978+ script.setCode (code);
979+ Thread thread (target.get (), &m_engineMock, &script);
980+
981+ Stage stage;
982+ stage.setEngine (&m_engineMock);
983+ EXPECT_CALL (m_engineMock, targetAt (8 )).WillOnce (Return (&stage));
984+ EXPECT_CALL (m_engineMock, initClone).Times (0 );
985+ thread.run ();
986+ }
987+
988+ m_engine->clear ();
989+ target = std::make_shared<Stage>();
990+ target->setEngine (&m_engineMock);
991+
992+ // create clone of [myself]
993+ {
994+ ScriptBuilder builder (m_extension.get (), m_engine, target);
995+
996+ builder.addBlock (" control_create_clone_of" );
997+ builder.addDropdownInput (" CLONE_OPTION" , " _myself_" );
998+ auto block = builder.currentBlock ();
999+
1000+ EXPECT_CALL (m_engineMock, findTarget).Times (0 );
1001+ Compiler compiler (&m_engineMock, target.get ());
1002+ auto code = compiler.compile (block);
1003+ Script script (target.get (), block, &m_engineMock);
1004+ script.setCode (code);
1005+ Thread thread (target.get (), &m_engineMock, &script);
1006+
1007+ EXPECT_CALL (m_engineMock, initClone).Times (0 );
1008+ thread.run ();
1009+ }
1010+
1011+ m_engine->clear ();
1012+ target = std::make_shared<Stage>();
1013+ target->setEngine (&m_engineMock);
1014+
1015+ // create clone of (null block)
1016+ {
1017+ ScriptBuilder builder (m_extension.get (), m_engine, target);
1018+
1019+ builder.addBlock (" control_create_clone_of" );
1020+ builder.addNullObscuredInput (" CLONE_OPTION" );
1021+ auto block = builder.currentBlock ();
1022+
1023+ EXPECT_CALL (m_engineMock, findTarget).Times (0 );
1024+ Compiler compiler (&m_engineMock, target.get ());
1025+ auto code = compiler.compile (block);
1026+ Script script (target.get (), block, &m_engineMock);
1027+ script.setCode (code);
1028+ Thread thread (target.get (), &m_engineMock, &script);
1029+
1030+ Stage stage;
1031+ stage.setEngine (&m_engineMock);
1032+ EXPECT_CALL (m_engineMock, findTarget (" 0" )).WillOnce (Return (2 ));
1033+ EXPECT_CALL (m_engineMock, targetAt (2 )).WillOnce (Return (&stage));
1034+ EXPECT_CALL (m_engineMock, initClone).Times (0 );
1035+ thread.run ();
1036+ }
1037+
1038+ m_engine->clear ();
1039+ target = std::make_shared<Stage>();
1040+ target->setEngine (&m_engineMock);
1041+
1042+ // create clone of ("_myself_")
1043+ {
1044+ ScriptBuilder builder (m_extension.get (), m_engine, target);
1045+
1046+ builder.addBlock (" control_create_clone_of" );
1047+ auto valueBlock = std::make_shared<Block>(" " , " test_input" );
1048+ auto input = std::make_shared<Input>(" INPUT" , Input::Type::Shadow);
1049+ input->setPrimaryValue (" _myself_" );
1050+ valueBlock->addInput (input);
1051+ builder.addObscuredInput (" CLONE_OPTION" , valueBlock);
1052+ auto block = builder.currentBlock ();
1053+
1054+ EXPECT_CALL (m_engineMock, findTarget).Times (0 );
1055+ Compiler compiler (&m_engineMock, target.get ());
1056+ auto code = compiler.compile (block);
1057+ Script script (target.get (), block, &m_engineMock);
1058+ script.setCode (code);
1059+ Thread thread (target.get (), &m_engineMock, &script);
1060+
1061+ EXPECT_CALL (m_engineMock, findTarget).Times (0 );
1062+ EXPECT_CALL (m_engineMock, initClone).Times (0 );
1063+ thread.run ();
1064+ }
1065+ }
0 commit comments