44#include < scratchcpp/inputvalue.h>
55#include < scratchcpp/field.h>
66#include < scratchcpp/broadcast.h>
7+ #include < scratchcpp/sprite.h>
78#include < scratchcpp/stage.h>
89#include < scratchcpp/costume.h>
910#include < enginemock.h>
1011#include < audioinputmock.h>
1112#include < audioloudnessmock.h>
1213#include < timermock.h>
14+ #include < targetmock.h>
1315
1416#include " ../common.h"
1517#include " blocks/eventblocks.h"
@@ -35,6 +37,15 @@ class EventBlocksTest : public testing::Test
3537 // For any event block
3638 std::shared_ptr<Block> createEventBlock (const std::string &id, const std::string &opcode) const { return std::make_shared<Block>(id, opcode); }
3739
40+ std::shared_ptr<Block> createNullBlock (const std::string &id)
41+ {
42+ std::shared_ptr<Block> block = std::make_shared<Block>(id, " " );
43+ BlockComp func = [](Compiler *compiler) { compiler->addInstruction (vm::OP_NULL); };
44+ block->setCompileFunction (func);
45+
46+ return block;
47+ }
48+
3849 void addBroadcastInput (std::shared_ptr<Block> block, const std::string &name, EventBlocks::Inputs id, std::shared_ptr<Broadcast> broadcast) const
3950 {
4051 auto input = std::make_shared<Input>(name, Input::Type::Shadow);
@@ -45,6 +56,15 @@ class EventBlocksTest : public testing::Test
4556 block->addInput (input);
4657 }
4758
59+ std::shared_ptr<Input> addNullInput (std::shared_ptr<Block> block, const std::string &name, EventBlocks::Inputs id) const
60+ {
61+ auto input = std::make_shared<Input>(name, Input::Type::Shadow);
62+ input->setInputId (id);
63+ block->addInput (input);
64+
65+ return input;
66+ }
67+
4868 void addValueInput (std::shared_ptr<Block> block, const std::string &name, EventBlocks::Inputs id, const Value &value) const
4969 {
5070 auto input = std::make_shared<Input>(name, Input::Type::Shadow);
@@ -61,6 +81,26 @@ class EventBlocksTest : public testing::Test
6181 block->addInput (input);
6282 }
6383
84+ void addDropdownInput (std::shared_ptr<Block> block, const std::string &name, EventBlocks::Inputs id, const std::string &selectedValue, std::shared_ptr<Block> valueBlock = nullptr ) const
85+ {
86+ if (valueBlock)
87+ addObscuredInput (block, name, id, valueBlock);
88+ else {
89+ auto input = addNullInput (block, name, id);
90+ auto menu = std::make_shared<Block>(block->id () + " _menu" , block->opcode () + " _menu" );
91+ input->setValueBlock (menu);
92+ addDropdownField (menu, name, static_cast <EventBlocks::Fields>(-1 ), selectedValue, static_cast <EventBlocks::FieldValues>(-1 ));
93+ }
94+ }
95+
96+ void addDropdownField (std::shared_ptr<Block> block, const std::string &name, EventBlocks::Fields id, const std::string &value, EventBlocks::FieldValues valueId) const
97+ {
98+ auto field = std::make_shared<Field>(name, value);
99+ field->setFieldId (id);
100+ field->setSpecialValueId (valueId);
101+ block->addField (field);
102+ }
103+
64104 void addValueField (std::shared_ptr<Block> block, const std::string &name, EventBlocks::Fields id, const std::string &value, int valueId = -1 ) const
65105 {
66106 auto field = std::make_shared<Field>(name, value);
@@ -95,6 +135,7 @@ TEST_F(EventBlocksTest, CategoryVisible)
95135TEST_F (EventBlocksTest, RegisterBlocks)
96136{
97137 // Blocks
138+ EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whentouchingobject" , &EventBlocks::compileWhenTouchingObject));
98139 EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whenflagclicked" , &EventBlocks::compileWhenFlagClicked));
99140 EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whenthisspriteclicked" , &EventBlocks::compileWhenThisSpriteClicked));
100141 EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whenstageclicked" , &EventBlocks::compileWhenStageClicked));
@@ -106,9 +147,11 @@ TEST_F(EventBlocksTest, RegisterBlocks)
106147 EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whenkeypressed" , &EventBlocks::compileWhenKeyPressed));
107148
108149 // Hat predicates
150+ EXPECT_CALL (m_engineMock, addHatPredicateCompileFunction (m_section.get (), " event_whentouchingobject" , &EventBlocks::compileWhenTouchingObjectPredicate));
109151 EXPECT_CALL (m_engineMock, addHatPredicateCompileFunction (m_section.get (), " event_whengreaterthan" , &EventBlocks::compileWhenGreaterThanPredicate));
110152
111153 // Inputs
154+ EXPECT_CALL (m_engineMock, addInput (m_section.get (), " TOUCHINGOBJECTMENU" , EventBlocks::TOUCHINGOBJECTMENU));
112155 EXPECT_CALL (m_engineMock, addInput (m_section.get (), " BROADCAST_INPUT" , EventBlocks::BROADCAST_INPUT));
113156 EXPECT_CALL (m_engineMock, addInput (m_section.get (), " VALUE" , EventBlocks::VALUE));
114157
@@ -125,6 +168,136 @@ TEST_F(EventBlocksTest, RegisterBlocks)
125168 m_section->registerBlocks (&m_engineMock);
126169}
127170
171+ TEST_F (EventBlocksTest, WhenTouchingObjectPredicate)
172+ {
173+ Compiler compiler (&m_engineMock);
174+
175+ // when touching (Sprite1)
176+ auto block1 = createEventBlock (" a" , " event_whentouchingobject" );
177+ addDropdownInput (block1, " TOUCHINGOBJECTMENU" , EventBlocks::TOUCHINGOBJECTMENU, " Sprite1" );
178+
179+ // when touching (null block)
180+ auto block2 = createEventBlock (" b" , " event_whentouchingobject" );
181+ addDropdownInput (block2, " TOUCHINGOBJECTMENU" , EventBlocks::TOUCHINGOBJECTMENU, " " , createNullBlock (" e" ));
182+
183+ compiler.init ();
184+
185+ EXPECT_CALL (m_engineMock, functionIndex (&EventBlocks::whenTouchingObjectPredicate)).WillOnce (Return (0 ));
186+ compiler.setBlock (block1);
187+ EventBlocks::compileWhenTouchingObjectPredicate (&compiler);
188+
189+ EXPECT_CALL (m_engineMock, functionIndex (&EventBlocks::whenTouchingObjectPredicate)).WillOnce (Return (0 ));
190+ compiler.setBlock (block2);
191+ EventBlocks::compileWhenTouchingObjectPredicate (&compiler);
192+
193+ compiler.end ();
194+
195+ ASSERT_EQ (compiler.bytecode (), std::vector<unsigned int >({ vm::OP_START, vm::OP_CONST, 0 , vm::OP_EXEC, 0 , vm::OP_NULL, vm::OP_EXEC, 0 , vm::OP_HALT }));
196+ ASSERT_EQ (compiler.constValues ().size (), 1 );
197+ ASSERT_EQ (compiler.constValues ()[0 ], " Sprite1" );
198+ ASSERT_TRUE (compiler.variables ().empty ());
199+ ASSERT_TRUE (compiler.lists ().empty ());
200+ }
201+
202+ TEST_F (EventBlocksTest, WhenTouchingObjectPredicateImpl)
203+ {
204+ static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0 , vm::OP_EXEC, 0 , vm::OP_HALT };
205+ static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1 , vm::OP_EXEC, 0 , vm::OP_HALT };
206+ static unsigned int bytecode3[] = { vm::OP_START, vm::OP_CONST, 2 , vm::OP_EXEC, 0 , vm::OP_HALT };
207+ static unsigned int bytecode4[] = { vm::OP_START, vm::OP_CONST, 3 , vm::OP_EXEC, 0 , vm::OP_HALT };
208+ static BlockFunc functions[] = { &EventBlocks::whenTouchingObjectPredicate };
209+ static Value constValues[] = { " Sprite2" , " _mouse_" , " _edge_" , " " , 1 , -1 , 2 };
210+
211+ TargetMock target;
212+ target.setEngine (&m_engineMock);
213+ Sprite sprite;
214+ VirtualMachine vm (&target, &m_engineMock, nullptr );
215+ vm.setFunctions (functions);
216+ vm.setConstValues (constValues);
217+
218+ // touching "Sprite2"
219+ EXPECT_CALL (m_engineMock, findTarget (" Sprite2" )).WillOnce (Return (3 ));
220+ EXPECT_CALL (m_engineMock, targetAt (3 )).WillOnce (Return (&sprite));
221+ EXPECT_CALL (target, touchingClones).WillOnce (Return (false ));
222+ vm.setBytecode (bytecode1);
223+ vm.run ();
224+
225+ ASSERT_EQ (vm.registerCount (), 1 );
226+ ASSERT_FALSE (vm.getInput (0 , 1 )->toBool ());
227+
228+ EXPECT_CALL (m_engineMock, findTarget (" Sprite2" )).WillOnce (Return (3 ));
229+ EXPECT_CALL (m_engineMock, targetAt (3 )).WillOnce (Return (&sprite));
230+ EXPECT_CALL (target, touchingClones).WillOnce (Return (true ));
231+ vm.reset ();
232+ vm.run ();
233+
234+ ASSERT_EQ (vm.registerCount (), 1 );
235+ ASSERT_TRUE (vm.getInput (0 , 1 )->toBool ());
236+
237+ // touching "_mouse_"
238+ EXPECT_CALL (m_engineMock, mouseX ()).WillOnce (Return (24.5 ));
239+ EXPECT_CALL (m_engineMock, mouseY ()).WillOnce (Return (-16.04 ));
240+ EXPECT_CALL (target, touchingPoint (24.5 , -16.04 )).WillOnce (Return (true ));
241+ vm.setBytecode (bytecode2);
242+ vm.reset ();
243+ vm.run ();
244+
245+ ASSERT_EQ (vm.registerCount (), 1 );
246+ ASSERT_TRUE (vm.getInput (0 , 1 )->toBool ());
247+
248+ // touching "_edge_"
249+ EXPECT_CALL (m_engineMock, stageWidth ()).WillOnce (Return (0 ));
250+ EXPECT_CALL (m_engineMock, stageHeight ()).WillOnce (Return (0 ));
251+ EXPECT_CALL (target, boundingRect ()).WillOnce (Return (Rect (-5 , 5 , 5 , -5 )));
252+ vm.setBytecode (bytecode3);
253+ vm.reset ();
254+ vm.run ();
255+
256+ ASSERT_EQ (vm.registerCount (), 1 );
257+ ASSERT_TRUE (vm.getInput (0 , 1 )->toBool ());
258+
259+ EXPECT_CALL (m_engineMock, stageWidth ()).WillOnce (Return (10 ));
260+ EXPECT_CALL (m_engineMock, stageHeight ()).WillOnce (Return (10 ));
261+ EXPECT_CALL (target, boundingRect ()).WillOnce (Return (Rect (-5 , 5 , 5 , -5 )));
262+ vm.reset ();
263+ vm.run ();
264+
265+ ASSERT_EQ (vm.registerCount (), 1 );
266+ ASSERT_FALSE (vm.getInput (0 , 1 )->toBool ());
267+
268+ // touching ""
269+ EXPECT_CALL (m_engineMock, findTarget (" " )).WillOnce (Return (-1 ));
270+ EXPECT_CALL (m_engineMock, targetAt (-1 )).WillOnce (Return (nullptr ));
271+ vm.setBytecode (bytecode4);
272+ vm.reset ();
273+ vm.run ();
274+
275+ ASSERT_EQ (vm.registerCount (), 1 );
276+ ASSERT_FALSE (vm.getInput (0 , 1 )->toBool ());
277+ }
278+
279+ TEST_F (EventBlocksTest, WhenTouchingObject)
280+ {
281+ Compiler compiler (&m_engineMock);
282+
283+ // when touching (Sprite1)
284+ auto block = createEventBlock (" a" , " event_whentouchingobject" );
285+ addDropdownInput (block, " TOUCHINGOBJECTMENU" , EventBlocks::TOUCHINGOBJECTMENU, " Sprite1" );
286+
287+ compiler.init ();
288+
289+ EXPECT_CALL (m_engineMock, addWhenTouchingObjectScript (block));
290+ compiler.setBlock (block);
291+ EventBlocks::compileWhenTouchingObject (&compiler);
292+
293+ compiler.end ();
294+
295+ ASSERT_EQ (compiler.bytecode (), std::vector<unsigned int >({ vm::OP_START, vm::OP_HALT }));
296+ ASSERT_TRUE (compiler.constValues ().empty ());
297+ ASSERT_TRUE (compiler.variables ().empty ());
298+ ASSERT_TRUE (compiler.lists ().empty ());
299+ }
300+
128301TEST_F (EventBlocksTest, WhenFlagClicked)
129302{
130303 Compiler compiler (&m_engineMock);
0 commit comments