OSC tests
Some checks failed
CI / Native Windows Build And Tests (push) Failing after 7s
CI / React UI Build (push) Has been cancelled
CI / Windows Release Package (push) Has been cancelled

This commit is contained in:
2026-05-03 12:23:19 +10:00
parent 902f46774f
commit bfc12a1aea
3 changed files with 197 additions and 0 deletions

View File

@@ -128,6 +128,25 @@ endif()
add_test(NAME ShaderPackageRegistryTests COMMAND ShaderPackageRegistryTests) add_test(NAME ShaderPackageRegistryTests COMMAND ShaderPackageRegistryTests)
add_executable(OscServerTests
"${APP_DIR}/OscServer.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/tests/OscServerTests.cpp"
)
target_include_directories(OscServerTests PRIVATE
"${APP_DIR}"
)
target_link_libraries(OscServerTests PRIVATE
Ws2_32
)
if(MSVC)
target_compile_options(OscServerTests PRIVATE /W3)
endif()
add_test(NAME OscServerTests COMMAND OscServerTests)
add_custom_command(TARGET LoopThroughWithOpenGLCompositing POST_BUILD add_custom_command(TARGET LoopThroughWithOpenGLCompositing POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${GPUDIRECT_DIR}/bin/x64/dvp.dll" "${GPUDIRECT_DIR}/bin/x64/dvp.dll"

View File

@@ -26,6 +26,8 @@ public:
unsigned short GetPort() const { return mPort; } unsigned short GetPort() const { return mPort; }
private: private:
friend struct OscServerTestAccess;
struct OscMessage struct OscMessage
{ {
std::string address; std::string address;

176
tests/OscServerTests.cpp Normal file
View File

@@ -0,0 +1,176 @@
#include "OscServer.h"
#include <cstring>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
namespace
{
int gFailures = 0;
void Expect(bool condition, const char* message)
{
if (condition)
return;
std::cerr << "FAIL: " << message << "\n";
++gFailures;
}
void AppendPaddedString(std::vector<char>& 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<char>& packet, int value)
{
const unsigned int bits = static_cast<unsigned int>(value);
packet.push_back(static_cast<char>((bits >> 24) & 0xff));
packet.push_back(static_cast<char>((bits >> 16) & 0xff));
packet.push_back(static_cast<char>((bits >> 8) & 0xff));
packet.push_back(static_cast<char>(bits & 0xff));
}
void AppendFloat32(std::vector<char>& packet, float value)
{
unsigned int bits = 0;
std::memcpy(&bits, &value, sizeof(bits));
AppendInt32(packet, static_cast<int>(bits));
}
std::vector<char> BuildOscPacket(const std::string& address, const std::string& typeTags)
{
std::vector<char> packet;
AppendPaddedString(packet, address);
AppendPaddedString(packet, typeTags);
return packet;
}
}
struct OscServerTestAccess
{
using Message = OscServer::OscMessage;
static bool Decode(OscServer& server, const std::vector<char>& packet, Message& message, std::string& error)
{
return server.DecodeMessage(packet.data(), static_cast<int>(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<bool(const std::string&, const std::string&, const std::string&, std::string&)>& callback)
{
server.mCallbacks.updateParameter = callback;
}
};
namespace
{
void TestDecodeFloatMessage()
{
OscServer server;
std::vector<char> 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 TestDecodeIntStringAndBoolMessages()
{
OscServer server;
std::vector<char> 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<char> 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<char> 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();
TestDecodeIntStringAndBoolMessages();
TestDispatchValidAddress();
TestRejectsUnsupportedAddress();
if (gFailures != 0)
{
std::cerr << gFailures << " OscServer test failure(s).\n";
return 1;
}
std::cout << "OscServer tests passed.\n";
return 0;
}