Skip to content

Commit a115a54

Browse files
committed
Add methods for missing variable and list monitors
1 parent e98718e commit a115a54

File tree

6 files changed

+73
-86
lines changed

6 files changed

+73
-86
lines changed

include/scratchcpp/iengine.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,12 @@ class LIBSCRATCHCPP_EXPORT IEngine
360360
/*! Sets the list of monitors. */
361361
virtual void setMonitors(const std::vector<std::shared_ptr<Monitor>> &newMonitors) = 0;
362362

363+
/*! Creates a monitor for the given variable if it's missing and returns it. */
364+
virtual Monitor *createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId) = 0;
365+
366+
/*! Creates a monitor for the given list if it's missing and returns it. */
367+
virtual Monitor *createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId) = 0;
368+
363369
/*! Emits when a monitor is added. */
364370
virtual sigslot::signal<Monitor *> &monitorAdded() = 0;
365371

src/engine/internal/engine.cpp

Lines changed: 31 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
#include "clock.h"
3030
#include "audio/iaudioengine.h"
3131
#include "blocks/standardblocks.h"
32-
#include "blocks/variableblocks.h"
33-
#include "blocks/listblocks.h"
3432
#include "scratch/monitor_p.h"
3533

3634
using namespace libscratchcpp;
@@ -1231,9 +1229,6 @@ void Engine::setTargets(const std::vector<std::shared_ptr<Target>> &newTargets)
12311229

12321230
// Sort the executable targets by layer order
12331231
std::sort(m_executableTargets.begin(), m_executableTargets.end(), [](Target *t1, Target *t2) { return t1->layerOrder() < t2->layerOrder(); });
1234-
1235-
// Create missing monitors
1236-
createMissingMonitors();
12371232
}
12381233

12391234
Target *Engine::targetAt(int index) const
@@ -1401,9 +1396,38 @@ void Engine::setMonitors(const std::vector<std::shared_ptr<Monitor>> &newMonitor
14011396
m_monitors.push_back(monitor);
14021397
m_monitorAdded(monitor.get());
14031398
}
1399+
}
1400+
1401+
Monitor *Engine::createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId)
1402+
{
1403+
if (var->monitor())
1404+
return var->monitor();
1405+
else {
1406+
auto monitor = std::make_shared<Monitor>(var->id(), opcode);
1407+
auto field = std::make_shared<Field>(varFieldName, var->name(), var);
1408+
field->setFieldId(varFieldId);
1409+
monitor->block()->addField(field);
1410+
1411+
addVarOrListMonitor(monitor, var->target());
1412+
var->setMonitor(monitor.get());
1413+
return monitor.get();
1414+
}
1415+
}
14041416

1405-
// Create missing monitors
1406-
createMissingMonitors();
1417+
Monitor *Engine::createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId)
1418+
{
1419+
if (list->monitor())
1420+
return list->monitor();
1421+
else {
1422+
auto monitor = std::make_shared<Monitor>(list->id(), opcode);
1423+
auto field = std::make_shared<Field>(listFieldName, list->name(), list);
1424+
field->setFieldId(listFieldId);
1425+
monitor->block()->addField(field);
1426+
list->setMonitor(monitor.get());
1427+
1428+
addVarOrListMonitor(monitor, list->target());
1429+
return monitor.get();
1430+
}
14071431
}
14081432

14091433
sigslot::signal<Monitor *> &Engine::monitorAdded()
@@ -1797,60 +1821,6 @@ void Engine::removeExecutableClones()
17971821
m_executableTargets.erase(std::remove(m_executableTargets.begin(), m_executableTargets.end(), clone.get()), m_executableTargets.end());
17981822
}
17991823

1800-
void Engine::createMissingMonitors()
1801-
{
1802-
// This is called when setting targets and monitors because we never know in which order they're set
1803-
// If there aren't any targets yet, quit
1804-
if (m_targets.empty())
1805-
return;
1806-
1807-
for (auto target : m_targets) {
1808-
// Read all variables
1809-
const auto &variables = target->variables();
1810-
1811-
for (auto variable : variables) {
1812-
// Find the monitor for this variable
1813-
auto it = std::find_if(m_monitors.begin(), m_monitors.end(), [variable](std::shared_ptr<Monitor> monitor) {
1814-
// TODO: Move the opcode out of Engine
1815-
return monitor->opcode() == "data_variable" && monitor->id() == variable->id();
1816-
});
1817-
1818-
// If it doesn't exist, create it
1819-
if (it == m_monitors.end()) {
1820-
auto monitor = std::make_shared<Monitor>(variable->id(), "data_variable");
1821-
// TODO: Move field information out of Engine
1822-
auto field = std::make_shared<Field>("VARIABLE", variable->name(), variable);
1823-
field->setFieldId(VariableBlocks::VARIABLE);
1824-
monitor->block()->addField(field);
1825-
1826-
addVarOrListMonitor(monitor, target.get());
1827-
}
1828-
}
1829-
1830-
// Read all lists
1831-
const auto &lists = target->lists();
1832-
1833-
for (auto list : lists) {
1834-
// Find the monitor for this list
1835-
auto it = std::find_if(m_monitors.begin(), m_monitors.end(), [list](std::shared_ptr<Monitor> monitor) {
1836-
// TODO: Move the opcode out of Engine
1837-
return monitor->opcode() == "data_listcontents" && monitor->id() == list->id();
1838-
});
1839-
1840-
// If it doesn't exist, create it
1841-
if (it == m_monitors.end()) {
1842-
auto monitor = std::make_shared<Monitor>(list->id(), "data_listcontents");
1843-
// TODO: Move field information out of Engine
1844-
auto field = std::make_shared<Field>("LIST", list->name(), list);
1845-
field->setFieldId(ListBlocks::LIST);
1846-
monitor->block()->addField(field);
1847-
1848-
addVarOrListMonitor(monitor, target.get());
1849-
}
1850-
}
1851-
}
1852-
}
1853-
18541824
void Engine::addVarOrListMonitor(std::shared_ptr<Monitor> monitor, Target *target)
18551825
{
18561826
if (!target->isStage())

src/engine/internal/engine.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ class Engine : public IEngine
149149

150150
const std::vector<std::shared_ptr<Monitor>> &monitors() const override;
151151
void setMonitors(const std::vector<std::shared_ptr<Monitor>> &newMonitors) override;
152+
Monitor *createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId) override;
153+
Monitor *createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId) override;
152154
sigslot::signal<Monitor *> &monitorAdded() override;
153155
sigslot::signal<Monitor *, IMonitorHandler *> &monitorRemoved() override;
154156

@@ -199,7 +201,6 @@ class Engine : public IEngine
199201
void finalize();
200202
void deleteClones();
201203
void removeExecutableClones();
202-
void createMissingMonitors();
203204
void addVarOrListMonitor(std::shared_ptr<Monitor> monitor, Target *target);
204205
std::shared_ptr<Block> getBlock(const std::string &id, Target *target);
205206
std::shared_ptr<Variable> getVariable(const std::string &id, Target *target);

test/engine/engine_test.cpp

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
#include "engine/internal/clock.h"
3030

3131
// TODO: Remove this
32-
#include "blocks/variableblocks.h"
33-
#include "blocks/listblocks.h"
3432
#include "blocks/eventblocks.h"
3533

3634
using namespace libscratchcpp;
@@ -1708,6 +1706,14 @@ TEST(EngineTest, Monitors)
17081706

17091707
TEST(EngineTest, CreateMissingMonitors)
17101708
{
1709+
static constexpr const char *VARIABLE_OPCODE = "data_variable";
1710+
static constexpr const char *VARIABLE_FIELD_NAME = "VARIABLE";
1711+
static constexpr int VARIABLE_FIELD_ID = 1;
1712+
1713+
static constexpr const char *LIST_OPCODE = "data_listcontents";
1714+
static constexpr const char *LIST_FIELD_NAME = "LIST";
1715+
static constexpr int LIST_FIELD_ID = 2;
1716+
17111717
auto var1 = std::make_shared<Variable>("a", "var1");
17121718
auto var2 = std::make_shared<Variable>("b", "var2");
17131719
auto var3 = std::make_shared<Variable>("c", "var3");
@@ -1730,6 +1736,8 @@ TEST(EngineTest, CreateMissingMonitors)
17301736
auto m3 = std::make_shared<Monitor>(list2->id(), "data_listcontents");
17311737

17321738
auto checkVariableMonitor = [](std::shared_ptr<Monitor> monitor, std::shared_ptr<Variable> var) {
1739+
ASSERT_EQ(var->monitor(), monitor.get());
1740+
17331741
auto block = monitor->block();
17341742
ASSERT_EQ(monitor->id(), var->id());
17351743
ASSERT_EQ(monitor->opcode(), "data_variable");
@@ -1738,8 +1746,8 @@ TEST(EngineTest, CreateMissingMonitors)
17381746
ASSERT_EQ(block->fields().size(), 1);
17391747

17401748
auto field = block->fieldAt(0);
1741-
ASSERT_EQ(field->name(), "VARIABLE");
1742-
ASSERT_EQ(field->fieldId(), VariableBlocks::VARIABLE);
1749+
ASSERT_EQ(field->name(), VARIABLE_FIELD_NAME);
1750+
ASSERT_EQ(field->fieldId(), VARIABLE_FIELD_ID);
17431751
ASSERT_EQ(field->value(), var->name());
17441752
ASSERT_EQ(field->valuePtr(), var);
17451753

@@ -1750,6 +1758,8 @@ TEST(EngineTest, CreateMissingMonitors)
17501758
};
17511759

17521760
auto checkListMonitor = [](std::shared_ptr<Monitor> monitor, std::shared_ptr<List> list) {
1761+
ASSERT_EQ(list->monitor(), monitor.get());
1762+
17531763
auto block = monitor->block();
17541764
ASSERT_EQ(monitor->id(), list->id());
17551765
ASSERT_EQ(monitor->opcode(), "data_listcontents");
@@ -1758,8 +1768,8 @@ TEST(EngineTest, CreateMissingMonitors)
17581768
ASSERT_EQ(block->fields().size(), 1);
17591769

17601770
auto field = block->fieldAt(0);
1761-
ASSERT_EQ(field->name(), "LIST");
1762-
ASSERT_EQ(field->fieldId(), ListBlocks::LIST);
1771+
ASSERT_EQ(field->name(), LIST_FIELD_NAME);
1772+
ASSERT_EQ(field->fieldId(), LIST_FIELD_ID);
17631773
ASSERT_EQ(field->value(), list->name());
17641774
ASSERT_EQ(field->valuePtr(), list);
17651775

@@ -1769,40 +1779,34 @@ TEST(EngineTest, CreateMissingMonitors)
17691779
ASSERT_EQ(monitor->sprite(), dynamic_cast<Sprite *>(list->target()));
17701780
};
17711781

1772-
// Set monitors after setting targets
17731782
{
17741783
Engine engine;
17751784
engine.setTargets({ target1, target2 });
17761785
engine.setMonitors({ m1, m2, m3 });
17771786

17781787
const auto &monitors = engine.monitors();
1779-
ASSERT_EQ(monitors.size(), 7);
1788+
ASSERT_EQ(monitors.size(), 3);
17801789
ASSERT_EQ(monitors[0], m1);
17811790
ASSERT_EQ(monitors[1], m2);
17821791
ASSERT_EQ(monitors[2], m3);
1783-
checkVariableMonitor(monitors[3], var2);
1784-
checkListMonitor(monitors[4], list1);
1785-
checkVariableMonitor(monitors[5], var4);
1786-
checkVariableMonitor(monitors[6], var5);
1787-
}
17881792

1789-
// Set monitors before setting targets
1790-
{
1791-
Engine engine;
1792-
engine.setMonitors({ m1, m2, m3 });
1793-
engine.setTargets({ target1, target2 });
1793+
engine.createVariableMonitor(var2, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1794+
engine.createListMonitor(list1, LIST_OPCODE, LIST_FIELD_NAME, LIST_FIELD_ID);
1795+
engine.createVariableMonitor(var4, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1796+
engine.createVariableMonitor(var5, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
17941797

1795-
const auto &monitors = engine.monitors();
17961798
ASSERT_EQ(monitors.size(), 7);
1797-
ASSERT_EQ(monitors[0], m1);
1798-
ASSERT_EQ(monitors[1], m2);
1799-
ASSERT_EQ(monitors[2], m3);
18001799
checkVariableMonitor(monitors[3], var2);
18011800
checkListMonitor(monitors[4], list1);
18021801
checkVariableMonitor(monitors[5], var4);
18031802
checkVariableMonitor(monitors[6], var5);
18041803
}
18051804

1805+
var2->setMonitor(nullptr);
1806+
list1->setMonitor(nullptr);
1807+
var4->setMonitor(nullptr);
1808+
var5->setMonitor(nullptr);
1809+
18061810
{
18071811
Engine engine;
18081812
AddRemoveMonitorMock addMonitorMock;
@@ -1816,7 +1820,11 @@ TEST(EngineTest, CreateMissingMonitors)
18161820

18171821
Monitor *m4, *m5, *m6, *m7;
18181822
EXPECT_CALL(addMonitorMock, monitorAdded(_)).WillOnce(SaveArg<0>(&m4)).WillOnce(SaveArg<0>(&m5)).WillOnce(SaveArg<0>(&m6)).WillOnce(SaveArg<0>(&m7));
1819-
engine.setTargets({ target1, target2 });
1823+
1824+
engine.createVariableMonitor(var2, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1825+
engine.createListMonitor(list1, LIST_OPCODE, LIST_FIELD_NAME, LIST_FIELD_ID);
1826+
engine.createVariableMonitor(var4, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1827+
engine.createVariableMonitor(var5, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
18201828

18211829
const auto &monitors = engine.monitors();
18221830
ASSERT_EQ(monitors.size(), 7);

test/load_project/load_project_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ TEST(LoadProjectTest, LoadTestProject)
454454

455455
// Monitors
456456
const auto &monitors = engine->monitors();
457-
ASSERT_EQ(monitors.size(), 11);
457+
ASSERT_EQ(monitors.size(), 10);
458458

459459
// list1
460460
auto monitor = monitors[0];

test/mocks/enginemock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ class EngineMock : public IEngine
128128

129129
MOCK_METHOD(const std::vector<std::shared_ptr<Monitor>> &, monitors, (), (const, override));
130130
MOCK_METHOD(void, setMonitors, (const std::vector<std::shared_ptr<Monitor>> &), (override));
131+
MOCK_METHOD(Monitor *, createVariableMonitor, (std::shared_ptr<Variable>, const std::string &, const std::string &, int), (override));
132+
MOCK_METHOD(Monitor *, createListMonitor, (std::shared_ptr<List>, const std::string &, const std::string &, int), (override));
131133
MOCK_METHOD(sigslot::signal<Monitor *> &, monitorAdded, (), (override));
132134
MOCK_METHOD((sigslot::signal<Monitor *, IMonitorHandler *> &), monitorRemoved, (), (override));
133135

0 commit comments

Comments
 (0)