diff --git a/include/scratchcpp/iblocksection.h b/include/scratchcpp/iblocksection.h index d12159e4..92b71cfb 100644 --- a/include/scratchcpp/iblocksection.h +++ b/include/scratchcpp/iblocksection.h @@ -36,6 +36,9 @@ class LIBSCRATCHCPP_EXPORT IBlockSection /*! Override this method to register blocks. */ virtual void registerBlocks(IEngine *engine) = 0; + + /*! This method is called when a project is loaded. */ + virtual void onInit(IEngine *engine) { } }; } // namespace libscratchcpp diff --git a/src/blocks/soundblocks.cpp b/src/blocks/soundblocks.cpp index edd9659b..4543f6c3 100644 --- a/src/blocks/soundblocks.cpp +++ b/src/blocks/soundblocks.cpp @@ -33,6 +33,12 @@ void SoundBlocks::registerBlocks(IEngine *engine) engine->addInput(this, "VOLUME", VOLUME); } +void SoundBlocks::onInit(IEngine *engine) +{ + m_waitingSounds.clear(); + // TODO: Remove stopped threads from m_waitingSounds +} + bool SoundBlocks::compilePlayCommon(Compiler *compiler, bool untilDone, bool *byIndex) { Target *target = compiler->target(); diff --git a/src/blocks/soundblocks.h b/src/blocks/soundblocks.h index f2a1faed..866be118 100644 --- a/src/blocks/soundblocks.h +++ b/src/blocks/soundblocks.h @@ -36,6 +36,7 @@ class SoundBlocks : public IBlockSection std::string name() const override; void registerBlocks(IEngine *engine) override; + void onInit(IEngine *engine) override; static bool compilePlayCommon(Compiler *compiler, bool untilDone, bool *byIndex = nullptr); static void compilePlay(Compiler *compiler); diff --git a/src/engine/internal/engine.cpp b/src/engine/internal/engine.cpp index a810a99d..ed4ce7ef 100644 --- a/src/engine/internal/engine.cpp +++ b/src/engine/internal/engine.cpp @@ -864,6 +864,7 @@ void Engine::registerSection(std::shared_ptr section) m_sections[section] = std::make_unique(); section->registerBlocks(this); + section->onInit(this); } } diff --git a/test/engine/CMakeLists.txt b/test/engine/CMakeLists.txt index b8d97c5c..d669bda3 100644 --- a/test/engine/CMakeLists.txt +++ b/test/engine/CMakeLists.txt @@ -1,8 +1,6 @@ add_executable( engine_test engine_test.cpp - testsection.cpp - testsection.h ) target_link_libraries( diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp index e4c59e7a..b2d390fc 100644 --- a/test/engine/engine_test.cpp +++ b/test/engine/engine_test.cpp @@ -17,10 +17,10 @@ #include #include #include +#include #include #include "../common.h" -#include "testsection.h" #include "engine/internal/engine.h" #include "engine/internal/clock.h" @@ -77,7 +77,9 @@ TEST(EngineTest, Clear) auto broadcast2 = std::make_shared("", ""); engine.setBroadcasts({ broadcast1, broadcast2 }); - auto section = std::make_shared(); + auto section = std::make_shared(); + EXPECT_CALL(*section, registerBlocks); + EXPECT_CALL(*section, onInit); engine.registerSection(section); auto monitor1 = std::make_shared("", ""); @@ -126,7 +128,9 @@ TEST(EngineTest, CompileAndExecuteMonitors) m2->setSprite(sprite.get()); engine.setMonitors({ m1, m2 }); - auto section = std::make_shared(); + auto section = std::make_shared(); + EXPECT_CALL(*section, registerBlocks); + EXPECT_CALL(*section, onInit); engine.registerSection(section); engine.addCompileFunction(section.get(), m1->opcode(), [](Compiler *compiler) { compiler->addConstValue(5.4); }); engine.addCompileFunction(section.get(), m2->opcode(), [](Compiler *compiler) { compiler->addConstValue("test"); }); @@ -859,12 +863,19 @@ TEST(EngineTest, Sections) { Engine engine; - auto section1 = std::make_shared(); + auto section1 = std::make_shared(); + EXPECT_CALL(*section1, registerBlocks(&engine)); + EXPECT_CALL(*section1, onInit(&engine)); engine.registerSection(section1); - auto section2 = std::make_shared(); + auto section2 = std::make_shared(); + EXPECT_CALL(*section2, registerBlocks(&engine)); + EXPECT_CALL(*section2, onInit(&engine)); engine.registerSection(section2); + EXPECT_CALL(*section1, name()).WillOnce(Return("test")); + EXPECT_CALL(*section1, registerBlocks).Times(0); + EXPECT_CALL(*section1, onInit).Times(0); engine.registerSection(section1); // register existing section ASSERT_EQ(engine.registeredSections().size(), 2); @@ -908,15 +919,19 @@ TEST(EngineTest, CompileFunctions) { Engine engine; - auto section1 = std::make_shared(); + auto section1 = std::make_shared(); + EXPECT_CALL(*section1, registerBlocks); + EXPECT_CALL(*section1, onInit); engine.registerSection(section1); auto container1 = engine.blockSectionContainer(section1.get()); - auto section2 = std::make_shared(); + auto section2 = std::make_shared(); + EXPECT_CALL(*section2, registerBlocks); + EXPECT_CALL(*section2, onInit); engine.registerSection(section2); auto container2 = engine.blockSectionContainer(section2.get()); - TestSection section3; + BlockSectionMock section3; engine.addCompileFunction(section1.get(), "test1", &compileTest1); engine.addCompileFunction(section2.get(), "test2", &compileTest2); @@ -929,19 +944,123 @@ TEST(EngineTest, CompileFunctions) ASSERT_EQ(container2->resolveBlockCompileFunc("test2"), &compileTest2); } +TEST(EngineTest, HatPredicateCompileFunctions) +{ + Engine engine; + + auto section1 = std::make_shared(); + EXPECT_CALL(*section1, registerBlocks); + EXPECT_CALL(*section1, onInit); + engine.registerSection(section1); + auto container1 = engine.blockSectionContainer(section1.get()); + + auto section2 = std::make_shared(); + EXPECT_CALL(*section2, registerBlocks); + EXPECT_CALL(*section2, onInit); + engine.registerSection(section2); + auto container2 = engine.blockSectionContainer(section2.get()); + + BlockSectionMock section3; + + engine.addHatPredicateCompileFunction(section1.get(), "test1", &compileTest1); + engine.addHatPredicateCompileFunction(section2.get(), "test2", &compileTest2); + engine.addHatPredicateCompileFunction(section1.get(), "test1", &compileTest1); + engine.addHatPredicateCompileFunction(§ion3, "test1", &compileTest1); + + ASSERT_EQ(container1->resolveHatPredicateCompileFunc("test1"), &compileTest1); + ASSERT_EQ(container1->resolveHatPredicateCompileFunc("test2"), nullptr); + ASSERT_EQ(container2->resolveHatPredicateCompileFunc("test1"), nullptr); + ASSERT_EQ(container2->resolveHatPredicateCompileFunc("test2"), &compileTest2); +} + +TEST(EngineTest, MonitorNameFunctions) +{ + Engine engine; + + auto section1 = std::make_shared(); + EXPECT_CALL(*section1, registerBlocks); + EXPECT_CALL(*section1, onInit); + engine.registerSection(section1); + auto container1 = engine.blockSectionContainer(section1.get()); + + auto section2 = std::make_shared(); + EXPECT_CALL(*section2, registerBlocks); + EXPECT_CALL(*section2, onInit); + engine.registerSection(section2); + auto container2 = engine.blockSectionContainer(section2.get()); + + BlockSectionMock section3; + + MonitorNameFunc f1 = [](Block *) -> const std::string & { + static const std::string ret; + return ret; + }; + + MonitorNameFunc f2 = [](Block *) -> const std::string & { + static const std::string ret; + return ret; + }; + + engine.addMonitorNameFunction(section1.get(), "test1", f1); + engine.addMonitorNameFunction(section2.get(), "test2", f2); + engine.addMonitorNameFunction(section1.get(), "test1", f1); + engine.addMonitorNameFunction(§ion3, "test1", f1); + + ASSERT_EQ(container1->resolveMonitorNameFunc("test1"), f1); + ASSERT_EQ(container1->resolveMonitorNameFunc("test2"), nullptr); + ASSERT_EQ(container2->resolveMonitorNameFunc("test1"), nullptr); + ASSERT_EQ(container2->resolveMonitorNameFunc("test2"), f2); +} + +TEST(EngineTest, MonitorChangeFunctions) +{ + Engine engine; + + auto section1 = std::make_shared(); + EXPECT_CALL(*section1, registerBlocks); + EXPECT_CALL(*section1, onInit); + engine.registerSection(section1); + auto container1 = engine.blockSectionContainer(section1.get()); + + auto section2 = std::make_shared(); + EXPECT_CALL(*section2, registerBlocks); + EXPECT_CALL(*section2, onInit); + engine.registerSection(section2); + auto container2 = engine.blockSectionContainer(section2.get()); + + BlockSectionMock section3; + + MonitorChangeFunc f1 = [](Block *, const Value &) {}; + MonitorChangeFunc f2 = [](Block *, const Value &) {}; + + engine.addMonitorChangeFunction(section1.get(), "test1", f1); + engine.addMonitorChangeFunction(section2.get(), "test2", f2); + engine.addMonitorChangeFunction(section1.get(), "test1", f1); + engine.addMonitorChangeFunction(§ion3, "test1", f1); + + ASSERT_EQ(container1->resolveMonitorChangeFunc("test1"), f1); + ASSERT_EQ(container1->resolveMonitorChangeFunc("test2"), nullptr); + ASSERT_EQ(container2->resolveMonitorChangeFunc("test1"), nullptr); + ASSERT_EQ(container2->resolveMonitorChangeFunc("test2"), f2); +} + TEST(EngineTest, HatBlocks) { Engine engine; - auto section1 = std::make_shared(); + auto section1 = std::make_shared(); + EXPECT_CALL(*section1, registerBlocks); + EXPECT_CALL(*section1, onInit); engine.registerSection(section1); auto container1 = engine.blockSectionContainer(section1.get()); - auto section2 = std::make_shared(); + auto section2 = std::make_shared(); + EXPECT_CALL(*section2, registerBlocks); + EXPECT_CALL(*section2, onInit); engine.registerSection(section2); auto container2 = engine.blockSectionContainer(section2.get()); - TestSection section3; + BlockSectionMock section3; engine.addHatBlock(section1.get(), "test1"); engine.addHatBlock(section2.get(), "test2"); @@ -958,15 +1077,19 @@ TEST(EngineTest, Inputs) { Engine engine; - auto section1 = std::make_shared(); + auto section1 = std::make_shared(); + EXPECT_CALL(*section1, registerBlocks); + EXPECT_CALL(*section1, onInit); engine.registerSection(section1); auto container1 = engine.blockSectionContainer(section1.get()); - auto section2 = std::make_shared(); + auto section2 = std::make_shared(); + EXPECT_CALL(*section2, registerBlocks); + EXPECT_CALL(*section2, onInit); engine.registerSection(section2); auto container2 = engine.blockSectionContainer(section2.get()); - TestSection section3; + BlockSectionMock section3; engine.addInput(section1.get(), "VALUE1", 1); engine.addInput(section2.get(), "VALUE2", 2); @@ -985,15 +1108,19 @@ TEST(EngineTest, Fields) { Engine engine; - auto section1 = std::make_shared(); + auto section1 = std::make_shared(); + EXPECT_CALL(*section1, registerBlocks); + EXPECT_CALL(*section1, onInit); engine.registerSection(section1); auto container1 = engine.blockSectionContainer(section1.get()); - auto section2 = std::make_shared(); + auto section2 = std::make_shared(); + EXPECT_CALL(*section2, registerBlocks); + EXPECT_CALL(*section2, onInit); engine.registerSection(section2); auto container2 = engine.blockSectionContainer(section2.get()); - TestSection section3; + BlockSectionMock section3; engine.addField(section1.get(), "VALUE1", 1); engine.addField(section2.get(), "VALUE2", 2); @@ -1012,19 +1139,23 @@ TEST(EngineTest, FieldValues) { Engine engine; - auto section1 = std::make_shared(); + auto section1 = std::make_shared(); + EXPECT_CALL(*section1, registerBlocks); + EXPECT_CALL(*section1, onInit); engine.registerSection(section1); auto container1 = engine.blockSectionContainer(section1.get()); - auto section2 = std::make_shared(); + auto section2 = std::make_shared(); + EXPECT_CALL(*section2, registerBlocks); + EXPECT_CALL(*section2, onInit); engine.registerSection(section2); auto container2 = engine.blockSectionContainer(section2.get()); - TestSection section3; + BlockSectionMock section3; engine.addFieldValue(section1.get(), "value1", 1); engine.addFieldValue(section2.get(), "value2", 2); - engine.addFieldValue(section1.get(), "value1", 3); // change ID of existing field + engine.addFieldValue(section1.get(), "value1", 3); // change ID of existing field value engine.addFieldValue(§ion3, "value3", 4); ASSERT_EQ(container1->resolveFieldValue("value1"), 3); diff --git a/test/engine/testsection.cpp b/test/engine/testsection.cpp deleted file mode 100644 index 255e6938..00000000 --- a/test/engine/testsection.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#include "testsection.h" - -using namespace libscratchcpp; - -std::string TestSection::name() const -{ - return "Test"; -} - -void TestSection::registerBlocks(IEngine *engine) -{ -} diff --git a/test/engine/testsection.h b/test/engine/testsection.h deleted file mode 100644 index 78a0507d..00000000 --- a/test/engine/testsection.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -namespace libscratchcpp -{ - -class TestSection : public IBlockSection -{ - public: - std::string name() const override; - - void registerBlocks(IEngine *engine) override; -}; - -} // namespace libscratchcpp diff --git a/test/mocks/blocksectionmock.h b/test/mocks/blocksectionmock.h new file mode 100644 index 00000000..5050d83c --- /dev/null +++ b/test/mocks/blocksectionmock.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +using namespace libscratchcpp; + +class BlockSectionMock : public IBlockSection +{ + public: + MOCK_METHOD(std::string, name, (), (const, override)); + MOCK_METHOD(bool, categoryVisible, (), (const, override)); + + MOCK_METHOD(void, registerBlocks, (IEngine *), (override)); + MOCK_METHOD(void, onInit, (IEngine *), (override)); +};