#include "OscServer.h" #include #include #include #include #include namespace { int gFailures = 0; void Expect(bool condition, const char* message) { if (condition) return; std::cerr << "FAIL: " << message << "\n"; ++gFailures; } void AppendPaddedString(std::vector& packet, const std::string& text) { packet.insert(packet.end(), text.begin(), text.end()); packet.push_back('\0'); while (packet.size() % 4 != 0) packet.push_back('\0'); } void AppendInt32(std::vector& packet, int value) { const unsigned int bits = static_cast(value); packet.push_back(static_cast((bits >> 24) & 0xff)); packet.push_back(static_cast((bits >> 16) & 0xff)); packet.push_back(static_cast((bits >> 8) & 0xff)); packet.push_back(static_cast(bits & 0xff)); } void AppendFloat32(std::vector& packet, float value) { unsigned int bits = 0; std::memcpy(&bits, &value, sizeof(bits)); AppendInt32(packet, static_cast(bits)); } void AppendFloat64(std::vector& packet, double value) { uint64_t bits = 0; std::memcpy(&bits, &value, sizeof(bits)); for (int shift = 56; shift >= 0; shift -= 8) packet.push_back(static_cast((bits >> shift) & 0xff)); } std::vector BuildOscPacket(const std::string& address, const std::string& typeTags) { std::vector packet; AppendPaddedString(packet, address); AppendPaddedString(packet, typeTags); return packet; } } struct OscServerTestAccess { using Message = OscServer::OscMessage; static bool Decode(OscServer& server, const std::vector& packet, Message& message, std::string& error) { return server.DecodeMessage(packet.data(), static_cast(packet.size()), message, error); } static bool Dispatch(OscServer& server, const Message& message, std::string& error) { return server.DispatchMessage(message, error); } static void SetUpdateParameterCallback( OscServer& server, const std::function& callback) { server.mCallbacks.updateParameter = callback; } }; namespace { void TestDecodeFloatMessage() { OscServer server; std::vector packet = BuildOscPacket("/VideoShaderToys/VHS/intensity", ",f"); AppendFloat32(packet, 0.75f); OscServerTestAccess::Message message; std::string error; Expect(OscServerTestAccess::Decode(server, packet, message, error), "float OSC message decodes"); Expect(message.address == "/VideoShaderToys/VHS/intensity", "float OSC address is preserved"); Expect(message.valueJson.find("0.75") == 0, "float OSC value becomes JSON number"); } void TestDecodeDoubleMessage() { OscServer server; std::vector packet = BuildOscPacket("/VideoShaderToys/fisheye-reproject/panDegrees", ",d"); AppendFloat64(packet, 51.5); OscServerTestAccess::Message message; std::string error; Expect(OscServerTestAccess::Decode(server, packet, message, error), "double OSC message decodes"); Expect(message.address == "/VideoShaderToys/fisheye-reproject/panDegrees", "double OSC address is preserved"); Expect(message.valueJson.find("51.5") == 0, "double OSC value becomes JSON number"); } void TestDecodeVectorMessage() { OscServer server; std::vector packet = BuildOscPacket("/VideoShaderToys/video-transform/pan", ",ff"); AppendFloat32(packet, 0.25f); AppendFloat32(packet, -0.5f); OscServerTestAccess::Message message; std::string error; Expect(OscServerTestAccess::Decode(server, packet, message, error), "multi-float OSC message decodes"); Expect(message.address == "/VideoShaderToys/video-transform/pan", "multi-float OSC address is preserved"); Expect(message.valueJson.find("[0.25,-0.5") == 0, "multi-float OSC value becomes JSON array"); } void TestDecodeIntStringAndBoolMessages() { OscServer server; std::vector intPacket = BuildOscPacket("/VideoShaderToys/layer-1/mode", ",i"); AppendInt32(intPacket, 3); OscServerTestAccess::Message intMessage; std::string error; Expect(OscServerTestAccess::Decode(server, intPacket, intMessage, error), "int OSC message decodes"); Expect(intMessage.valueJson == "3", "int OSC value becomes JSON number"); std::vector stringPacket = BuildOscPacket("/VideoShaderToys/layer-1/mode", ",s"); AppendPaddedString(stringPacket, "equisolid"); OscServerTestAccess::Message stringMessage; error.clear(); Expect(OscServerTestAccess::Decode(server, stringPacket, stringMessage, error), "string OSC message decodes"); Expect(stringMessage.valueJson == "\"equisolid\"", "string OSC value becomes JSON string"); std::vector boolPacket = BuildOscPacket("/VideoShaderToys/layer-1/enabled", ",T"); OscServerTestAccess::Message boolMessage; error.clear(); Expect(OscServerTestAccess::Decode(server, boolPacket, boolMessage, error), "boolean OSC message decodes"); Expect(boolMessage.valueJson == "true", "true OSC typetag becomes JSON boolean"); } void TestDispatchValidAddress() { OscServer server; std::string layerKey; std::string parameterKey; std::string valueJson; OscServerTestAccess::SetUpdateParameterCallback(server, [&](const std::string& layer, const std::string& parameter, const std::string& value, std::string&) { layerKey = layer; parameterKey = parameter; valueJson = value; return true; }); OscServerTestAccess::Message message; message.address = "/VideoShaderToys/VHS/intensity"; message.valueJson = "0.5"; std::string error; Expect(OscServerTestAccess::Dispatch(server, message, error), "valid OSC control address dispatches"); Expect(layerKey == "VHS", "dispatch extracts layer key"); Expect(parameterKey == "intensity", "dispatch extracts parameter key"); Expect(valueJson == "0.5", "dispatch forwards JSON value"); } void TestRejectsUnsupportedAddress() { OscServer server; bool called = false; OscServerTestAccess::SetUpdateParameterCallback(server, [&](const std::string&, const std::string&, const std::string&, std::string&) { called = true; return true; }); OscServerTestAccess::Message message; message.address = "/OtherApp/VHS/intensity"; message.valueJson = "0.5"; std::string error; Expect(!OscServerTestAccess::Dispatch(server, message, error), "unsupported OSC namespace is rejected"); Expect(!called, "unsupported OSC namespace does not invoke callback"); Expect(!error.empty(), "unsupported OSC address reports an error"); } } int main() { TestDecodeFloatMessage(); TestDecodeDoubleMessage(); TestDecodeVectorMessage(); TestDecodeIntStringAndBoolMessages(); TestDispatchValidAddress(); TestRejectsUnsupportedAddress(); if (gFailures != 0) { std::cerr << gFailures << " OscServer test failure(s).\n"; return 1; } std::cout << "OscServer tests passed.\n"; return 0; }