OverviewFilesCommitsIssuesDocsReleasesPeers

blender-bridge / test / test_shm_protocol.cpp

216 lines · cpp ref:
#include "../src/shm_protocol.h"

#include <cassert>
#include <cstdio>
#include <cstring>

static int tests_passed = 0;

#define TEST(name)                             \
	do {                                       \
		printf("  %-40s", #name "...");        \
	} while (0)
#define PASS()                                 \
	do {                                       \
		printf("PASS\n");                      \
		tests_passed++;                        \
	} while (0)

void test_struct_sizes() {
	TEST(struct_sizes);
	assert(sizeof(BridgeHeader) == 64);
	assert(sizeof(ObjectEntry) == 32);
	assert(OBJECT_TABLE_OFFSET == 64);
	PASS();
}

void test_shm_create_destroy() {
	TEST(shm_create_destroy);
	ShmRegion region;
	assert(region.create("/test_bb_create", 4096));
	assert(region.valid());
	assert(region.ptr() != nullptr);
	assert(region.size() == 4096);
	region.destroy();
	assert(!region.valid());
	PASS();
}

void test_shm_open_shared() {
	TEST(shm_open_shared);
	ShmRegion owner;
	assert(owner.create("/test_bb_shared", 4096));

	// Write some data from the owner
	memset(owner.ptr(), 0xAB, 16);

	// Open from a "reader"
	ShmRegion reader;
	assert(reader.open("/test_bb_shared", 4096));
	assert(reader.valid());

	// Reader should see the same data
	uint8_t *rp = static_cast<uint8_t *>(reader.ptr());
	assert(rp[0] == 0xAB);
	assert(rp[15] == 0xAB);

	reader.destroy();
	owner.destroy();
	PASS();
}

void test_header_readwrite() {
	TEST(header_readwrite);
	ShmRegion region;
	assert(region.create("/test_bb_hdr", 4096));

	BridgeHeader hdr = {};
	hdr.magic[0] = 'B';
	hdr.magic[1] = 'G';
	hdr.magic[2] = 'O';
	hdr.magic[3] = 'D';
	hdr.version = 1;
	hdr.direction = 0;
	hdr.sequence = 42;
	hdr.object_count = 3;
	hdr.frame_number = 12345;
	write_header(region.ptr(), hdr);

	BridgeHeader read_hdr = read_header(region.ptr());
	assert(read_hdr.magic[0] == 'B');
	assert(read_hdr.magic[1] == 'G');
	assert(read_hdr.magic[2] == 'O');
	assert(read_hdr.magic[3] == 'D');
	assert(read_hdr.version == 1);
	assert(read_hdr.direction == 0);
	assert(read_hdr.sequence == 42);
	assert(read_hdr.object_count == 3);
	assert(read_hdr.frame_number == 12345);

	region.destroy();
	PASS();
}

void test_object_entry_readwrite() {
	TEST(object_entry_readwrite);
	ShmRegion region;
	assert(region.create("/test_bb_obj", 4096));

	ObjectEntry entry = {};
	entry.object_id = 100;
	entry.object_type = OBJ_MESH;
	entry.update_type = UPDATE_TRANSFORM;
	entry.data_offset = 512;
	entry.data_size = 64;
	entry.sequence = 7;
	write_object_entry(region.ptr(), 0, entry);

	ObjectEntry read_entry = read_object_entry(region.ptr(), 0);
	assert(read_entry.object_id == 100);
	assert(read_entry.object_type == OBJ_MESH);
	assert(read_entry.update_type == UPDATE_TRANSFORM);
	assert(read_entry.data_offset == 512);
	assert(read_entry.data_size == 64);
	assert(read_entry.sequence == 7);

	region.destroy();
	PASS();
}

void test_multiple_object_entries() {
	TEST(multiple_object_entries);
	ShmRegion region;
	assert(region.create("/test_bb_multi", 4096));

	for (uint32_t i = 0; i < 10; i++) {
		ObjectEntry entry = {};
		entry.object_id = i * 10;
		entry.object_type = (i % 2 == 0) ? OBJ_MESH : OBJ_LIGHT;
		entry.update_type = UPDATE_FULL;
		entry.data_offset = 1024 + i * 128;
		entry.data_size = 128;
		entry.sequence = i;
		write_object_entry(region.ptr(), i, entry);
	}

	for (uint32_t i = 0; i < 10; i++) {
		ObjectEntry read_entry = read_object_entry(region.ptr(), i);
		assert(read_entry.object_id == i * 10);
		assert(read_entry.data_offset == 1024 + i * 128);
		assert(read_entry.sequence == i);
	}

	region.destroy();
	PASS();
}

void test_data_blob_offset() {
	TEST(data_blob_offset);
	// With 10 max objects: 64 (header) + 10 * 32 (entries) = 384
	assert(data_blob_offset(10) == 64 + 10 * 32);
	assert(data_blob_offset(0) == 64);
	assert(data_blob_offset(100) == 64 + 100 * 32);
	PASS();
}

void test_cross_process_visibility() {
	TEST(cross_process_visibility);
	ShmRegion writer;
	assert(writer.create("/test_bb_xproc", 4096));

	// Write a header
	BridgeHeader hdr = {};
	hdr.magic[0] = 'B';
	hdr.magic[1] = 'G';
	hdr.magic[2] = 'O';
	hdr.magic[3] = 'D';
	hdr.version = 1;
	hdr.direction = 1; // blender→godot
	hdr.sequence = 99;
	hdr.object_count = 1;
	write_header(writer.ptr(), hdr);

	// Write an object entry
	ObjectEntry entry = {};
	entry.object_id = 42;
	entry.object_type = OBJ_CAMERA;
	entry.update_type = UPDATE_VERTEX;
	entry.data_offset = 256;
	entry.data_size = 48;
	write_object_entry(writer.ptr(), 0, entry);

	// Open as reader and verify
	ShmRegion reader;
	assert(reader.open("/test_bb_xproc", 4096));

	BridgeHeader rh = read_header(reader.ptr());
	assert(rh.direction == 1);
	assert(rh.sequence == 99);
	assert(rh.object_count == 1);

	ObjectEntry re = read_object_entry(reader.ptr(), 0);
	assert(re.object_id == 42);
	assert(re.object_type == OBJ_CAMERA);
	assert(re.update_type == UPDATE_VERTEX);

	reader.destroy();
	writer.destroy();
	PASS();
}

int main() {
	printf("=== SHM Protocol Tests ===\n");

	test_struct_sizes();
	test_shm_create_destroy();
	test_shm_open_shared();
	test_header_readwrite();
	test_object_entry_readwrite();
	test_multiple_object_entries();
	test_data_blob_offset();
	test_cross_process_visibility();

	printf("\nAll %d tests passed.\n", tests_passed);
	return 0;
}