implement Milestone 18: inter-app MessageBus with intent system

This commit is contained in:
2026-01-18 16:36:08 +01:00
parent 72a06f542b
commit 372a293bd0
6 changed files with 1310 additions and 1 deletions

View File

@@ -31,6 +31,7 @@ add_library(mosis-sandbox STATIC
../src/main/cpp/sandbox/sensor_interface.cpp
../src/main/cpp/sandbox/bluetooth_interface.cpp
../src/main/cpp/sandbox/contacts_interface.cpp
../src/main/cpp/sandbox/message_bus.cpp
)
target_include_directories(mosis-sandbox PUBLIC
../src/main/cpp/sandbox

View File

@@ -21,11 +21,16 @@
#include "sensor_interface.h"
#include "bluetooth_interface.h"
#include "contacts_interface.h"
#include "message_bus.h"
#include <filesystem>
#include <fstream>
#include <sstream>
#include <thread>
#include <chrono>
#include <cstdlib>
#ifdef _WIN32
#include <crtdbg.h>
#endif
// Get path to scripts directory
std::string GetScriptsDir() {
@@ -3075,11 +3080,181 @@ bool Test_ContactsLuaIntegration(std::string& error_msg) {
return true;
}
//=============================================================================
// MILESTONE 18: MESSAGE BUS TESTS
//=============================================================================
bool Test_MessageBusSendToReceiver(std::string& error_msg) {
mosis::MessageBus bus;
bool received = false;
mosis::Intent receivedIntent;
// Register receiver
bus.RegisterReceiver("receiver.app", {"share", {}}, [&](const mosis::Intent& i) {
received = true;
receivedIntent = i;
});
// Send intent
mosis::Intent intent{"share", "text/plain", "Hello", "sender.app"};
std::string err;
auto result = bus.Send("sender.app", "receiver.app", intent, err);
EXPECT_TRUE(result == mosis::MessageError::None);
EXPECT_TRUE(received);
EXPECT_TRUE(receivedIntent.action == "share");
EXPECT_TRUE(receivedIntent.data == "Hello");
EXPECT_TRUE(receivedIntent.from_app == "sender.app");
return true;
}
bool Test_MessageBusBlockUnregistered(std::string& error_msg) {
mosis::MessageBus bus;
// No receivers registered
mosis::Intent intent{"share", "text/plain", "Hello", "sender.app"};
std::string err;
auto result = bus.Send("sender.app", "receiver.app", intent, err);
EXPECT_TRUE(result == mosis::MessageError::ReceiverNotFound);
EXPECT_TRUE(err.find("not found") != std::string::npos ||
err.find("no receiver") != std::string::npos);
return true;
}
bool Test_MessageBusBroadcast(std::string& error_msg) {
mosis::MessageBus bus;
int receiveCount = 0;
// Register multiple receivers for same action
bus.RegisterReceiver("app1", {"share", {}}, [&](const mosis::Intent&) { receiveCount++; });
bus.RegisterReceiver("app2", {"share", {}}, [&](const mosis::Intent&) { receiveCount++; });
bus.RegisterReceiver("app3", {"other", {}}, [&](const mosis::Intent&) { receiveCount++; });
// Broadcast share intent
mosis::Intent intent{"share", "text/plain", "Hello", "sender.app"};
std::string err;
auto result = bus.Broadcast("sender.app", intent, err);
EXPECT_TRUE(result == mosis::MessageError::None);
EXPECT_TRUE(receiveCount == 2); // Only app1 and app2
return true;
}
bool Test_MessageBusMimeFilter(std::string& error_msg) {
mosis::MessageBus bus;
bool imageReceived = false;
bool textReceived = false;
// Register with MIME filter
bus.RegisterReceiver("image.viewer", {"view", {"image/png", "image/jpeg"}},
[&](const mosis::Intent&) { imageReceived = true; });
bus.RegisterReceiver("text.viewer", {"view", {"text/plain"}},
[&](const mosis::Intent&) { textReceived = true; });
// Send image intent
mosis::Intent imgIntent{"view", "image/png", "data", "sender"};
std::string err;
bus.Broadcast("sender", imgIntent, err);
EXPECT_TRUE(imageReceived);
EXPECT_TRUE(!textReceived);
return true;
}
bool Test_MessageBusDataLimit(std::string& error_msg) {
mosis::MessageBus bus;
bus.RegisterReceiver("receiver", {"share", {}}, [](const mosis::Intent&) {});
// Create oversized data (> 1MB)
std::string largeData(2 * 1024 * 1024, 'x');
mosis::Intent intent{"share", "text/plain", largeData, "sender"};
std::string err;
auto result = bus.Send("sender", "receiver", intent, err);
EXPECT_TRUE(result == mosis::MessageError::DataTooLarge);
return true;
}
bool Test_MessageBusBlockedApp(std::string& error_msg) {
mosis::MessageBus bus;
bus.RegisterReceiver("receiver", {"share", {}}, [](const mosis::Intent&) {});
bus.BlockApp("bad.app");
mosis::Intent intent{"share", "text/plain", "Hello", "bad.app"};
std::string err;
auto result = bus.Send("bad.app", "receiver", intent, err);
EXPECT_TRUE(result == mosis::MessageError::SenderBlocked);
return true;
}
bool Test_MessageBusLuaIntegration(std::string& error_msg) {
SandboxContext ctx = TestContext();
LuaSandbox sandbox(ctx);
mosis::MessageBus bus;
mosis::RegisterIntentsAPI(sandbox.GetState(), &bus, "test.app");
std::string script = R"lua(
-- Test that intents global exists
if not intents then
error("intents global not found")
end
if not intents.on then
error("intents.on not found")
end
if not intents.send then
error("intents.send not found")
end
if not intents.broadcast then
error("intents.broadcast not found")
end
if not intents.hasReceiver then
error("intents.hasReceiver not found")
end
if not intents.getReceivers then
error("intents.getReceivers not found")
end
if not intents.unregisterAll then
error("intents.unregisterAll not found")
end
)lua";
bool ok = sandbox.LoadString(script, "intents_test");
if (!ok) {
error_msg = "Lua test failed: " + sandbox.GetLastError();
return false;
}
return true;
}
//=============================================================================
// MAIN
//=============================================================================
int main(int argc, char* argv[]) {
#ifdef _WIN32
// Disable VC runtime abort dialog - write to console instead
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
#endif
std::string filter;
std::string output_file = "test_results.json";
@@ -3276,6 +3451,15 @@ int main(int argc, char* argv[]) {
harness.AddTest("ContactsDeleteNotFound", Test_ContactsDeleteNotFound);
harness.AddTest("ContactsLuaIntegration", Test_ContactsLuaIntegration);
// Milestone 18: Message Bus
harness.AddTest("MessageBusSendToReceiver", Test_MessageBusSendToReceiver);
harness.AddTest("MessageBusBlockUnregistered", Test_MessageBusBlockUnregistered);
harness.AddTest("MessageBusBroadcast", Test_MessageBusBroadcast);
harness.AddTest("MessageBusMimeFilter", Test_MessageBusMimeFilter);
harness.AddTest("MessageBusDataLimit", Test_MessageBusDataLimit);
harness.AddTest("MessageBusBlockedApp", Test_MessageBusBlockedApp);
harness.AddTest("MessageBusLuaIntegration", Test_MessageBusLuaIntegration);
// Run tests
auto results = harness.Run(filter);