Skip to content

Commit cb15d7d

Browse files
authored
Merge pull request #152 from scratchcpp/event_blocks_test
Add event blocks test
2 parents 7bff7a3 + d4724a8 commit cb15d7d

File tree

3 files changed

+252
-1
lines changed

3 files changed

+252
-1
lines changed

src/blocks/eventblocks.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ class EventBlocks : public IBlockSection
3232
static void compileBroadcastAndWait(Compiler *compiler);
3333
static void compileWhenBroadcastReceived(Compiler *compiler);
3434

35-
private:
3635
static unsigned int broadcast(VirtualMachine *vm);
3736
static unsigned int broadcastByIndex(VirtualMachine *vm);
3837
static unsigned int broadcastAndWait(VirtualMachine *vm);

test/blocks/CMakeLists.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,19 @@ target_link_libraries(
4545
)
4646

4747
gtest_discover_tests(operator_blocks_test)
48+
49+
# event_blocks_test
50+
add_executable(
51+
event_blocks_test
52+
event_blocks_test.cpp
53+
)
54+
55+
target_link_libraries(
56+
event_blocks_test
57+
GTest::gtest_main
58+
GTest::gmock_main
59+
scratchcpp
60+
scratchcpp_mocks
61+
)
62+
63+
gtest_discover_tests(event_blocks_test)

test/blocks/event_blocks_test.cpp

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
#include <scratchcpp/compiler.h>
2+
#include <scratchcpp/block.h>
3+
#include <scratchcpp/input.h>
4+
#include <scratchcpp/inputvalue.h>
5+
#include <scratchcpp/field.h>
6+
#include <scratchcpp/broadcast.h>
7+
#include <enginemock.h>
8+
9+
#include "../common.h"
10+
#include "blocks/eventblocks.h"
11+
#include "blocks/operatorblocks.h"
12+
#include "engine/engine.h"
13+
14+
using namespace libscratchcpp;
15+
16+
using ::testing::Return;
17+
18+
class EventBlocksTest : public testing::Test
19+
{
20+
public:
21+
void SetUp() override
22+
{
23+
m_section = std::make_unique<EventBlocks>();
24+
m_section->registerBlocks(&m_engine);
25+
26+
m_broadcast = std::make_shared<Broadcast>("", "test");
27+
m_engine.setBroadcasts({ m_broadcast });
28+
}
29+
30+
// For any event block
31+
std::shared_ptr<Block> createEventBlock(const std::string &id, const std::string &opcode) const { return std::make_shared<Block>(id, opcode); }
32+
33+
void addBroadcastInput(std::shared_ptr<Block> block, const std::string &name, EventBlocks::Inputs id, std::shared_ptr<Broadcast> broadcast) const
34+
{
35+
auto input = std::make_shared<Input>(name, Input::Type::Shadow);
36+
input->setPrimaryValue(broadcast->name());
37+
input->primaryValue()->setValuePtr(broadcast);
38+
input->primaryValue()->setType(InputValue::Type::Broadcast);
39+
input->setInputId(id);
40+
block->addInput(input);
41+
block->updateInputMap();
42+
}
43+
44+
void addObscuredInput(std::shared_ptr<Block> block, const std::string &name, EventBlocks::Inputs id, std::shared_ptr<Block> valueBlock) const
45+
{
46+
auto input = std::make_shared<Input>(name, Input::Type::ObscuredShadow);
47+
input->setValueBlock(valueBlock);
48+
input->setInputId(id);
49+
block->addInput(input);
50+
block->updateInputMap();
51+
}
52+
53+
void addBroadcastField(std::shared_ptr<Block> block, const std::string &name, EventBlocks::Fields id, std::shared_ptr<Broadcast> broadcast) const
54+
{
55+
auto field = std::make_shared<Field>(name, Value(), broadcast);
56+
field->setFieldId(id);
57+
block->addField(field);
58+
block->updateFieldMap();
59+
}
60+
61+
std::unique_ptr<IBlockSection> m_section;
62+
EngineMock m_engineMock;
63+
Engine m_engine;
64+
std::shared_ptr<Broadcast> m_broadcast;
65+
};
66+
67+
TEST_F(EventBlocksTest, Name)
68+
{
69+
ASSERT_EQ(m_section->name(), "Events");
70+
}
71+
72+
TEST_F(EventBlocksTest, CategoryVisible)
73+
{
74+
ASSERT_TRUE(m_section->categoryVisible());
75+
}
76+
77+
TEST_F(EventBlocksTest, RegisterBlocks)
78+
{
79+
// Blocks
80+
EXPECT_CALL(m_engineMock, addHatBlock(m_section.get(), "event_whenflagclicked")).Times(1);
81+
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_broadcast", &EventBlocks::compileBroadcast)).Times(1);
82+
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_broadcastandwait", &EventBlocks::compileBroadcastAndWait)).Times(1);
83+
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_whenbroadcastreceived", &EventBlocks::compileWhenBroadcastReceived)).Times(1);
84+
85+
// Inputs
86+
EXPECT_CALL(m_engineMock, addInput(m_section.get(), "BROADCAST_INPUT", EventBlocks::BROADCAST_INPUT)).Times(1);
87+
88+
// Fields
89+
EXPECT_CALL(m_engineMock, addField(m_section.get(), "BROADCAST_OPTION", EventBlocks::BROADCAST_OPTION));
90+
91+
m_section->registerBlocks(&m_engineMock);
92+
}
93+
94+
TEST_F(EventBlocksTest, Broadcast)
95+
{
96+
Compiler compiler(&m_engineMock);
97+
98+
// broadcast "test"
99+
auto block1 = createEventBlock("a", "event_broadcast");
100+
addBroadcastInput(block1, "BROADCAST_INPUT", EventBlocks::BROADCAST_INPUT, m_broadcast);
101+
102+
// broadcast <not <>>
103+
auto block2 = createEventBlock("b", "event_broadcast");
104+
auto notBlock = std::make_shared<Block>("c", "operator_not");
105+
notBlock->setCompileFunction(&OperatorBlocks::compileNot);
106+
addObscuredInput(block2, "BROADCAST_INPUT", EventBlocks::BROADCAST_INPUT, notBlock);
107+
108+
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(0));
109+
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcastByIndex)).WillOnce(Return(0));
110+
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcast)).WillOnce(Return(1));
111+
112+
compiler.init();
113+
compiler.setBlock(block1);
114+
EventBlocks::compileBroadcast(&compiler);
115+
compiler.setBlock(block2);
116+
EventBlocks::compileBroadcast(&compiler);
117+
compiler.end();
118+
119+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 1, vm::OP_HALT }));
120+
ASSERT_EQ(compiler.constValues().size(), 1);
121+
ASSERT_EQ(compiler.constValues()[0].toDouble(), 0);
122+
ASSERT_TRUE(compiler.variables().empty());
123+
ASSERT_TRUE(compiler.lists().empty());
124+
}
125+
126+
TEST_F(EventBlocksTest, BroadcastImpl)
127+
{
128+
static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT };
129+
static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 1, vm::OP_HALT };
130+
static BlockFunc functions[] = { &EventBlocks::broadcast, &EventBlocks::broadcastByIndex };
131+
static Value constValues[] = { "test", 0 };
132+
133+
VirtualMachine vm(nullptr, &m_engineMock, nullptr);
134+
vm.setFunctions(functions);
135+
vm.setConstValues(constValues);
136+
137+
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(0));
138+
EXPECT_CALL(m_engineMock, broadcast(0, &vm, false)).Times(1);
139+
140+
vm.setBytecode(bytecode1);
141+
vm.run();
142+
143+
ASSERT_EQ(vm.registerCount(), 0);
144+
145+
EXPECT_CALL(m_engineMock, broadcast(0, &vm, false)).Times(1);
146+
147+
vm.setBytecode(bytecode2);
148+
vm.run();
149+
150+
ASSERT_EQ(vm.registerCount(), 0);
151+
}
152+
153+
TEST_F(EventBlocksTest, BroadcastAndWait)
154+
{
155+
Compiler compiler(&m_engineMock);
156+
157+
// broadcast "test" and wait
158+
auto block1 = createEventBlock("a", "event_broadcastandwait");
159+
addBroadcastInput(block1, "BROADCAST_INPUT", EventBlocks::BROADCAST_INPUT, m_broadcast);
160+
161+
// broadcast <not <>> and wait
162+
auto block2 = createEventBlock("b", "event_broadcastandwait");
163+
auto notBlock = std::make_shared<Block>("c", "operator_not");
164+
notBlock->setCompileFunction(&OperatorBlocks::compileNot);
165+
addObscuredInput(block2, "BROADCAST_INPUT", EventBlocks::BROADCAST_INPUT, notBlock);
166+
167+
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(0));
168+
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcastByIndexAndWait)).WillOnce(Return(0));
169+
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::checkBroadcastByIndex)).WillOnce(Return(1));
170+
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::broadcastAndWait)).WillOnce(Return(2));
171+
EXPECT_CALL(m_engineMock, functionIndex(&EventBlocks::checkBroadcast)).WillOnce(Return(3));
172+
173+
compiler.init();
174+
compiler.setBlock(block1);
175+
EventBlocks::compileBroadcastAndWait(&compiler);
176+
compiler.setBlock(block2);
177+
EventBlocks::compileBroadcastAndWait(&compiler);
178+
compiler.end();
179+
180+
ASSERT_EQ(
181+
compiler.bytecode(),
182+
std::vector<unsigned int>(
183+
{ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_CONST, 0, vm::OP_EXEC, 1, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 3, vm::OP_HALT }));
184+
ASSERT_EQ(compiler.constValues().size(), 1);
185+
ASSERT_EQ(compiler.constValues()[0].toDouble(), 0);
186+
ASSERT_TRUE(compiler.variables().empty());
187+
ASSERT_TRUE(compiler.lists().empty());
188+
}
189+
190+
TEST_F(EventBlocksTest, BroadcastAndWaitImpl)
191+
{
192+
static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT };
193+
static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 1, vm::OP_HALT };
194+
static BlockFunc functions[] = { &EventBlocks::broadcastAndWait, &EventBlocks::broadcastByIndexAndWait };
195+
static Value constValues[] = { "test", 0 };
196+
197+
VirtualMachine vm(nullptr, &m_engineMock, nullptr);
198+
vm.setFunctions(functions);
199+
vm.setConstValues(constValues);
200+
201+
EXPECT_CALL(m_engineMock, findBroadcast("test")).WillOnce(Return(0));
202+
EXPECT_CALL(m_engineMock, broadcast(0, &vm, true)).Times(1);
203+
204+
vm.setBytecode(bytecode1);
205+
vm.run();
206+
207+
ASSERT_EQ(vm.registerCount(), 0);
208+
209+
EXPECT_CALL(m_engineMock, broadcast(0, &vm, true)).Times(1);
210+
211+
vm.setBytecode(bytecode2);
212+
vm.run();
213+
214+
ASSERT_EQ(vm.registerCount(), 0);
215+
}
216+
217+
TEST_F(EventBlocksTest, WhenBroadcastReceived)
218+
{
219+
Compiler compiler(&m_engineMock);
220+
221+
// when I receive "test"
222+
auto block1 = createEventBlock("a", "event_whenbroadcastreceived");
223+
addBroadcastField(block1, "BROADCAST_OPTION", EventBlocks::BROADCAST_OPTION, m_broadcast);
224+
225+
EXPECT_CALL(m_engineMock, addBroadcastScript(block1, m_broadcast)).Times(1);
226+
227+
compiler.init();
228+
compiler.setBlock(block1);
229+
EventBlocks::compileWhenBroadcastReceived(&compiler);
230+
compiler.end();
231+
232+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_HALT }));
233+
ASSERT_TRUE(compiler.constValues().empty());
234+
ASSERT_TRUE(compiler.variables().empty());
235+
ASSERT_TRUE(compiler.lists().empty());
236+
}

0 commit comments

Comments
 (0)