Skip to content

Commit bf43439

Browse files
authored
Merge pull request #40 from scratchcpp/unit_tests
Add unit tests
2 parents 68f5c3e + 1dd28b5 commit bf43439

37 files changed

+1412
-66
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- name: Install dependencies
2222
run: |
2323
sudo apt-get update
24-
sudo apt-get install -y nlohmann-json3-dev libutfcpp-dev libgd-dev
24+
sudo apt-get install -y nlohmann-json3-dev libutfcpp-dev libgd-dev xvfb libxcb-cursor0
2525
shell: bash
2626
- name: Install Qt
2727
uses: jurplel/install-qt-action@v3
@@ -31,5 +31,5 @@ jobs:
3131
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
3232

3333
- name: Build
34-
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j$(nproc --all)
34+
run: xvfb-run cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j$(nproc --all)
3535

.github/workflows/utests.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Unit tests
2+
3+
on:
4+
push:
5+
branches: '*'
6+
pull_request:
7+
branches: [ "master" ]
8+
9+
env:
10+
BUILD_TYPE: Debug
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v3
18+
with:
19+
submodules: 'recursive'
20+
21+
- name: Install dependencies
22+
run: |
23+
sudo apt-get update
24+
sudo apt-get install -y nlohmann-json3-dev libutfcpp-dev libgd-dev xvfb libxcb-cursor0
25+
shell: bash
26+
- name: Install Qt
27+
uses: jurplel/install-qt-action@v3
28+
with:
29+
version: '6.6.*'
30+
- name: Configure CMake
31+
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DSCRATCHCPPGUI_BUILD_UNIT_TESTS=ON
32+
33+
- name: Build
34+
run: xvfb-run cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j$(nproc --all)
35+
36+
- name: Run unit tests
37+
run: xvfb-run ctest --test-dir build -V
38+

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "libscratchcpp"]
22
path = libscratchcpp
33
url = https://github.com/scratchcpp/libscratchcpp
4+
[submodule "thirdparty/googletest"]
5+
path = thirdparty/googletest
6+
url = https://github.com/google/googletest

CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ set(CMAKE_AUTORCC ON)
99
set(CMAKE_CXX_STANDARD 17)
1010
set(CMAKE_CXX_STANDARD_REQUIRED ON)
1111

12+
option(SCRATCHCPPGUI_BUILD_UNIT_TESTS "Build unit tests" ON)
13+
1214
include(build/FindQt.cmake)
1315

1416
qt_standard_project_setup(REQUIRES 6.6)
@@ -18,11 +20,16 @@ set(QML_IMPORT_PATH "${QML_IMPORT_PATH};${PROJECT_SOURCE_DIR}/src/qml" PARENT_SC
1820

1921
target_compile_definitions(libscratchcpp-gui PRIVATE SCRATCHCPPGUI_LIBRARY)
2022

21-
target_link_libraries(libscratchcpp-gui PRIVATE Qt6::Gui Qt6::Qml Qt6::Quick)
23+
linkQt(libscratchcpp-gui)
2224

2325
include(build/SetUpLibscratchcpp.cmake)
2426
target_link_libraries(libscratchcpp-gui PRIVATE scratchcpp)
2527

2628
add_subdirectory(thirdparty/libqnanopainter)
2729
target_include_directories(libscratchcpp-gui PRIVATE thirdparty/libqnanopainter)
2830
target_link_libraries(libscratchcpp-gui PRIVATE qnanopainter)
31+
32+
if (SCRATCHCPPGUI_BUILD_UNIT_TESTS)
33+
enable_testing()
34+
add_subdirectory(test)
35+
endif()

ScratchCPPGui/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ qt_add_qml_module(libscratchcpp-gui
1717
stagemodel.h
1818
spritemodel.cpp
1919
spritemodel.h
20+
irenderedtarget.h
2021
renderedtarget.cpp
2122
renderedtarget.h
2223
targetpainter.cpp

ScratchCPPGui/irenderedtarget.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
3+
#pragma once
4+
5+
#include <qnanoquickitem.h>
6+
7+
class QBuffer;
8+
9+
namespace libscratchcpp
10+
{
11+
12+
class Costume;
13+
class IEngine;
14+
class Target;
15+
16+
} // namespace libscratchcpp
17+
18+
namespace scratchcppgui
19+
{
20+
21+
class StageModel;
22+
class SpriteModel;
23+
24+
class IRenderedTarget : public QNanoQuickItem
25+
{
26+
public:
27+
IRenderedTarget(QNanoQuickItem *parent = nullptr) :
28+
QNanoQuickItem(parent)
29+
{
30+
}
31+
32+
virtual ~IRenderedTarget() { }
33+
34+
virtual void loadProperties() = 0;
35+
virtual void loadCostume(libscratchcpp::Costume *costume) = 0;
36+
virtual void updateProperties() = 0;
37+
38+
virtual libscratchcpp::IEngine *engine() const = 0;
39+
virtual void setEngine(libscratchcpp::IEngine *newEngine) = 0;
40+
41+
virtual StageModel *stageModel() const = 0;
42+
virtual void setStageModel(StageModel *newStageModel) = 0;
43+
44+
virtual SpriteModel *spriteModel() const = 0;
45+
virtual void setSpriteModel(SpriteModel *newSpriteModel) = 0;
46+
47+
virtual libscratchcpp::Target *scratchTarget() const = 0;
48+
49+
virtual qreal width() const = 0;
50+
virtual void setWidth(qreal width) = 0;
51+
52+
virtual qreal height() const = 0;
53+
virtual void setHeight(qreal width) = 0;
54+
55+
virtual double costumeWidth() const = 0;
56+
virtual void setCostumeWidth(double width) = 0;
57+
58+
virtual double costumeHeight() const = 0;
59+
virtual void setCostumeHeight(double width) = 0;
60+
61+
virtual unsigned char *svgBitmap() const = 0;
62+
virtual QBuffer *bitmapBuffer() = 0;
63+
virtual const QString &bitmapUniqueKey() const = 0;
64+
65+
virtual void lockCostume() = 0;
66+
virtual void unlockCostume() = 0;
67+
68+
virtual bool mirrorHorizontally() const = 0;
69+
};
70+
71+
} // namespace scratchcppgui

ScratchCPPGui/projectloader.cpp

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ ProjectLoader::~ProjectLoader()
3434
if (m_loadThread.isRunning())
3535
m_loadThread.waitForFinished();
3636

37-
if (m_engine) {
37+
if (m_engine && m_eventLoopEnabled) {
3838
m_engine->stopEventLoop();
3939
m_eventLoop.waitForFinished();
4040
}
@@ -88,6 +88,12 @@ IEngine *ProjectLoader::engine() const
8888
return m_engine;
8989
}
9090

91+
// NOTE: This should be only used for testing
92+
void ProjectLoader::setEngine(libscratchcpp::IEngine *engine)
93+
{
94+
m_engine = engine;
95+
}
96+
9197
StageModel *ProjectLoader::stage()
9298
{
9399
if (m_loadThread.isRunning())
@@ -104,6 +110,11 @@ QQmlListProperty<SpriteModel> ProjectLoader::sprites()
104110
return QQmlListProperty<SpriteModel>(this, &m_sprites);
105111
}
106112

113+
const QList<SpriteModel *> &ProjectLoader::spriteList() const
114+
{
115+
return m_sprites;
116+
}
117+
107118
void ProjectLoader::start()
108119
{
109120
if (m_loadThread.isRunning())
@@ -198,7 +209,10 @@ void ProjectLoader::load()
198209

199210
// Run event loop
200211
m_engine->setSpriteFencingEnabled(false);
201-
m_eventLoop = QtConcurrent::run(&runEventLoop, m_engine);
212+
213+
if (m_eventLoopEnabled)
214+
m_eventLoop = QtConcurrent::run(&runEventLoop, m_engine);
215+
202216
m_engineMutex.unlock();
203217

204218
emit loadStatusChanged();
@@ -244,11 +258,13 @@ void ProjectLoader::setFps(double newFps)
244258
if (qFuzzyCompare(m_fps, newFps))
245259
return;
246260

247-
m_fps = newFps;
248261
m_engineMutex.lock();
249262

250-
if (m_engine)
251-
m_engine->setFps(m_fps);
263+
if (m_engine) {
264+
m_engine->setFps(newFps);
265+
m_fps = m_engine->fps();
266+
} else
267+
m_fps = newFps;
252268

253269
m_engineMutex.unlock();
254270
emit fpsChanged();
@@ -324,11 +340,13 @@ void ProjectLoader::setCloneLimit(int newCloneLimit)
324340
if (m_cloneLimit == newCloneLimit)
325341
return;
326342

327-
m_cloneLimit = newCloneLimit;
328343
m_engineMutex.lock();
329344

330-
if (m_engine)
331-
m_engine->setCloneLimit(m_cloneLimit);
345+
if (m_engine) {
346+
m_engine->setCloneLimit(newCloneLimit);
347+
m_cloneLimit = m_engine->cloneLimit();
348+
} else
349+
m_cloneLimit = newCloneLimit;
332350

333351
m_engineMutex.unlock();
334352
emit cloneLimitChanged();
@@ -353,3 +371,29 @@ void ProjectLoader::setSpriteFencing(bool newSpriteFencing)
353371
m_engineMutex.unlock();
354372
emit spriteFencingChanged();
355373
}
374+
375+
bool ProjectLoader::eventLoopEnabled() const
376+
{
377+
return m_eventLoopEnabled;
378+
}
379+
380+
void ProjectLoader::setEventLoopEnabled(bool newEventLoopEnabled)
381+
{
382+
if (m_eventLoopEnabled == newEventLoopEnabled)
383+
return;
384+
385+
m_eventLoopEnabled = newEventLoopEnabled;
386+
m_engineMutex.lock();
387+
388+
if (m_engine) {
389+
if (m_eventLoopEnabled)
390+
m_eventLoop = QtConcurrent::run(&runEventLoop, m_engine);
391+
else {
392+
m_engine->stopEventLoop();
393+
m_eventLoop.waitForFinished();
394+
}
395+
}
396+
397+
m_engineMutex.unlock();
398+
emit eventLoopEnabledChanged();
399+
}

ScratchCPPGui/projectloader.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class ProjectLoader : public QObject
2929
Q_PROPERTY(unsigned int stageHeight READ stageHeight WRITE setStageHeight NOTIFY stageHeightChanged)
3030
Q_PROPERTY(int cloneLimit READ cloneLimit WRITE setCloneLimit NOTIFY cloneLimitChanged)
3131
Q_PROPERTY(bool spriteFencing READ spriteFencing WRITE setSpriteFencing NOTIFY spriteFencingChanged)
32+
Q_PROPERTY(bool eventLoopEnabled READ eventLoopEnabled WRITE setEventLoopEnabled NOTIFY eventLoopEnabledChanged)
3233

3334
public:
3435
explicit ProjectLoader(QObject *parent = nullptr);
@@ -40,17 +41,16 @@ class ProjectLoader : public QObject
4041
bool loadStatus() const;
4142

4243
libscratchcpp::IEngine *engine() const;
44+
void setEngine(libscratchcpp::IEngine *engine);
4345

4446
StageModel *stage();
4547

4648
QQmlListProperty<SpriteModel> sprites();
49+
const QList<SpriteModel *> &spriteList() const;
4750

4851
Q_INVOKABLE void start();
4952
Q_INVOKABLE void stop();
5053

51-
unsigned int frameFinished() const;
52-
void setFrameFinished(unsigned int newFrameFinished);
53-
5454
double fps() const;
5555
void setFps(double newFps);
5656

@@ -69,6 +69,9 @@ class ProjectLoader : public QObject
6969
bool spriteFencing() const;
7070
void setSpriteFencing(bool newSpriteFencing);
7171

72+
bool eventLoopEnabled() const;
73+
void setEventLoopEnabled(bool newEventLoopEnabled);
74+
7275
signals:
7376
void fileNameChanged();
7477
void loadStatusChanged();
@@ -82,6 +85,7 @@ class ProjectLoader : public QObject
8285
void stageHeightChanged();
8386
void cloneLimitChanged();
8487
void spriteFencingChanged();
88+
void eventLoopEnabledChanged();
8589

8690
protected:
8791
void timerEvent(QTimerEvent *event) override;
@@ -108,6 +112,7 @@ class ProjectLoader : public QObject
108112
unsigned int m_stageHeight = 360;
109113
int m_cloneLimit = 300;
110114
bool m_spriteFencing = true;
115+
bool m_eventLoopEnabled = true;
111116
};
112117

113118
} // namespace scratchcppgui

0 commit comments

Comments
 (0)