]> git.localhorst.tv Git - blank.git/blob - tst/net/PacketTest.cpp
exchange block updates with clients
[blank.git] / tst / net / PacketTest.cpp
1 #include "PacketTest.hpp"
2
3 #include "model/CompositeModel.hpp"
4 #include "world/Entity.hpp"
5
6 CPPUNIT_TEST_SUITE_REGISTRATION(blank::test::PacketTest);
7
8 using namespace std;
9
10 namespace blank {
11 namespace test {
12
13 void PacketTest::setUp() {
14         udp_pack.data = new Uint8[sizeof(Packet)];
15         udp_pack.maxlen = sizeof(Packet);
16 }
17
18 void PacketTest::tearDown() {
19         delete[] udp_pack.data;
20 }
21
22 namespace {
23
24 static constexpr uint32_t TEST_TAG = 0xFB1AB1AF;
25
26 }
27
28 void PacketTest::testSizes() {
29         CPPUNIT_ASSERT_EQUAL_MESSAGE(
30                 "unexpected size of vec3",
31                 size_t(12), sizeof(glm::vec3)
32         );
33         CPPUNIT_ASSERT_EQUAL_MESSAGE(
34                 "unexpected size of vec3i",
35                 size_t(12), sizeof(glm::ivec3)
36         );
37         CPPUNIT_ASSERT_EQUAL_MESSAGE(
38                 "unexpected size of quat",
39                 size_t(16), sizeof(glm::quat)
40         );
41         CPPUNIT_ASSERT_EQUAL_MESSAGE(
42                 "unexpected size of entity state",
43                 size_t(64), sizeof(EntityState)
44         );
45 }
46
47 void PacketTest::testControl() {
48         Packet::TControl ctrl;
49         ctrl.ack = 10;
50
51         CPPUNIT_ASSERT_MESSAGE(
52                 "TControl should ack the packet in the ack field",
53                 ctrl.Acks(10)
54         );
55         CPPUNIT_ASSERT_MESSAGE(
56                 "TControl should ack the packet in the future",
57                 !ctrl.Acks(11)
58         );
59         CPPUNIT_ASSERT_MESSAGE(
60                 "TControl should not ack a packet in the distant past",
61                 !ctrl.Acks(-30)
62         );
63         CPPUNIT_ASSERT_MESSAGE(
64                 "TControl should not ack the previous packet if the bitfield is 0",
65                 !ctrl.Acks(9)
66         );
67         CPPUNIT_ASSERT_EQUAL_MESSAGE(
68                 "TControl's acks should begin at the packet in the ack field",
69                 uint16_t(10), ctrl.AckBegin()
70         );
71         CPPUNIT_ASSERT_EQUAL_MESSAGE(
72                 "TControl's acks should end 33 packets before the one in the ack field",
73                 uint16_t(-23), ctrl.AckEnd()
74         );
75         ctrl.hist = 1;
76         CPPUNIT_ASSERT_MESSAGE(
77                 "TControl should ack the previous packet if the bitfield is 1",
78                 ctrl.Acks(9)
79         );
80         ctrl.hist = 2;
81         CPPUNIT_ASSERT_MESSAGE(
82                 "TControl should not ack the previous packet if the bitfield is 2",
83                 !ctrl.Acks(9)
84         );
85         CPPUNIT_ASSERT_MESSAGE(
86                 "TControl should ack the packet before the previous one if the bitfield is 2",
87                 ctrl.Acks(8)
88         );
89 }
90
91 void PacketTest::testPing() {
92         auto pack = Packet::Make<Packet::Ping>(udp_pack);
93         AssertPacket("Ping", 0, 0, pack);
94 }
95
96 void PacketTest::testLogin() {
97         auto pack = Packet::Make<Packet::Login>(udp_pack);
98         AssertPacket("Login", 1, 0, 32, pack);
99
100         string write_name = "test";
101         string read_name;
102         pack.WritePlayerName(write_name);
103         pack.ReadPlayerName(read_name);
104         CPPUNIT_ASSERT_EQUAL_MESSAGE(
105                 "player name not correctly transported in Login packet",
106                 write_name, read_name
107         );
108
109         write_name = "0123456789012345678901234567890123456789";
110         pack.WritePlayerName(write_name);
111         pack.ReadPlayerName(read_name);
112         CPPUNIT_ASSERT_EQUAL_MESSAGE(
113                 "player name not correctly truncated in Login packet",
114                 write_name.substr(0, 32), read_name
115         );
116 }
117
118 void PacketTest::testJoin() {
119         auto pack = Packet::Make<Packet::Join>(udp_pack);
120         AssertPacket("Join", 2, 68, 100, pack);
121
122         Entity write_entity;
123         write_entity.ID(534574);
124         write_entity.GetState().chunk_pos = { 7, 2, -3 };
125         write_entity.GetState().block_pos = { 1.5f, 0.9f, 12.0f };
126         write_entity.GetState().velocity = { 0.025f, 0.001f, 0.0f };
127         write_entity.GetState().orient = { 1.0f, 0.0f, 0.0f, 0.0f };
128         write_entity.GetState().ang_vel = { 0.01f, 0.00302f, 0.0985f };
129         uint32_t read_id = 0;
130         EntityState read_state;
131         pack.WritePlayer(write_entity);
132
133         pack.ReadPlayerID(read_id);
134         CPPUNIT_ASSERT_EQUAL_MESSAGE(
135                 "player entity ID not correctly transported in Join packet",
136                 write_entity.ID(), read_id
137         );
138         pack.ReadPlayerState(read_state);
139         AssertEqual(
140                 "player entity state not correctly transported in Join packet",
141                 write_entity.GetState(), read_state
142         );
143
144         string write_name = "test";
145         string read_name;
146         pack.WriteWorldName(write_name);
147         pack.ReadWorldName(read_name);
148         CPPUNIT_ASSERT_EQUAL_MESSAGE(
149                 "world name not correctly transported in Join packet",
150                 write_name, read_name
151         );
152
153         write_name = "0123456789012345678901234567890123456789";
154         pack.WriteWorldName(write_name);
155         pack.ReadWorldName(read_name);
156         CPPUNIT_ASSERT_EQUAL_MESSAGE(
157                 "world name not correctly truncated in Join packet",
158                 write_name.substr(0, 32), read_name
159         );
160 }
161
162 void PacketTest::testPart() {
163         auto pack = Packet::Make<Packet::Part>(udp_pack);
164         AssertPacket("Part", 3, 0, pack);
165 }
166
167 void PacketTest::testPlayerUpdate() {
168         auto pack = Packet::Make<Packet::PlayerUpdate>(udp_pack);
169         AssertPacket("PlayerUpdate", 4, 76, pack);
170
171         EntityState write_state;
172         write_state.chunk_pos = { 7, 2, -3 };
173         write_state.block_pos = { 1.5f, 0.9f, 12.0f };
174         write_state.velocity = { 0.025f, 0.001f, 0.0f };
175         write_state.orient = { 1.0f, 0.0f, 0.0f, 0.0f };
176         write_state.ang_vel = { 0.01f, 0.00302f, 0.0985f };
177         glm::vec3 write_movement(0.5f, -1.0f, 1.0f);
178         float write_pitch = 1.25f;
179         float write_yaw = -2.5f;
180         uint8_t write_actions = 0x05;
181         uint8_t write_slot = 3;
182         pack.WritePredictedState(write_state);
183         pack.WriteMovement(write_movement);
184         pack.WritePitch(write_pitch);
185         pack.WriteYaw(write_yaw);
186         pack.WriteActions(write_actions);
187         pack.WriteSlot(write_slot);
188
189         EntityState read_state;
190         glm::vec3 read_movement;
191         float read_pitch;
192         float read_yaw;
193         uint8_t read_actions;
194         uint8_t read_slot;
195         pack.ReadPredictedState(read_state);
196         pack.ReadMovement(read_movement);
197         pack.ReadPitch(read_pitch);
198         pack.ReadYaw(read_yaw);
199         pack.ReadActions(read_actions);
200         pack.ReadSlot(read_slot);
201         AssertEqual(
202                 "player predicted entity state not correctly transported in PlayerUpdate packet",
203                 write_state, read_state
204         );
205         AssertEqual(
206                 "player movement input not correctly transported in PlayerUpdate packet",
207                 write_movement, read_movement, 0.0001f
208         );
209         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
210                 "player pitch input not correctly transported in PlayerUpdate packet",
211                 write_pitch, read_pitch, 0.0001f
212         );
213         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
214                 "player yaw input not correctly transported in PlayerUpdate packet",
215                 write_yaw, read_yaw, 0.0001f
216         );
217         CPPUNIT_ASSERT_EQUAL_MESSAGE(
218                 "player actions not correctly transported in PlayerUpdate packet",
219                 int(write_actions), int(read_actions)
220         );
221         CPPUNIT_ASSERT_EQUAL_MESSAGE(
222                 "player inventory slot not correctly transported in PlayerUpdate packet",
223                 int(write_slot), int(read_slot)
224         );
225 }
226
227 void PacketTest::testSpawnEntity() {
228         auto pack = Packet::Make<Packet::SpawnEntity>(udp_pack);
229         AssertPacket("SpawnEntity", 5, 100, 132, pack);
230
231         Entity write_entity;
232         write_entity.ID(534574);
233         CompositeModel model;
234         model.ID(23);
235         model.Instantiate(write_entity.GetModel());
236         write_entity.GetState().chunk_pos = { 7, 2, -3 };
237         write_entity.GetState().block_pos = { 1.5f, 0.9f, 12.0f };
238         write_entity.GetState().velocity = { 0.025f, 0.001f, 0.0f };
239         write_entity.GetState().orient = { 1.0f, 0.0f, 0.0f, 0.0f };
240         write_entity.GetState().ang_vel = { 0.01f, 0.00302f, 0.0985f };
241         write_entity.Bounds({{ -1, -1, -1 }, { 1, 1, 1 }});
242         write_entity.WorldCollidable(true);
243         write_entity.Name("blah");
244         pack.WriteEntity(write_entity);
245
246         uint32_t entity_id;
247         uint32_t skeleton_id;
248         Entity read_entity;
249         pack.ReadEntityID(entity_id);
250         pack.ReadSkeletonID(skeleton_id);
251         pack.ReadEntity(read_entity);
252
253         CPPUNIT_ASSERT_EQUAL_MESSAGE(
254                 "entity ID not correctly transported in SpawnEntity packet",
255                 write_entity.ID(), entity_id
256         );
257         CPPUNIT_ASSERT_EQUAL_MESSAGE(
258                 "skeleton ID not correctly transported in SpawnEntity packet",
259                 write_entity.GetModel().GetModel().ID(), skeleton_id
260         );
261         AssertEqual(
262                 "entity state not correctly transported in PlayerUpdate packet",
263                 write_entity.GetState(), read_entity.GetState()
264         );
265         AssertEqual(
266                 "entity bounds not correctly transported in PlayerUpdate packet",
267                 write_entity.Bounds(), read_entity.Bounds()
268         );
269         CPPUNIT_ASSERT_MESSAGE(
270                 "entity flags not correctly transported in SpawnEntity packet",
271                 read_entity.WorldCollidable()
272         );
273         CPPUNIT_ASSERT_EQUAL_MESSAGE(
274                 "entity name not correctly transported in SpawnEntity packet",
275                 write_entity.Name(), read_entity.Name()
276         );
277 }
278
279 void PacketTest::testDespawnEntity() {
280         auto pack = Packet::Make<Packet::DespawnEntity>(udp_pack);
281         AssertPacket("DespawnEntity", 6, 4, pack);
282
283         uint32_t write_id = 5437;
284         uint32_t read_id;
285         pack.WriteEntityID(write_id);
286         pack.ReadEntityID(read_id);
287
288         CPPUNIT_ASSERT_EQUAL_MESSAGE(
289                 "entity ID not correctly transported in DespawnEntity packet",
290                 write_id, read_id
291         );
292 }
293
294 void PacketTest::testEntityUpdate() {
295         auto pack = Packet::Make<Packet::EntityUpdate>(udp_pack);
296         AssertPacket("EntityUpdate", 7, 4, 480, pack);
297
298         pack.length = Packet::EntityUpdate::GetSize(3);
299         CPPUNIT_ASSERT_EQUAL_MESSAGE(
300                 "length not correctly set in EntityUpdate packet",
301                 size_t(4 + 3 * 68), pack.length
302         );
303
304         uint32_t write_count = 3;
305         uint32_t read_count;
306         pack.WriteEntityCount(write_count);
307         pack.ReadEntityCount(read_count);
308         CPPUNIT_ASSERT_EQUAL_MESSAGE(
309                 "entity count not correctly transported in EntityUpdate packet",
310                 write_count, read_count
311         );
312
313         Entity write_entity;
314         write_entity.ID(8567234);
315         write_entity.GetState().chunk_pos = { 7, 2, -3 };
316         write_entity.GetState().block_pos = { 1.5f, 0.9f, 12.0f };
317         write_entity.GetState().velocity = { 0.025f, 0.001f, 0.0f };
318         write_entity.GetState().orient = { 1.0f, 0.0f, 0.0f, 0.0f };
319         write_entity.GetState().ang_vel = { 0.01f, 0.00302f, 0.0985f };
320         pack.WriteEntity(write_entity, 1);
321         pack.WriteEntity(write_entity, 0);
322         pack.WriteEntity(write_entity, 2);
323
324         uint32_t read_id;
325         EntityState read_state;
326         pack.ReadEntityID(read_id, 1);
327         pack.ReadEntityState(read_state, 1);
328         CPPUNIT_ASSERT_EQUAL_MESSAGE(
329                 "entity ID not correctly transported in EntityUpdate packet",
330                 write_entity.ID(), read_id
331         );
332         AssertEqual(
333                 "entity state not correctly transported in EntityUpdate packet",
334                 write_entity.GetState(), read_state
335         );
336 }
337
338 void PacketTest::testPlayerCorrection() {
339         auto pack = Packet::Make<Packet::PlayerCorrection>(udp_pack);
340         AssertPacket("PlayerCorrection", 8, 66, pack);
341
342         uint16_t write_seq = 50050;
343         uint16_t read_seq;
344         pack.WritePacketSeq(write_seq);
345         pack.ReadPacketSeq(read_seq);
346         CPPUNIT_ASSERT_EQUAL_MESSAGE(
347                 "packet sequence not correctly transported in PlayerCorrection packet",
348                 write_seq, read_seq
349         );
350
351         Entity write_entity;
352         write_entity.GetState().chunk_pos = { 7, 2, -3 };
353         write_entity.GetState().block_pos = { 1.5f, 0.9f, 12.0f };
354         write_entity.GetState().velocity = { 0.025f, 0.001f, 0.0f };
355         write_entity.GetState().orient = { 1.0f, 0.0f, 0.0f, 0.0f };
356         write_entity.GetState().ang_vel = { 0.01f, 0.00302f, 0.0985f };
357         pack.WritePlayer(write_entity);
358
359         EntityState read_state;
360         pack.ReadPlayerState(read_state);
361         AssertEqual(
362                 "entity state not correctly transported in PlayerCorrection packet",
363                 write_entity.GetState(), read_state
364         );
365 }
366
367 void PacketTest::testChunkBegin() {
368         auto pack = Packet::Make<Packet::ChunkBegin>(udp_pack);
369         AssertPacket("ChunkBegin", 9, 24, pack);
370
371         uint32_t write_id = 532;
372         uint32_t write_flags = 9864328;
373         glm::ivec3 write_pos = { -6, 15, 38 };
374         uint32_t write_size = 4097;
375
376         pack.WriteTransmissionId(write_id);
377         pack.WriteFlags(write_flags);
378         pack.WriteChunkCoords(write_pos);
379         pack.WriteDataSize(write_size);
380
381         uint32_t read_id;
382         uint32_t read_flags;
383         glm::ivec3 read_pos;
384         uint32_t read_size;
385
386         pack.ReadTransmissionId(read_id);
387         pack.ReadFlags(read_flags);
388         pack.ReadChunkCoords(read_pos);
389         pack.ReadDataSize(read_size);
390
391         CPPUNIT_ASSERT_EQUAL_MESSAGE(
392                 "transmission ID not correctly transported in ChunkBegin packet",
393                 write_id, read_id
394         );
395         CPPUNIT_ASSERT_EQUAL_MESSAGE(
396                 "flags not correctly transported in ChunkBegin packet",
397                 write_flags, read_flags
398         );
399         AssertEqual(
400                 "chunk coordinates not correctly transported in ChunkBegin packet",
401                 write_pos, read_pos
402         );
403         CPPUNIT_ASSERT_EQUAL_MESSAGE(
404                 "data size not correctly transported in ChunkBegin packet",
405                 write_size, read_size
406         );
407 }
408
409 void PacketTest::testChunkData() {
410         auto pack = Packet::Make<Packet::ChunkData>(udp_pack);
411         AssertPacket("ChunkData", 10, 12, 484, pack);
412
413         constexpr size_t block_size = 97;
414
415         uint32_t write_id = 6743124;
416         uint32_t write_offset = 8583;
417         uint32_t write_size = block_size;
418         uint8_t write_data[block_size];
419         memset(write_data, 'X', block_size);
420
421         pack.WriteTransmissionId(write_id);
422         pack.WriteDataOffset(write_offset);
423         pack.WriteDataSize(write_size);
424         pack.WriteData(write_data, write_size);
425
426         uint32_t read_id;
427         uint32_t read_offset;
428         uint32_t read_size;
429         uint8_t read_data[block_size];
430
431         pack.ReadTransmissionId(read_id);
432         pack.ReadDataOffset(read_offset);
433         pack.ReadDataSize(read_size);
434         pack.ReadData(read_data, read_size);
435
436         CPPUNIT_ASSERT_EQUAL_MESSAGE(
437                 "transmission ID not correctly transported in ChunkData packet",
438                 write_id, read_id
439         );
440         CPPUNIT_ASSERT_EQUAL_MESSAGE(
441                 "data offset not correctly transported in ChunkData packet",
442                 write_offset, read_offset
443         );
444         CPPUNIT_ASSERT_EQUAL_MESSAGE(
445                 "data size not correctly transported in ChunkData packet",
446                 write_size, read_size
447         );
448         CPPUNIT_ASSERT_EQUAL_MESSAGE(
449                 "raw data not correctly transported in ChunkData packet",
450                 string(write_data, write_data + write_size), string(read_data, read_data + read_size)
451         );
452 }
453
454 void PacketTest::testBlockUpdate() {
455         auto pack = Packet::Make<Packet::BlockUpdate>(udp_pack);
456         AssertPacket("BlockUpdate", 11, 16, 484, pack);
457
458         pack.length = Packet::BlockUpdate::GetSize(3);
459         CPPUNIT_ASSERT_EQUAL_MESSAGE(
460                 "length not correctly set in BlockUpdate packet",
461                 size_t(16 + 3 * 6), pack.length
462         );
463
464         glm::ivec3 write_coords(432, -325, 99998);
465         uint32_t write_count = 3;
466         uint16_t write_index = 432;
467         Block write_block(324, Block::FACE_DOWN, Block::TURN_AROUND);
468
469         pack.WriteChunkCoords(write_coords);
470         pack.WriteBlockCount(write_count);
471         pack.WriteIndex(write_index, 1);
472         pack.WriteBlock(write_block, 1);
473         pack.WriteIndex(write_index, 0);
474         pack.WriteBlock(write_block, 0);
475         pack.WriteIndex(write_index, 2);
476         pack.WriteBlock(write_block, 2);
477
478         glm::ivec3 read_coords;
479         uint32_t read_count;
480         uint16_t read_index;
481         Block read_block;
482
483         pack.ReadChunkCoords(read_coords);
484         pack.ReadBlockCount(read_count);
485         pack.ReadIndex(read_index, 1);
486         pack.ReadBlock(read_block, 1);
487
488         AssertEqual(
489                 "chunk coordinates not correctly transported in BlockUpdate packet",
490                 write_coords, read_coords
491         );
492         CPPUNIT_ASSERT_EQUAL_MESSAGE(
493                 "block count not correctly transported in BlockUpdate packet",
494                 write_count, read_count
495         );
496         CPPUNIT_ASSERT_EQUAL_MESSAGE(
497                 "block index not correctly transported in BlockUpdate packet",
498                 write_index, read_index
499         );
500         CPPUNIT_ASSERT_EQUAL_MESSAGE(
501                 "block type not correctly transported in BlockUpdate packet",
502                 write_block.type, read_block.type
503         );
504         CPPUNIT_ASSERT_EQUAL_MESSAGE(
505                 "block face not correctly transported in BlockUpdate packet",
506                 write_block.GetFace(), read_block.GetFace()
507         );
508         CPPUNIT_ASSERT_EQUAL_MESSAGE(
509                 "block turn not correctly transported in BlockUpdate packet",
510                 write_block.GetTurn(), read_block.GetTurn()
511         );
512 }
513
514
515 void PacketTest::AssertPacket(
516         const string &name,
517         uint8_t expected_type,
518         size_t expected_length,
519         const Packet::Payload &actual
520 ) {
521         CPPUNIT_ASSERT_EQUAL_MESSAGE(
522                 name + " packet not correctly tagged",
523                 TEST_TAG, actual.GetHeader().tag
524         );
525         CPPUNIT_ASSERT_EQUAL_MESSAGE(
526                 "wrong type code for " + name + " packet",
527                 int(expected_type), int(actual.GetHeader().type)
528         );
529         CPPUNIT_ASSERT_EQUAL_MESSAGE(
530                 "bad payload length for " + name + " packet",
531                 expected_length, actual.length
532         );
533 }
534
535 void PacketTest::AssertPacket(
536         const string &name,
537         uint8_t expected_type,
538         size_t min_length,
539         size_t max_length,
540         const Packet::Payload &actual
541 ) {
542         CPPUNIT_ASSERT_EQUAL_MESSAGE(
543                 name + " packet not correctly tagged",
544                 TEST_TAG, actual.GetHeader().tag
545         );
546         CPPUNIT_ASSERT_EQUAL_MESSAGE(
547                 "wrong type code for " + name + " packet",
548                 expected_type, actual.GetHeader().type
549         );
550         CPPUNIT_ASSERT_MESSAGE(
551                 "bad payload length for " + name + " packet",
552                 actual.length >= min_length && actual.length <= max_length
553         );
554 }
555
556 void PacketTest::AssertEqual(
557         const string &message,
558         const EntityState &expected,
559         const EntityState &actual
560 ) {
561         AssertEqual(
562                 message + ": bad chunk position",
563                 expected.chunk_pos, actual.chunk_pos
564         );
565         AssertEqual(
566                 message + ": bad block position",
567                 expected.block_pos, actual.block_pos
568         );
569         AssertEqual(
570                 message + ": bad velocity",
571                 expected.velocity, actual.velocity
572         );
573         AssertEqual(
574                 message + ": bad orientation",
575                 expected.orient, actual.orient
576         );
577         AssertEqual(
578                 message + ": bad angular velocity",
579                 expected.ang_vel, actual.ang_vel
580         );
581 }
582
583 void PacketTest::AssertEqual(
584         const string &message,
585         const AABB &expected,
586         const AABB &actual
587 ) {
588         AssertEqual(
589                 message + ": bad lower bound",
590                 expected.min, actual.min
591         );
592         AssertEqual(
593                 message + ": bad upper bound",
594                 expected.max, actual.max
595         );
596 }
597
598 void PacketTest::AssertEqual(
599         const string &message,
600         const glm::ivec3 &expected,
601         const glm::ivec3 &actual
602 ) {
603         CPPUNIT_ASSERT_EQUAL_MESSAGE(
604                 message + " (X component)",
605                 expected.x, actual.x
606         );
607         CPPUNIT_ASSERT_EQUAL_MESSAGE(
608                 message + " (Y component)",
609                 expected.y, actual.y
610         );
611         CPPUNIT_ASSERT_EQUAL_MESSAGE(
612                 message + " (Z component)",
613                 expected.z, actual.z
614         );
615 }
616
617 void PacketTest::AssertEqual(
618         const string &message,
619         const glm::vec3 &expected,
620         const glm::vec3 &actual,
621         float epsilon
622 ) {
623         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
624                 message + " (X component)",
625                 expected.x, actual.x, epsilon
626         );
627         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
628                 message + " (Y component)",
629                 expected.y, actual.y, epsilon
630         );
631         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
632                 message + " (Z component)",
633                 expected.z, actual.z, epsilon
634         );
635 }
636
637 void PacketTest::AssertEqual(
638         const string &message,
639         const glm::quat &expected,
640         const glm::quat &actual
641 ) {
642         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
643                 message + " (W component)",
644                 expected.w, actual.w, numeric_limits<float>::epsilon()
645         );
646         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
647                 message + " (X component)",
648                 expected.x, actual.x, numeric_limits<float>::epsilon()
649         );
650         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
651                 message + " (Y component)",
652                 expected.y, actual.y, numeric_limits<float>::epsilon()
653         );
654         CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(
655                 message + " (Z component)",
656                 expected.z, actual.z, numeric_limits<float>::epsilon()
657         );
658 }
659
660 }
661 }