Skip to content

Commit 148f0da

Browse files
authored
Merge pull request #202 from scratchcpp/timer_blocks
Implement timer blocks
2 parents d9cefc2 + ee52ef5 commit 148f0da

File tree

5 files changed

+165
-1
lines changed

5 files changed

+165
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ int main(int argc, char **argv) {
130130
- [x] Variables (monitors are not implemented yet)
131131
- [x] Lists (monitors are not implemented yet)
132132
- [x] Clones
133-
- [ ] Timer
133+
- [x] Timer
134134
- [ ] API for monitors
135135
- [ ] Project metadata
136136
- [ ] Turbo mode

src/blocks/sensingblocks.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
// SPDX-License-Identifier: Apache-2.0
22

3+
#include <scratchcpp/virtualmachine.h>
4+
#include <scratchcpp/compiler.h>
5+
#include <scratchcpp/iengine.h>
6+
#include <scratchcpp/itimer.h>
37
#include "sensingblocks.h"
48

59
using namespace libscratchcpp;
@@ -11,4 +15,29 @@ std::string SensingBlocks::name() const
1115

1216
void SensingBlocks::registerBlocks(IEngine *engine)
1317
{
18+
// Blocks
19+
engine->addCompileFunction(this, "sensing_timer", &compileTimer);
20+
engine->addCompileFunction(this, "sensing_resettimer", &compileResetTimer);
21+
}
22+
23+
void SensingBlocks::compileTimer(Compiler *compiler)
24+
{
25+
compiler->addFunctionCall(&timer);
26+
}
27+
28+
void SensingBlocks::compileResetTimer(Compiler *compiler)
29+
{
30+
compiler->addFunctionCall(&resetTimer);
31+
}
32+
33+
unsigned int SensingBlocks::timer(VirtualMachine *vm)
34+
{
35+
vm->addReturnValue(vm->engine()->timer()->value());
36+
return 0;
37+
}
38+
39+
unsigned int SensingBlocks::resetTimer(VirtualMachine *vm)
40+
{
41+
vm->engine()->timer()->reset();
42+
return 0;
1443
}

src/blocks/sensingblocks.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ class SensingBlocks : public IBlockSection
1414
std::string name() const override;
1515

1616
void registerBlocks(IEngine *engine) override;
17+
18+
static void compileTimer(Compiler *compiler);
19+
static void compileResetTimer(Compiler *compiler);
20+
21+
static unsigned int timer(VirtualMachine *vm);
22+
static unsigned int resetTimer(VirtualMachine *vm);
1723
};
1824

1925
} // namespace libscratchcpp

test/blocks/CMakeLists.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,19 @@ target_link_libraries(
9393
)
9494

9595
gtest_discover_tests(custom_blocks_test)
96+
97+
# sensing_blocks_test
98+
add_executable(
99+
sensing_blocks_test
100+
sensing_blocks_test.cpp
101+
)
102+
103+
target_link_libraries(
104+
sensing_blocks_test
105+
GTest::gtest_main
106+
GTest::gmock_main
107+
scratchcpp
108+
scratchcpp_mocks
109+
)
110+
111+
gtest_discover_tests(sensing_blocks_test)
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#include <scratchcpp/compiler.h>
2+
#include <scratchcpp/block.h>
3+
#include <enginemock.h>
4+
#include <timermock.h>
5+
6+
#include "../common.h"
7+
#include "blocks/sensingblocks.h"
8+
#include "engine/internal/engine.h"
9+
10+
using namespace libscratchcpp;
11+
12+
using ::testing::Return;
13+
14+
class SensingBlocksTest : public testing::Test
15+
{
16+
public:
17+
void SetUp() override
18+
{
19+
m_section = std::make_unique<SensingBlocks>();
20+
m_section->registerBlocks(&m_engine);
21+
}
22+
23+
std::unique_ptr<IBlockSection> m_section;
24+
EngineMock m_engineMock;
25+
Engine m_engine;
26+
TimerMock m_timerMock;
27+
};
28+
29+
TEST_F(SensingBlocksTest, Name)
30+
{
31+
ASSERT_EQ(m_section->name(), "Sensing");
32+
}
33+
34+
TEST_F(SensingBlocksTest, CategoryVisible)
35+
{
36+
ASSERT_TRUE(m_section->categoryVisible());
37+
}
38+
39+
TEST_F(SensingBlocksTest, RegisterBlocks)
40+
{
41+
// Blocks
42+
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "sensing_timer", &SensingBlocks::compileTimer)).Times(1);
43+
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "sensing_resettimer", &SensingBlocks::compileResetTimer)).Times(1);
44+
45+
m_section->registerBlocks(&m_engineMock);
46+
}
47+
48+
TEST_F(SensingBlocksTest, Timer)
49+
{
50+
Compiler compiler(&m_engineMock);
51+
52+
auto block = std::make_shared<Block>("a", "sensing_timer");
53+
54+
EXPECT_CALL(m_engineMock, functionIndex(&SensingBlocks::timer)).WillOnce(Return(0));
55+
56+
compiler.init();
57+
compiler.setBlock(block);
58+
SensingBlocks::compileTimer(&compiler);
59+
compiler.end();
60+
61+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_EXEC, 0, vm::OP_HALT }));
62+
}
63+
64+
TEST_F(SensingBlocksTest, TimerImpl)
65+
{
66+
static unsigned int bytecode[] = { vm::OP_START, vm::OP_EXEC, 0, vm::OP_HALT };
67+
static BlockFunc functions[] = { &SensingBlocks::timer };
68+
69+
VirtualMachine vm(nullptr, &m_engineMock, nullptr);
70+
vm.setFunctions(functions);
71+
72+
EXPECT_CALL(m_engineMock, timer()).WillOnce(Return(&m_timerMock));
73+
EXPECT_CALL(m_timerMock, value()).WillOnce(Return(2.375));
74+
75+
vm.setBytecode(bytecode);
76+
vm.run();
77+
78+
ASSERT_EQ(vm.registerCount(), 1);
79+
ASSERT_EQ(vm.getInput(0, 1)->toDouble(), 2.375);
80+
}
81+
82+
TEST_F(SensingBlocksTest, ResetTimer)
83+
{
84+
Compiler compiler(&m_engineMock);
85+
86+
auto block = std::make_shared<Block>("a", "sensing_resettimer");
87+
88+
EXPECT_CALL(m_engineMock, functionIndex(&SensingBlocks::resetTimer)).WillOnce(Return(0));
89+
90+
compiler.init();
91+
compiler.setBlock(block);
92+
SensingBlocks::compileResetTimer(&compiler);
93+
compiler.end();
94+
95+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_EXEC, 0, vm::OP_HALT }));
96+
}
97+
98+
TEST_F(SensingBlocksTest, ResetTimerImpl)
99+
{
100+
static unsigned int bytecode[] = { vm::OP_START, vm::OP_EXEC, 0, vm::OP_HALT };
101+
static BlockFunc functions[] = { &SensingBlocks::resetTimer };
102+
103+
VirtualMachine vm(nullptr, &m_engineMock, nullptr);
104+
vm.setFunctions(functions);
105+
106+
EXPECT_CALL(m_engineMock, timer()).WillOnce(Return(&m_timerMock));
107+
EXPECT_CALL(m_timerMock, reset()).Times(1);
108+
109+
vm.setBytecode(bytecode);
110+
vm.run();
111+
112+
ASSERT_EQ(vm.registerCount(), 0);
113+
}

0 commit comments

Comments
 (0)