Compare commits
10 commits
243af95a3b
...
801b00ad97
Author | SHA1 | Date | |
---|---|---|---|
801b00ad97 | |||
4940b07403 | |||
2f09c6eb9c | |||
3521f50d1b | |||
11df6595c0 | |||
44c28b6825 | |||
92ab9f6fb9 | |||
b117f3cd4d | |||
d086cf629b | |||
143d3769c7 |
31 changed files with 6320 additions and 35 deletions
|
@ -25,4 +25,6 @@ add_subdirectory(client)
|
|||
add_subdirectory(editor)
|
||||
|
||||
|
||||
install(FILES $<TARGET_RUNTIME_DLLS:editor> TYPE BIN)
|
||||
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests )
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
|
|
|
@ -43,6 +43,8 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
fs::create_directories(outPath.parent_path()); // Make sure generated dir exists before we try writing to it
|
||||
|
||||
// We write to a special log file instead of stdout/stderr to
|
||||
// 1. avoid confusion
|
||||
// 2. prevent MSBuild from reading the word "error" and detecting there's a problem with the program (there isn't)
|
||||
|
@ -74,8 +76,6 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
|
|||
data::analyzeClasses(cursor, srcRootStr, &dataAnlyState);
|
||||
enum_::analyzeClasses(cursor, srcRootStr, &enumAnlyState);
|
||||
|
||||
fs::create_directories(outPath.parent_path()); // Make sure generated dir exists before we try writing to it
|
||||
|
||||
printf("[AUTOGEN] Generating file %s...\n", relpathStr.c_str());
|
||||
std::ofstream outStream(outPathStr);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include "logger.h"
|
||||
#include "objects/part/part.h"
|
||||
#include "panic.h"
|
||||
#include "rendering/renderer.h"
|
||||
#include "common.h"
|
||||
#include "version.h"
|
||||
|
@ -37,7 +39,13 @@ int main() {
|
|||
glfwSetFramebufferSizeCallback(window, resizeCallback);
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glewInit();
|
||||
int version = gladLoadGL(glfwGetProcAddress);
|
||||
if (version == 0) {
|
||||
Logger::fatalError("Failed to initialize OpenGL context");
|
||||
panic();
|
||||
} else {
|
||||
Logger::debugf("Initialized GL context version %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
|
||||
}
|
||||
|
||||
gDataModel->Init();
|
||||
renderInit(1200, 900);
|
||||
|
@ -83,7 +91,7 @@ int main() {
|
|||
}
|
||||
|
||||
void errorCatcher(int id, const char* str) {
|
||||
Logger::fatalErrorf("GLFW Error: [{}] {}", id, str);
|
||||
Logger::fatalErrorf("GLFW Error: [%d] %s", id, str);
|
||||
}
|
||||
|
||||
float lastTime;
|
||||
|
|
|
@ -3,6 +3,8 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/deps.cmake)
|
|||
## Sources
|
||||
set(SOURCES
|
||||
src/stb.cpp
|
||||
src/glad.cpp
|
||||
|
||||
src/ptr_helpers.h
|
||||
src/enum/part.h
|
||||
src/enum/surface.cpp
|
||||
|
@ -195,8 +197,8 @@ list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp)
|
|||
add_library(openblocks STATIC ${SOURCES})
|
||||
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
||||
target_link_directories(openblocks PUBLIC ${LUAJIT_LIBRARY_DIRS})
|
||||
target_link_libraries(openblocks libglew_static reactphysics3d pugixml::pugixml Freetype::Freetype glm::glm libluajit ${LuaJIT_LIBRARIES})
|
||||
target_include_directories(openblocks PUBLIC "src" "../include" ${ReactPhysics3D_SOURCE_DIR}/include ${LUAJIT_INCLUDE_DIRS} ${stb_SOURCE_DIR} ${glew_SOURCE_DIR}/include)
|
||||
target_link_libraries(openblocks reactphysics3d pugixml::pugixml Freetype::Freetype glm::glm libluajit ${LuaJIT_LIBRARIES})
|
||||
target_include_directories(openblocks PUBLIC "src" "../include" "${CMAKE_SOURCE_DIR}/external/glad" ${ReactPhysics3D_SOURCE_DIR}/include ${LUAJIT_INCLUDE_DIRS} ${stb_SOURCE_DIR})
|
||||
add_dependencies(openblocks autogen_build autogen)
|
||||
|
||||
# Windows-specific dependencies
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
|
||||
include(CPM)
|
||||
|
||||
CPMAddPackage("gh:Perlmint/glew-cmake#glew-cmake-2.2.0")
|
||||
# Some packages will build helper binaries. This keeps them out of our own build output
|
||||
set (PREV_BIN_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||
unset (CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||
|
||||
CPMAddPackage("gh:g-truc/glm#1.0.1")
|
||||
CPMAddPackage(NAME reactphysics3d GITHUB_REPOSITORY "DanielChappuis/reactphysics3d" VERSION 0.10.2 PATCHES ${CMAKE_SOURCE_DIR}/patches/std_chrono.patch)
|
||||
# https://github.com/StereoKit/StereoKit/blob/0be056efebcee5e58ad1438f4cf6dfdb942f6cf9/CMakeLists.txt#L205
|
||||
|
@ -13,6 +16,7 @@ CPMAddPackage(
|
|||
GIT_REPOSITORY https://github.com/aseprite/freetype2.git
|
||||
GIT_TAG VER-2-10-0
|
||||
VERSION 2.10.0
|
||||
PATCHES ${CMAKE_SOURCE_DIR}/patches/freetype_cmakever.patch
|
||||
)
|
||||
|
||||
if (freetype_ADDED)
|
||||
|
@ -21,4 +25,6 @@ endif()
|
|||
|
||||
CPMAddPackage("gh:nothings/stb#8cfb1605c02aee9fb6eb5d8ea559017745bd9a16") # 2.14
|
||||
CPMAddPackage("gh:WohlSoft/LuaJIT#a5da8f4a31972b74254f00969111b8b7a07cf584") # v2.1
|
||||
set(LUAJIT_INCLUDE_DIRS ${LuaJIT_SOURCE_DIR}/src)
|
||||
set(LUAJIT_INCLUDE_DIRS ${LuaJIT_SOURCE_DIR}/src)
|
||||
|
||||
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PREV_BIN_PATH})
|
2
core/src/glad.cpp
Normal file
2
core/src/glad.cpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define GLAD_GL_IMPLEMENTATION
|
||||
#include <glad/gl.h>
|
|
@ -58,7 +58,7 @@ std::optional<HandleFace> raycastHandle(rp3d::Ray ray) {
|
|||
// Implement manual detection via boxes instead of... this shit
|
||||
// This code also hardly works, and is not good at all... Hooo nope.
|
||||
rp3d::RigidBody* body = world->createRigidBody(CFrame::IDENTITY + cframe.Position());
|
||||
body->addCollider(common.createBoxShape(cframe.Rotation() * Vector3(handleSize(face) / 2.f)), rp3d::Transform::identity());
|
||||
body->addCollider(common.createBoxShape((cframe.Rotation() * Vector3(handleSize(face) / 2.f)).Abs()), rp3d::Transform::identity());
|
||||
|
||||
rp3d::RaycastInfo info;
|
||||
if (body->raycast(ray, info)) {
|
||||
|
|
|
@ -10,18 +10,26 @@
|
|||
static std::ofstream logStream;
|
||||
static std::vector<Logger::LogListener> logListeners;
|
||||
std::string Logger::currentLogDir = "NULL";
|
||||
static std::stringstream* rawOutputBuffer = nullptr;
|
||||
|
||||
void Logger::init() {
|
||||
initProgramLogsDir();
|
||||
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
const auto nows = std::chrono::floor<std::chrono::seconds>(now);
|
||||
|
||||
std::string fileName = std::format("log_{0:%Y%m%d}_{0:%H%M%S}.txt", now);
|
||||
std::string fileName = std::format("log_{0:%Y%m%d}_{0:%H%M%S}.txt", nows);
|
||||
|
||||
logStream = std::ofstream(currentLogDir = (getProgramLogsDir() + "/" + fileName));
|
||||
Logger::debug("Logger initialized");
|
||||
}
|
||||
|
||||
// Initializes the logger in a "void" mode for testing.
|
||||
// It is not necessary to call Logger::finish
|
||||
void Logger::initTest(std::stringstream* outputBuffer) {
|
||||
rawOutputBuffer = outputBuffer;
|
||||
}
|
||||
|
||||
void Logger::finish() {
|
||||
Logger::debug("Closing logger...");
|
||||
logStream.close();
|
||||
|
@ -41,6 +49,7 @@ void Logger::log(std::string message, Logger::LogLevel logLevel, ScriptSource so
|
|||
|
||||
logStream << formattedLogLine << std::endl;
|
||||
printf("%s\n", formattedLogLine.c_str());
|
||||
if (rawOutputBuffer != nullptr) *rawOutputBuffer << logLevelStr << ": " << message << "\n";
|
||||
|
||||
for (Logger::LogListener listener : logListeners) {
|
||||
listener(logLevel, message, source);
|
||||
|
@ -53,4 +62,8 @@ void Logger::log(std::string message, Logger::LogLevel logLevel, ScriptSource so
|
|||
|
||||
void Logger::addLogListener(Logger::LogListener listener) {
|
||||
logListeners.push_back(listener);
|
||||
}
|
||||
|
||||
void Logger::resetLogListeners() {
|
||||
logListeners.clear();
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
class Script;
|
||||
|
@ -26,8 +27,10 @@ namespace Logger {
|
|||
extern std::string currentLogDir;
|
||||
|
||||
void init();
|
||||
void initTest(std::stringstream* out); // Testing only!
|
||||
void finish();
|
||||
void addLogListener(LogListener);
|
||||
void resetLogListeners(); // Testing only!
|
||||
|
||||
void log(std::string message, LogLevel logLevel, ScriptSource source = {});
|
||||
inline void info(std::string message) { log(message, LogLevel::INFO); }
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#include "rendering/shader.h"
|
||||
#include "rendering/texture.h"
|
||||
#include "timeutil.h"
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/ext/vector_float4.hpp>
|
||||
#include <string>
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
#include "panic.h"
|
||||
#include "rendering/shader.h"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <memory>
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include "mesh.h"
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#include "mesh2d.h"
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <glm/ext.hpp>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <fstream>
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "logger.h"
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "logger.h"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "texture.h"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "panic.h"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "texture3d.h"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glad/gl.h>
|
||||
#include <stb_image.h>
|
||||
|
||||
#include "panic.h"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "torus.h"
|
||||
#include <cmath>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
|
||||
#define PI 3.1415926535f
|
||||
|
||||
|
|
|
@ -4,9 +4,15 @@
|
|||
|
||||
tu_time_t TIME_STARTED_MICROS = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch().count();
|
||||
|
||||
static tu_time_t timeOverride = -1UL;
|
||||
|
||||
tu_time_t tu_clock_micros() {
|
||||
if (timeOverride != -1UL) return timeOverride;
|
||||
tu_time_t now = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch().count();;
|
||||
|
||||
return now - TIME_STARTED_MICROS;
|
||||
}
|
||||
|
||||
void tu_set_override(tu_time_t destTime) {
|
||||
timeOverride = destTime;
|
||||
}
|
|
@ -5,4 +5,8 @@
|
|||
typedef uint64_t tu_time_t;
|
||||
|
||||
// Provides a high-accuracy time since the program started in microseconds (via std::chrono)
|
||||
tu_time_t tu_clock_micros();
|
||||
tu_time_t tu_clock_micros();
|
||||
|
||||
#ifdef TU_TIME_EXPOSE_TEST
|
||||
void tu_set_override(tu_time_t destTime);
|
||||
#endif
|
2
deps.txt
2
deps.txt
|
@ -1,6 +1,6 @@
|
|||
opengl (Linux: glvnd, Windows: [built-in/none])
|
||||
glfw
|
||||
glew
|
||||
glad
|
||||
glm
|
||||
stb
|
||||
qt6
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include <GL/glew.h>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/common.hpp>
|
||||
#include <glm/vector_relational.hpp>
|
||||
#include <memory>
|
||||
|
@ -35,7 +35,13 @@ MainGLWidget::MainGLWidget(QWidget* parent): QOpenGLWidget(parent), contextMenu(
|
|||
}
|
||||
|
||||
void MainGLWidget::initializeGL() {
|
||||
glewInit();
|
||||
int version = gladLoaderLoadGL();
|
||||
if (version == 0) {
|
||||
Logger::fatalError("Failed to initialize OpenGL context");
|
||||
panic();
|
||||
} else {
|
||||
Logger::debugf("Initialized GL context version %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
|
||||
}
|
||||
renderInit(width(), height());
|
||||
}
|
||||
|
||||
|
|
5914
external/glad/glad/gl.h
vendored
Normal file
5914
external/glad/glad/gl.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
14
patches/freetype_cmakever.patch
Normal file
14
patches/freetype_cmakever.patch
Normal file
|
@ -0,0 +1,14 @@
|
|||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 28dc3b3f6..37fd14713 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -85,7 +85,8 @@
|
||||
# FreeType explicitly marks the API to be exported and relies on the compiler
|
||||
# to hide all other symbols. CMake supports a C_VISBILITY_PRESET property
|
||||
# starting with 2.8.12.
|
||||
-cmake_minimum_required(VERSION 2.8.12)
|
||||
+# cmake_minimum_required(VERSION 2.8.12)
|
||||
+cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
if (NOT CMAKE_VERSION VERSION_LESS 3.3)
|
||||
# Allow symbol visibility settings also on static libraries. CMake < 3.3
|
14
tests/CMakeLists.txt
Normal file
14
tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
function (create_test TEST_NAME)
|
||||
set(TARGET_NAME test_${TEST_NAME})
|
||||
add_executable(${TARGET_NAME} ${ARGN})
|
||||
target_link_libraries(${TARGET_NAME} PRIVATE openblocks)
|
||||
add_dependencies(${TARGET_NAME} openblocks)
|
||||
add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME})
|
||||
endfunction ()
|
||||
|
||||
create_test(lua src/luatest.cpp)
|
||||
create_test(luasched src/luaschedtest.cpp)
|
||||
create_test(luasignal src/luasignaltest.cpp)
|
||||
|
||||
# https://stackoverflow.com/a/36729074/16255372
|
||||
add_custom_target(check ${CMAKE_CTEST_COMMAND} --output-on-failure WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
77
tests/src/luaschedtest.cpp
Normal file
77
tests/src/luaschedtest.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "testutillua.h"
|
||||
|
||||
#include "timeutil.h"
|
||||
|
||||
void test_wait1(DATAMODEL_REF m) {
|
||||
auto ctx = m->GetService<ScriptContext>();
|
||||
std::stringstream out;
|
||||
Logger::initTest(&out);
|
||||
|
||||
tu_set_override(0);
|
||||
luaEval(m, "wait(1) print('Wait')");
|
||||
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("", out.str());
|
||||
|
||||
TT_ADVANCETIME(0.5);
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("", out.str());
|
||||
|
||||
TT_ADVANCETIME(0.5);
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("INFO: Wait\n", out.str());
|
||||
|
||||
Logger::initTest(nullptr);
|
||||
}
|
||||
|
||||
void test_wait0(DATAMODEL_REF m) {
|
||||
auto ctx = m->GetService<ScriptContext>();
|
||||
std::stringstream out;
|
||||
Logger::initTest(&out);
|
||||
|
||||
tu_set_override(0);
|
||||
luaEval(m, "wait(0) print('Wait')");
|
||||
ASSERT_EQ("", out.str());
|
||||
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("", out.str());
|
||||
|
||||
TT_ADVANCETIME(0.03);
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("INFO: Wait\n", out.str());
|
||||
|
||||
Logger::initTest(nullptr);
|
||||
}
|
||||
|
||||
void test_delay(DATAMODEL_REF m) {
|
||||
auto ctx = m->GetService<ScriptContext>();
|
||||
std::stringstream out;
|
||||
Logger::initTest(&out);
|
||||
|
||||
tu_set_override(0);
|
||||
luaEval(m, "delay(1, function() print('Delay') end)");
|
||||
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("", out.str());
|
||||
|
||||
TT_ADVANCETIME(0.5);
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("", out.str());
|
||||
|
||||
TT_ADVANCETIME(0.5);
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("INFO: Delay\n", out.str());
|
||||
|
||||
Logger::initTest(nullptr);
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto m = DataModel::New();
|
||||
m->Init(true);
|
||||
|
||||
test_wait1(m);
|
||||
test_wait0(m);
|
||||
test_delay(m);
|
||||
|
||||
return TEST_STATUS;
|
||||
}
|
103
tests/src/luasignaltest.cpp
Normal file
103
tests/src/luasignaltest.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
|
||||
#include "testutil.h"
|
||||
#include "testutillua.h"
|
||||
|
||||
#include "timeutil.h"
|
||||
#include "objects/part/part.h"
|
||||
#include "objects/service/workspace.h"
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
void test_connect(DATAMODEL_REF m) {
|
||||
auto ctx = m->GetService<ScriptContext>();
|
||||
auto part = Part::New();
|
||||
m->GetService<Workspace>()->AddChild(part);
|
||||
std::stringstream out;
|
||||
Logger::initTest(&out);
|
||||
|
||||
luaEval(m, "workspace.Part.Touched:Connect(function() print('Fired!') end)");
|
||||
ASSERT_EQ("", out.str());
|
||||
|
||||
part->Touched->Fire();
|
||||
ASSERT_EQ("INFO: Fired!\n", out.str());
|
||||
part->Touched->Fire();
|
||||
ASSERT_EQ("INFO: Fired!\nINFO: Fired!\n", out.str());
|
||||
|
||||
Logger::initTest(nullptr);
|
||||
part->Destroy();
|
||||
}
|
||||
|
||||
void test_waitwithin(DATAMODEL_REF m) {
|
||||
auto ctx = m->GetService<ScriptContext>();
|
||||
auto part = Part::New();
|
||||
m->GetService<Workspace>()->AddChild(part);
|
||||
std::stringstream out;
|
||||
Logger::initTest(&out);
|
||||
|
||||
tu_set_override(0);
|
||||
luaEval(m, "workspace.Part.Touched:Connect(function() print('Fired!') wait(1) print('Waited') end)");
|
||||
ASSERT_EQ("", out.str());
|
||||
|
||||
// One shot
|
||||
part->Touched->Fire();
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("INFO: Fired!\n", out.str());
|
||||
TT_ADVANCETIME(0.5);
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("INFO: Fired!\n", out.str());
|
||||
TT_ADVANCETIME(0.5);
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("INFO: Fired!\nINFO: Waited\n", out.str());
|
||||
|
||||
// Clear
|
||||
out = std::stringstream();
|
||||
Logger::initTest(&out); // Shouldn't *theoretically* be necessary, but just in principle...
|
||||
|
||||
// Double fire
|
||||
part->Touched->Fire();
|
||||
TT_ADVANCETIME(0.2);
|
||||
part->Touched->Fire();
|
||||
ASSERT_EQ("INFO: Fired!\nINFO: Fired!\n", out.str());
|
||||
TT_ADVANCETIME(1-0.2); // Small extra delay is necessary because floating point math
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("INFO: Fired!\nINFO: Fired!\nINFO: Waited\n", out.str());
|
||||
TT_ADVANCETIME(0.2);
|
||||
ctx->RunSleepingThreads();
|
||||
ASSERT_EQ("INFO: Fired!\nINFO: Fired!\nINFO: Waited\nINFO: Waited\n", out.str());
|
||||
|
||||
tu_set_override(-1UL);
|
||||
Logger::initTest(nullptr);
|
||||
part->Destroy();
|
||||
}
|
||||
|
||||
void test_await(DATAMODEL_REF m) {
|
||||
auto ctx = m->GetService<ScriptContext>();
|
||||
auto part = Part::New();
|
||||
m->GetService<Workspace>()->AddChild(part);
|
||||
std::stringstream out;
|
||||
Logger::initTest(&out);
|
||||
|
||||
tu_set_override(0);
|
||||
luaEval(m, "workspace.Part.Touched:Wait() print('Fired!')");
|
||||
ASSERT_EQ("", out.str());
|
||||
|
||||
part->Touched->Fire();
|
||||
ASSERT_EQ("INFO: Fired!\n", out.str());
|
||||
part->Touched->Fire(); // Firing again should not affect output
|
||||
ASSERT_EQ("INFO: Fired!\n", out.str());
|
||||
|
||||
tu_set_override(-1UL);
|
||||
Logger::initTest(nullptr);
|
||||
part->Destroy();
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto m = DataModel::New();
|
||||
m->Init(true);
|
||||
|
||||
test_connect(m);
|
||||
test_waitwithin(m);
|
||||
test_await(m);
|
||||
|
||||
return TEST_STATUS;
|
||||
}
|
20
tests/src/luatest.cpp
Normal file
20
tests/src/luatest.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include "testutil.h"
|
||||
#include "testutillua.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
void test_output(DATAMODEL_REF m) {
|
||||
ASSERT_EQ("INFO: Hello, world!\n", luaEvalOut(m, "print('Hello, world!')"));
|
||||
// ASSERT_EQ("WARN: Some warning here.\n", luaEvalOut(m, "warn('Some warning here.')"));
|
||||
// ASSERT_EQ("ERROR: An error!.\n", luaEvalOut(m, "error('An error!')"));
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto m = DataModel::New();
|
||||
m->Init(true);
|
||||
|
||||
test_output(m);
|
||||
|
||||
return TEST_STATUS;
|
||||
}
|
70
tests/src/testutil.h
Normal file
70
tests/src/testutil.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
#pragma once
|
||||
|
||||
// https://bastian.rieck.me/blog/2017/simple_unit_tests/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iomanip>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#ifdef __FUNCTION__
|
||||
#define __FUNC_NAME __FUNCTION__
|
||||
#else
|
||||
#define __FUNC_NAME __func__
|
||||
#endif
|
||||
|
||||
#define ASSERT(x, msg) __assert((x), __FILE__, __LINE__, __FUNC_NAME, msg)
|
||||
#define ASSERT_EQ(x, y) __assert_eq((x) == (y), __FILE__, __LINE__, __FUNC_NAME, #x, (y))
|
||||
// #define ASSERT_EQSTR(x, y) ASSERT(strcmp(x, y) == 0, #x " != " #y)
|
||||
#define ASSERT_EQSTR(x, y) ASSERT_EQ(x, y)
|
||||
|
||||
#define DATAMODEL_REF std::shared_ptr<DataModel>
|
||||
|
||||
#define TU_TIME_EXPOSE_TEST
|
||||
#define TT_ADVANCETIME(secs) tu_set_override(tu_clock_micros() + (secs) * 1'000'000);
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
int TEST_STATUS = 0;
|
||||
|
||||
inline void __assert(bool cond, std::string file, int line, std::string func, std::string message) {
|
||||
if (cond) return;
|
||||
fprintf(stderr, "ASSERT FAILED : %s:%d : %s : '%s'\n", file.c_str(), line, func.c_str(), message.c_str());
|
||||
TEST_STATUS = 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::string quote(T value) {
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string quote<std::string>(std::string value) {
|
||||
std::stringstream ss;
|
||||
ss << std::quoted(value);
|
||||
std::string newstr = ss.str();
|
||||
|
||||
newstr = std::regex_replace(newstr, std::regex("\n"), "\\n");
|
||||
return newstr;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string quote<const char*>(const char* value) {
|
||||
return quote<std::string>(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string quote<char*>(char* value) {
|
||||
return quote<std::string>(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void __assert_eq(bool cond, std::string file, int line, std::string func, std::string model, T value) {
|
||||
if (cond) return;
|
||||
std::string message = model + " != " + quote(value);
|
||||
fprintf(stderr, "ASSERT FAILED : %s:%d : %s : '%s'\n", file.c_str(), line, func.c_str(), message.c_str());
|
||||
TEST_STATUS = 1;
|
||||
}
|
30
tests/src/testutillua.h
Normal file
30
tests/src/testutillua.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "testutil.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "logger.h"
|
||||
#include "objects/datamodel.h"
|
||||
#include "objects/script.h"
|
||||
#include "objects/service/script/scriptcontext.h"
|
||||
|
||||
std::string luaEvalOut(DATAMODEL_REF m, std::string source) {
|
||||
std::stringstream out;
|
||||
Logger::initTest(&out);
|
||||
|
||||
auto s = Script::New();
|
||||
m->AddChild(s);
|
||||
s->source = source;
|
||||
s->Run();
|
||||
|
||||
Logger::initTest(nullptr);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void luaEval(DATAMODEL_REF m, std::string source) {
|
||||
auto s = Script::New();
|
||||
m->AddChild(s);
|
||||
s->source = source;
|
||||
s->Run();
|
||||
}
|
Loading…
Add table
Reference in a new issue