OSC tests
This commit is contained in:
@@ -128,6 +128,25 @@ endif()
|
||||
|
||||
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
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${GPUDIRECT_DIR}/bin/x64/dvp.dll"
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
unsigned short GetPort() const { return mPort; }
|
||||
|
||||
private:
|
||||
friend struct OscServerTestAccess;
|
||||
|
||||
struct OscMessage
|
||||
{
|
||||
std::string address;
|
||||
|
||||
176
tests/OscServerTests.cpp
Normal file
176
tests/OscServerTests.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user