CARLA
Loading...
Searching...
No Matches
test_v2x_serialization.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#include "test.h"
8
9#include <carla/Buffer.h>
10#include <carla/MsgPack.h>
14
15#include <cstring>
16#include <type_traits>
17
18namespace csd = carla::sensor::data;
19namespace css = carla::sensor::s11n;
21
22// The custom V2X sensor ships a fixed 100-byte binary blob across the RPC
23// boundary via MsgPack (client -> server "send" path). These tests pin the
24// blob contract, the in-memory message containers, and the byte-for-byte
25// fidelity of the V2X serializers that feed the sensor data stream.
26
27TEST(CustomV2XBytes, default_construction_is_empty_with_hundred_byte_cap) {
28 CustomV2XBytes blob{};
29 EXPECT_EQ(blob.data_size, 0u);
30 EXPECT_EQ(blob.max_data_size(), 100u);
31 EXPECT_EQ(blob.bytes.max_size(), 100u);
32}
33
34TEST(CustomV2XBytes, msgpack_roundtrip_preserves_payload) {
35 CustomV2XBytes blob{};
36 blob.data_size = 4u;
37 blob.bytes[0] = 0xDE;
38 blob.bytes[1] = 0xAD;
39 blob.bytes[2] = 0xBE;
40 blob.bytes[3] = 0xEF;
41
42 auto buffer = carla::MsgPack::Pack(blob);
43 auto restored = carla::MsgPack::UnPack<CustomV2XBytes>(buffer);
44
45 EXPECT_EQ(restored.data_size, blob.data_size);
46 EXPECT_EQ(restored.bytes, blob.bytes);
47}
48
49TEST(CustomV2XBytes, msgpack_roundtrip_preserves_full_capacity_payload) {
50 CustomV2XBytes blob{};
51 blob.data_size = blob.max_data_size();
52 for (uint8_t i = 0; i < blob.data_size; ++i) {
53 blob.bytes[i] = static_cast<unsigned char>(i);
54 }
55
56 auto buffer = carla::MsgPack::Pack(blob);
57 auto restored = carla::MsgPack::UnPack<CustomV2XBytes>(buffer);
58
59 EXPECT_EQ(restored.data_size, 100u);
60 EXPECT_EQ(restored.bytes, blob.bytes);
61}
62
63TEST(CAMDataContainer, write_message_counts_and_reset_clears) {
64 csd::CAMDataS data;
65 EXPECT_EQ(data.GetMessageCount(), 0u);
66
68 first.Power = 21.5f;
69 first.Message.header.stationID = 7;
70 data.WriteMessage(first);
71
72 csd::CAMData second{};
73 second.Power = -12.0f;
74 second.Message.header.stationID = 9;
75 data.WriteMessage(second);
76
77 EXPECT_EQ(data.GetMessageCount(), 2u);
78
79 data.Reset();
80 EXPECT_EQ(data.GetMessageCount(), 0u);
81}
82
83TEST(CustomV2XDataContainer, write_message_counts_and_reset_clears) {
85 EXPECT_EQ(data.GetMessageCount(), 0u);
86
87 csd::CustomV2XData message{};
88 message.Power = 5.0f;
89 message.Message.header.stationID = 3;
90 message.Message.data.data_size = 2u;
91 message.Message.data.bytes[0] = 1u;
92 message.Message.data.bytes[1] = 2u;
93 data.WriteMessage(message);
94
95 EXPECT_EQ(data.GetMessageCount(), 1u);
96
97 data.Reset();
98 EXPECT_EQ(data.GetMessageCount(), 0u);
99}
100
101TEST(CAMDataSerializer, serialize_copies_messages_byte_for_byte) {
102 csd::CAMDataS data;
103
105 first.Power = 21.5f;
106 first.Message.header.stationID = 11;
107 data.WriteMessage(first);
108
109 csd::CAMData second{};
110 second.Power = 33.25f;
111 second.Message.header.stationID = 22;
112 data.WriteMessage(second);
113
114 carla::Buffer output = css::CAMDataSerializer::Serialize(0, data, carla::Buffer{});
115
116 ASSERT_EQ(output.size(), 2u * sizeof(csd::CAMData));
117 const auto *messages = reinterpret_cast<const csd::CAMData *>(output.data());
118 EXPECT_EQ(messages[0].Power, 21.5f);
119 EXPECT_EQ(messages[0].Message.header.stationID, 11);
120 EXPECT_EQ(messages[1].Power, 33.25f);
121 EXPECT_EQ(messages[1].Message.header.stationID, 22);
122}
123
124// The CAM wire type must carry the optional pathDeltaTime by value (with an
125// availability flag) instead of a raw pointer: CAMDataSerializer memcpys the
126// whole message onto the data stream, so a server-side pointer must never reach
127// the wire.
128TEST(PathPoint, delta_time_is_an_inline_value_not_a_pointer) {
129 static_assert(
130 std::is_same<decltype(ITSContainer::PathPoint_t::pathDeltaTime),
132 "pathDeltaTime must be stored by value so no server pointer reaches the wire");
133 static_assert(
134 std::is_trivially_copyable<ITSContainer::PathPoint_t>::value,
135 "PathPoint_t is copied byte-for-byte by the V2X serializer");
136
138 EXPECT_FALSE(point.pathDeltaTimeAvailable);
139 EXPECT_EQ(point.pathDeltaTime, 0);
140}
141
142TEST(CAMDataSerializer, serialize_preserves_inline_path_delta_time) {
143 csd::CAMDataS data;
144
145 csd::CAMData message{};
146 message.Power = 7.5f;
147 message.Message.header.stationID = 99;
148 auto &history =
149 message.Message.cam.camParameters.lowFrequencyContainer
150 .basicVehicleContainerLowFrequency.pathHistory;
151 history.NumberOfPathPoint = 1;
152 history.data[0].pathDeltaTime = 1234;
153 history.data[0].pathDeltaTimeAvailable = true;
154 data.WriteMessage(message);
155
156 carla::Buffer output = css::CAMDataSerializer::Serialize(0, data, carla::Buffer{});
157
158 ASSERT_EQ(output.size(), sizeof(csd::CAMData));
159 const auto *restored = reinterpret_cast<const csd::CAMData *>(output.data());
160 const auto &restored_history =
163 EXPECT_EQ(restored_history.NumberOfPathPoint, 1);
164 EXPECT_TRUE(restored_history.data[0].pathDeltaTimeAvailable);
165 EXPECT_EQ(restored_history.data[0].pathDeltaTime, 1234);
166}
167
168TEST(CustomV2XDataSerializer, serialize_preserves_binary_payload) {
170
171 csd::CustomV2XData message{};
172 message.Power = 18.0f;
173 message.Message.header.stationID = 42;
174 message.Message.data.data_size = 3u;
175 message.Message.data.bytes[0] = 0xAA;
176 message.Message.data.bytes[1] = 0xBB;
177 message.Message.data.bytes[2] = 0xCC;
178 data.WriteMessage(message);
179
180 carla::Buffer output = css::CustomV2XDataSerializer::Serialize(0, data, carla::Buffer{});
181
182 ASSERT_EQ(output.size(), sizeof(csd::CustomV2XData));
183 const auto *restored = reinterpret_cast<const csd::CustomV2XData *>(output.data());
184 EXPECT_EQ(restored->Power, 18.0f);
185 EXPECT_EQ(restored->Message.header.stationID, 42);
186 EXPECT_EQ(restored->Message.data.data_size, 3u);
187 EXPECT_EQ(restored->Message.data.bytes[0], 0xAA);
188 EXPECT_EQ(restored->Message.data.bytes[1], 0xBB);
189 EXPECT_EQ(restored->Message.data.bytes[2], 0xCC);
190}
long long first
Definition LaneGraph.cpp:34
geom::Point point
Definition LaneGraph.cpp:41
long PathDeltaTime_t
Definition LibITS.h:631
A piece of raw data.
const value_type * data() const noexcept
Direct access to the allocated memory or nullptr if no memory is allocated.
size_type size() const noexcept
static Buffer Pack(const T &obj)
Definition MsgPack.h:19
Fixed-size binary payload carried by the custom V2X sensor (sensor.other.v2x_custom).
void WriteMessage(const CAMData &message)
Adds a new message.
Definition V2XData.h:54
size_t GetMessageCount() const
Returns the number of currently received messages.
Definition V2XData.h:44
void Reset()
Deletes the current messages.
Definition V2XData.h:49
void Reset()
Deletes the current messages.
Definition V2XData.h:74
void WriteMessage(const CustomV2XData &message)
Adds a new message.
Definition V2XData.h:79
size_t GetMessageCount() const
Returns the number of currently received messages.
Definition V2XData.h:69
ITSContainer::PathHistory_t pathHistory
Definition LibITS.h:745
LowFrequencyContainer_t lowFrequencyContainer
Definition LibITS.h:762
CamParameters_t camParameters
Definition LibITS.h:770
BasicVehicleContainerLowFrequency_t basicVehicleContainerLowFrequency
Definition LibITS.h:753
CAMContainer::CoopAwareness_t cam
Definition LibITS.h:778
PathDeltaTime_t pathDeltaTime
Definition LibITS.h:639
TEST(CustomV2XBytes, default_construction_is_empty_with_hundred_byte_cap)