OSC tests
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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
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