4
4
#include < scratchcpp/inputvalue.h>
5
5
#include < scratchcpp/field.h>
6
6
#include < scratchcpp/broadcast.h>
7
+ #include < scratchcpp/sprite.h>
7
8
#include < scratchcpp/stage.h>
8
9
#include < scratchcpp/costume.h>
9
10
#include < enginemock.h>
10
11
#include < audioinputmock.h>
11
12
#include < audioloudnessmock.h>
12
13
#include < timermock.h>
14
+ #include < targetmock.h>
13
15
14
16
#include " ../common.h"
15
17
#include " blocks/eventblocks.h"
@@ -35,6 +37,15 @@ class EventBlocksTest : public testing::Test
35
37
// For any event block
36
38
std::shared_ptr<Block> createEventBlock (const std::string &id, const std::string &opcode) const { return std::make_shared<Block>(id, opcode); }
37
39
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
+
38
49
void addBroadcastInput (std::shared_ptr<Block> block, const std::string &name, EventBlocks::Inputs id, std::shared_ptr<Broadcast> broadcast) const
39
50
{
40
51
auto input = std::make_shared<Input>(name, Input::Type::Shadow);
@@ -45,6 +56,15 @@ class EventBlocksTest : public testing::Test
45
56
block->addInput (input);
46
57
}
47
58
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
+
48
68
void addValueInput (std::shared_ptr<Block> block, const std::string &name, EventBlocks::Inputs id, const Value &value) const
49
69
{
50
70
auto input = std::make_shared<Input>(name, Input::Type::Shadow);
@@ -61,6 +81,26 @@ class EventBlocksTest : public testing::Test
61
81
block->addInput (input);
62
82
}
63
83
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
+
64
104
void addValueField (std::shared_ptr<Block> block, const std::string &name, EventBlocks::Fields id, const std::string &value, int valueId = -1 ) const
65
105
{
66
106
auto field = std::make_shared<Field>(name, value);
@@ -95,6 +135,7 @@ TEST_F(EventBlocksTest, CategoryVisible)
95
135
TEST_F (EventBlocksTest, RegisterBlocks)
96
136
{
97
137
// Blocks
138
+ EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whentouchingobject" , &EventBlocks::compileWhenTouchingObject));
98
139
EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whenflagclicked" , &EventBlocks::compileWhenFlagClicked));
99
140
EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whenthisspriteclicked" , &EventBlocks::compileWhenThisSpriteClicked));
100
141
EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whenstageclicked" , &EventBlocks::compileWhenStageClicked));
@@ -106,9 +147,11 @@ TEST_F(EventBlocksTest, RegisterBlocks)
106
147
EXPECT_CALL (m_engineMock, addCompileFunction (m_section.get (), " event_whenkeypressed" , &EventBlocks::compileWhenKeyPressed));
107
148
108
149
// Hat predicates
150
+ EXPECT_CALL (m_engineMock, addHatPredicateCompileFunction (m_section.get (), " event_whentouchingobject" , &EventBlocks::compileWhenTouchingObjectPredicate));
109
151
EXPECT_CALL (m_engineMock, addHatPredicateCompileFunction (m_section.get (), " event_whengreaterthan" , &EventBlocks::compileWhenGreaterThanPredicate));
110
152
111
153
// Inputs
154
+ EXPECT_CALL (m_engineMock, addInput (m_section.get (), " TOUCHINGOBJECTMENU" , EventBlocks::TOUCHINGOBJECTMENU));
112
155
EXPECT_CALL (m_engineMock, addInput (m_section.get (), " BROADCAST_INPUT" , EventBlocks::BROADCAST_INPUT));
113
156
EXPECT_CALL (m_engineMock, addInput (m_section.get (), " VALUE" , EventBlocks::VALUE));
114
157
@@ -125,6 +168,136 @@ TEST_F(EventBlocksTest, RegisterBlocks)
125
168
m_section->registerBlocks (&m_engineMock);
126
169
}
127
170
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
+
128
301
TEST_F (EventBlocksTest, WhenFlagClicked)
129
302
{
130
303
Compiler compiler (&m_engineMock);
0 commit comments