diff options
| author | Akshay Nair <phenax5@gmail.com> | 2025-03-21 23:00:08 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2025-03-21 23:00:08 +0530 |
| commit | 498135054a168bd839f2ee8ebb1ba245d72a8f3b (patch) | |
| tree | 0da58d35276d1f27fd548fff9dbab2cccebbc4b6 | |
| parent | 7ec8336431787156826185628ad3ee05dc327d2a (diff) | |
| download | null-browser-498135054a168bd839f2ee8ebb1ba245d72a8f3b.tar.gz null-browser-498135054a168bd839f2ee8ebb1ba245d72a8f3b.zip | |
Lua runtime simple value conversion + spec
Diffstat (limited to '')
| -rw-r--r-- | spec/LuaRuntimeSpec.cpp | 123 | ||||
| -rw-r--r-- | src/LuaRuntime.cpp | 35 | ||||
| -rw-r--r-- | src/LuaRuntime.hpp | 6 |
3 files changed, 117 insertions, 47 deletions
diff --git a/spec/LuaRuntimeSpec.cpp b/spec/LuaRuntimeSpec.cpp index 149e1e1..924681a 100644 --- a/spec/LuaRuntimeSpec.cpp +++ b/spec/LuaRuntimeSpec.cpp @@ -1,73 +1,108 @@ -#include "testUtils.h" #include <QtCore> -#include <atomic> #include <uv.h> #include "LuaRuntime.hpp" +#include "testUtils.h" class LuaRuntimeSpec : public QObject { Q_OBJECT private slots: - void cleanupTestCase() { uv_library_shutdown(); } + void beforeTestCase() { LuaRuntime::instance()->startEventLoop(); } - void testSanityCheckBuiltins() { - auto lua = LuaRuntime::instance(); + void cleanupTestCase() { + LuaRuntime::instance()->stopEventLoop(); + uv_library_shutdown(); + } - it("evaluates simple expression") { - lua->startEventLoop(); - std::atomic<int> foobar = 2; + void testEvaluate() { + context("when given an expression returning a number"); + it("emits evaluationCompleted with the result") { + auto lua = LuaRuntime::instance(); + QSignalSpy evaluationCompletedSpy(lua, &LuaRuntime::evaluationCompleted); - lua->queueTask([&foobar]() { foobar = 10; }); + lua->evaluate("return 20 + 1 * 5"); - lua->evaluate(R"( - print('Hello -- '); - local timer = uv.new_timer(); - timer:start(1000, 0, function() - print('inside timer 1') - print('inside timer 2') - print('inside timer 3') - print('inside timer 4') - print('inside timer 5') - timer:close() - end); - print('-- end'); - )"); - lua->queueTask([]() { qDebug() << "---- 1"; }); - lua->queueTask([]() { qDebug() << "---- 2"; }); - lua->queueTask([]() { qDebug() << "---- 3"; }); - std::this_thread::sleep_for(std::chrono::seconds(2)); - // std::this_thread::sleep_for(std::chrono::milliseconds(20)); - lua->stopEventLoop(); + evaluationCompletedSpy.wait(); + QCOMPARE(evaluationCompletedSpy.count(), 1); + QVariant result = evaluationCompletedSpy.takeFirst().at(0); + QCOMPARE(result, 25); + } + + context("when given an expression returning a string"); + it("emits evaluationCompleted with the result") { + auto lua = LuaRuntime::instance(); + QSignalSpy evaluationCompletedSpy(lua, &LuaRuntime::evaluationCompleted); + + lua->evaluate("local name = 'world'; return 'hello ' .. name"); - qDebug() << "foobar" << foobar; + evaluationCompletedSpy.wait(); + QCOMPARE(evaluationCompletedSpy.count(), 1); + QVariant result = evaluationCompletedSpy.takeFirst().at(0); + QCOMPARE(result, "hello world"); + } + + context("when given an expression returning a boolean"); + it("emits evaluationCompleted with the result") { + auto lua = LuaRuntime::instance(); + QSignalSpy evaluationCompletedSpy(lua, &LuaRuntime::evaluationCompleted); + + lua->evaluate("local num = 5; return 5 == num"); - QCOMPARE(1, 1); + evaluationCompletedSpy.wait(); + QCOMPARE(evaluationCompletedSpy.count(), 1); + QVariant result = evaluationCompletedSpy.takeFirst().at(0); + QCOMPARE(result, true); + } + + context("when given an expression returning nil"); + it("emits evaluationCompleted with the result") { + auto lua = LuaRuntime::instance(); + QSignalSpy evaluationCompletedSpy(lua, &LuaRuntime::evaluationCompleted); + + lua->evaluate("return nil"); + + QVERIFY(evaluationCompletedSpy.wait()); + QCOMPARE(evaluationCompletedSpy.count(), 1); + QVariant result = evaluationCompletedSpy.takeFirst().at(0); + QCOMPARE(result, 0); } } - void testSanityCheckBuiltins2() { - auto lua = LuaRuntime::instance(); + void testQueueTask() { + context("when task is queued"); + it("evaluates task asynchronously") { + auto lua = LuaRuntime::instance(); + bool wasTaskCalled = false; + + lua->queueTask([&wasTaskCalled]() { wasTaskCalled = true; }); + QVERIFY(NOT wasTaskCalled); + + QVERIFY(QTest::qWaitFor([&wasTaskCalled]() { return wasTaskCalled; })); + QVERIFY(wasTaskCalled); + } + } - it("evaluates again") { - lua->startEventLoop(); + void testSanityCheckUV() { + context("when a 1 second timer is set"); + it("calls callback after 1 second") { + auto lua = LuaRuntime::instance(); + QSignalSpy evaluationCompletedSpy(lua, &LuaRuntime::evaluationCompleted); - lua->queueTask([]() { qDebug() << "---- 5"; }); lua->evaluate(R"( - print('Hello -- '); + _G.wasTimerCalled = false; local timer = uv.new_timer(); timer:start(1000, 0, function() - print('%%%%% blagb') + _G.wasTimerCalled = true; timer:close() - end); - print('-- end'); + end) )"); - lua->queueTask([]() { qDebug() << "---- 5"; }); - // TODO: Impl - std::this_thread::sleep_for(std::chrono::seconds(2)); - lua->stopEventLoop(); + QVERIFY(evaluationCompletedSpy.wait()); + QVERIFY(NOT lua->evaluateSync("return _G.wasTimerCalled").toBool()); - QCOMPARE(1, 1); + QVERIFY(QTest::qWaitFor([&lua]() { + return lua->evaluateSync("return _G.wasTimerCalled").toBool(); + })); } } }; diff --git a/src/LuaRuntime.cpp b/src/LuaRuntime.cpp index e61fbf5..e9a30b1 100644 --- a/src/LuaRuntime.cpp +++ b/src/LuaRuntime.cpp @@ -52,13 +52,42 @@ void LuaRuntime::stopEventLoop() { void LuaRuntime::evaluate(QString code) { eventLoop->queueTask([this, code]() { if (luaL_dostring(state, code.toStdString().c_str())) { - qDebug() << "Lua Error: " << lua_tostring(state, -1); + auto value = lua_tostring(state, -1); lua_pop(state, 1); - } else - qDebug() << "done"; + + qDebug() << "Lua Error: " << value; + emit evaluationFailed(value); + } else { + auto value = getValue(-1); + lua_pop(state, 1); + + qDebug() << "result: " << value; + emit evaluationCompleted(value); + } }); } +QVariant LuaRuntime::evaluateSync(QString code) { + auto result = luaL_dostring(state, code.toStdString().c_str()); + return getValue(-1); // TODO: error handling +} + +QVariant LuaRuntime::getValue(int idx) { + if (lua_isstring(state, idx)) + return lua_tostring(state, idx); + + if (lua_isnumber(state, idx)) + return lua_tonumber(state, idx); + + if (lua_isboolean(state, idx)) + return lua_toboolean(state, idx); + + if (lua_isnil(state, idx)) + return 0; // TODO: nil representation + + return lua_tostring(state, idx); +} + int LuaRuntime::lua_onUrlOpen(lua_State *state) { const char *url = luaL_optstring(state, 1, ""); auto runtime = LuaRuntime::instance(); diff --git a/src/LuaRuntime.hpp b/src/LuaRuntime.hpp index 443dec5..dd5c0ec 100644 --- a/src/LuaRuntime.hpp +++ b/src/LuaRuntime.hpp @@ -16,14 +16,20 @@ public: } void evaluate(QString code); + QVariant evaluateSync(QString code); void stopEventLoop(); void startEventLoop(); + QVariant getValue(int idx); + DELEGATE(eventLoop, queueTask, queueTask) signals: void urlOpened(QString url, OpenType openType); + void evaluationCompleted(QVariant value); + void evaluationFailed(QString value); + // void outputProduced(QVariant value); protected: LuaRuntime(); |
