1 | #include <gtest/gtest.h> |
2 | |
3 | #include <base/detect.h> |
4 | #include <engine/external/json-parser/json.h> |
5 | #include <engine/server.h> |
6 | #include <engine/shared/config.h> |
7 | #include <game/gamecore.h> |
8 | #include <game/server/teehistorian.h> |
9 | |
10 | #include <vector> |
11 | |
12 | void RegisterGameUuids(CUuidManager *pManager); |
13 | |
14 | class TeeHistorian : public ::testing::Test |
15 | { |
16 | protected: |
17 | CTeeHistorian m_TH; |
18 | CConfig m_Config; |
19 | CTuningParams m_Tuning; |
20 | CUuidManager m_UuidManager; |
21 | CTeeHistorian::CGameInfo m_GameInfo; |
22 | |
23 | std::vector<unsigned char> m_vBuffer; |
24 | |
25 | enum |
26 | { |
27 | STATE_NONE, |
28 | STATE_PLAYERS, |
29 | STATE_INPUTS, |
30 | }; |
31 | |
32 | int m_State; |
33 | |
34 | TeeHistorian() |
35 | { |
36 | mem_zero(block: &m_Config, size: sizeof(m_Config)); |
37 | #define MACRO_CONFIG_INT(Name, ScriptName, Def, Min, Max, Save, Desc) \ |
38 | m_Config.m_##Name = (Def); |
39 | #define MACRO_CONFIG_COL(Name, ScriptName, Def, Save, Desc) MACRO_CONFIG_INT(Name, ScriptName, Def, 0, 0, Save, Desc) |
40 | #define MACRO_CONFIG_STR(Name, ScriptName, Len, Def, Save, Desc) \ |
41 | str_copy(m_Config.m_##Name, (Def), sizeof(m_Config.m_##Name)); |
42 | #include <engine/shared/config_variables.h> |
43 | #undef MACRO_CONFIG_STR |
44 | #undef MACRO_CONFIG_COL |
45 | #undef MACRO_CONFIG_INT |
46 | |
47 | RegisterUuids(pManager: &m_UuidManager); |
48 | RegisterTeehistorianUuids(pManager: &m_UuidManager); |
49 | RegisterGameUuids(pManager: &m_UuidManager); |
50 | |
51 | SHA256_DIGEST Sha256 = {.data: {0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89, |
52 | 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89, |
53 | 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89, |
54 | 0x01, 0x23}}; |
55 | |
56 | mem_zero(block: &m_GameInfo, size: sizeof(m_GameInfo)); |
57 | |
58 | m_GameInfo.m_GameUuid = CalculateUuid(pName: "test@ddnet.tw" ); |
59 | m_GameInfo.m_pServerVersion = "DDNet test" ; |
60 | m_GameInfo.m_StartTime = time(timer: 0); |
61 | m_GameInfo.m_pPrngDescription = "test-prng:02468ace" ; |
62 | |
63 | m_GameInfo.m_pServerName = "server name" ; |
64 | m_GameInfo.m_ServerPort = 8303; |
65 | m_GameInfo.m_pGameType = "game type" ; |
66 | |
67 | m_GameInfo.m_pMapName = "Kobra 3 Solo" ; |
68 | m_GameInfo.m_MapSize = 903514; |
69 | m_GameInfo.m_MapSha256 = Sha256; |
70 | m_GameInfo.m_MapCrc = 0xeceaf25c; |
71 | |
72 | m_GameInfo.m_HavePrevGameUuid = false; |
73 | mem_zero(block: &m_GameInfo.m_PrevGameUuid, size: sizeof(m_GameInfo.m_PrevGameUuid)); |
74 | |
75 | m_GameInfo.m_pConfig = &m_Config; |
76 | m_GameInfo.m_pTuning = &m_Tuning; |
77 | m_GameInfo.m_pUuids = &m_UuidManager; |
78 | |
79 | Reset(pGameInfo: &m_GameInfo); |
80 | } |
81 | |
82 | static void WriteBuffer(std::vector<unsigned char> &vBuffer, const void *pData, size_t DataSize) |
83 | { |
84 | if(DataSize <= 0) |
85 | return; |
86 | |
87 | const size_t OldSize = vBuffer.size(); |
88 | vBuffer.resize(new_size: OldSize + DataSize); |
89 | mem_copy(dest: &vBuffer[OldSize], source: pData, size: DataSize); |
90 | } |
91 | |
92 | static void Write(const void *pData, int DataSize, void *pUser) |
93 | { |
94 | TeeHistorian *pThis = (TeeHistorian *)pUser; |
95 | WriteBuffer(vBuffer&: pThis->m_vBuffer, pData, DataSize); |
96 | } |
97 | |
98 | void Reset(const CTeeHistorian::CGameInfo *pGameInfo) |
99 | { |
100 | m_vBuffer.clear(); |
101 | m_TH.Reset(pGameInfo, pfnWriteCallback: Write, pUser: this); |
102 | m_State = STATE_NONE; |
103 | } |
104 | |
105 | void Expect(const unsigned char *pOutput, size_t OutputSize) |
106 | { |
107 | static CUuid TEEHISTORIAN_UUID = CalculateUuid(pName: "teehistorian@ddnet.tw" ); |
108 | static const char PREFIX1[] = "{\"comment\":\"teehistorian@ddnet.tw\",\"version\":\"2\",\"version_minor\":\"8\",\"game_uuid\":\"a1eb7182-796e-3b3e-941d-38ca71b2a4a8\",\"server_version\":\"DDNet test\",\"start_time\":\"" ; |
109 | static const char PREFIX2[] = "\",\"server_name\":\"server name\",\"server_port\":\"8303\",\"game_type\":\"game type\",\"map_name\":\"Kobra 3 Solo\",\"map_size\":\"903514\",\"map_sha256\":\"0123456789012345678901234567890123456789012345678901234567890123\",\"map_crc\":\"eceaf25c\",\"prng_description\":\"test-prng:02468ace\",\"config\":{},\"tuning\":{},\"uuids\":[" ; |
110 | static const char PREFIX3[] = "]}" ; |
111 | |
112 | char aTimeBuf[64]; |
113 | str_timestamp_ex(time: m_GameInfo.m_StartTime, buffer: aTimeBuf, buffer_size: sizeof(aTimeBuf), format: "%Y-%m-%dT%H:%M:%S%z" ); |
114 | |
115 | std::vector<unsigned char> vBuffer; |
116 | WriteBuffer(vBuffer, pData: &TEEHISTORIAN_UUID, DataSize: sizeof(TEEHISTORIAN_UUID)); |
117 | WriteBuffer(vBuffer, pData: PREFIX1, DataSize: str_length(str: PREFIX1)); |
118 | WriteBuffer(vBuffer, pData: aTimeBuf, DataSize: str_length(str: aTimeBuf)); |
119 | WriteBuffer(vBuffer, pData: PREFIX2, DataSize: str_length(str: PREFIX2)); |
120 | for(int i = 0; i < m_UuidManager.NumUuids(); i++) |
121 | { |
122 | char aBuf[64]; |
123 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s\"%s\"" , |
124 | i == 0 ? "" : "," , |
125 | m_UuidManager.GetName(Id: OFFSET_UUID + i)); |
126 | WriteBuffer(vBuffer, pData: aBuf, DataSize: str_length(str: aBuf)); |
127 | } |
128 | WriteBuffer(vBuffer, pData: PREFIX3, DataSize: str_length(str: PREFIX3)); |
129 | WriteBuffer(vBuffer, pData: "" , DataSize: 1); |
130 | WriteBuffer(vBuffer, pData: pOutput, DataSize: OutputSize); |
131 | |
132 | ExpectFull(pOutput: vBuffer.data(), OutputSize: vBuffer.size()); |
133 | } |
134 | |
135 | void ExpectFull(const unsigned char *pOutput, size_t OutputSize) |
136 | { |
137 | const ::testing::TestInfo *pTestInfo = |
138 | ::testing::UnitTest::GetInstance()->current_test_info(); |
139 | const char *pTestName = pTestInfo->name(); |
140 | |
141 | if(m_vBuffer.size() != OutputSize || mem_comp(a: m_vBuffer.data(), b: pOutput, size: OutputSize) != 0) |
142 | { |
143 | char aFilename[IO_MAX_PATH_LENGTH]; |
144 | IOHANDLE File; |
145 | |
146 | str_format(buffer: aFilename, buffer_size: sizeof(aFilename), format: "%sGot.teehistorian" , pTestName); |
147 | File = io_open(filename: aFilename, flags: IOFLAG_WRITE); |
148 | ASSERT_TRUE(File); |
149 | io_write(io: File, buffer: m_vBuffer.data(), size: m_vBuffer.size()); |
150 | io_close(io: File); |
151 | |
152 | str_format(buffer: aFilename, buffer_size: sizeof(aFilename), format: "%sExpected.teehistorian" , pTestName); |
153 | File = io_open(filename: aFilename, flags: IOFLAG_WRITE); |
154 | ASSERT_TRUE(File); |
155 | io_write(io: File, buffer: pOutput, size: OutputSize); |
156 | io_close(io: File); |
157 | } |
158 | |
159 | printf(format: "pOutput = {" ); |
160 | size_t Start = 0; // skip over header; |
161 | for(size_t i = 0; i < m_vBuffer.size(); i++) |
162 | { |
163 | if(Start == 0) |
164 | { |
165 | if(m_vBuffer[i] == 0) |
166 | Start = i + 1; |
167 | continue; |
168 | } |
169 | if((i - Start) % 10 == 0) |
170 | printf(format: "\n\t" ); |
171 | else |
172 | printf(format: ", " ); |
173 | printf(format: "0x%.2x" , m_vBuffer[i]); |
174 | } |
175 | printf(format: "\n}\n" ); |
176 | ASSERT_EQ(m_vBuffer.size(), OutputSize); |
177 | ASSERT_TRUE(mem_comp(m_vBuffer.data(), pOutput, OutputSize) == 0); |
178 | } |
179 | |
180 | void Tick(int Tick) |
181 | { |
182 | if(m_State == STATE_PLAYERS) |
183 | { |
184 | Inputs(); |
185 | } |
186 | if(m_State == STATE_INPUTS) |
187 | { |
188 | m_TH.EndInputs(); |
189 | m_TH.EndTick(); |
190 | } |
191 | m_TH.BeginTick(Tick); |
192 | m_TH.BeginPlayers(); |
193 | m_State = STATE_PLAYERS; |
194 | } |
195 | void Inputs() |
196 | { |
197 | m_TH.EndPlayers(); |
198 | m_TH.BeginInputs(); |
199 | m_State = STATE_INPUTS; |
200 | } |
201 | void Finish() |
202 | { |
203 | if(m_State == STATE_PLAYERS) |
204 | { |
205 | Inputs(); |
206 | } |
207 | if(m_State == STATE_INPUTS) |
208 | { |
209 | m_TH.EndInputs(); |
210 | m_TH.EndTick(); |
211 | } |
212 | m_TH.Finish(); |
213 | } |
214 | void DeadPlayer(int ClientId) |
215 | { |
216 | m_TH.RecordDeadPlayer(ClientId); |
217 | } |
218 | void Player(int ClientId, int x, int y) |
219 | { |
220 | CNetObj_CharacterCore Char; |
221 | mem_zero(block: &Char, size: sizeof(Char)); |
222 | Char.m_X = x; |
223 | Char.m_Y = y; |
224 | m_TH.RecordPlayer(ClientId, pChar: &Char); |
225 | } |
226 | }; |
227 | |
228 | TEST_F(TeeHistorian, Empty) |
229 | { |
230 | Expect(pOutput: (const unsigned char *)"" , OutputSize: 0); |
231 | } |
232 | |
233 | TEST_F(TeeHistorian, Finished) |
234 | { |
235 | const unsigned char EXPECTED[] = {0x40}; // FINISH |
236 | m_TH.Finish(); |
237 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
238 | } |
239 | |
240 | TEST_F(TeeHistorian, TickImplicitOneTick) |
241 | { |
242 | const unsigned char EXPECTED[] = { |
243 | 0x42, 0x00, 0x01, 0x02, // PLAYERNEW cid=0 x=1 y=2 |
244 | 0x40, // FINISH |
245 | }; |
246 | Tick(Tick: 1); |
247 | Player(ClientId: 0, x: 1, y: 2); |
248 | Finish(); |
249 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
250 | } |
251 | |
252 | TEST_F(TeeHistorian, TickImplicitTwoTicks) |
253 | { |
254 | const unsigned char EXPECTED[] = { |
255 | 0x42, 0x00, 0x01, 0x02, // PLAYER_NEW cid=0 x=1 y=2 |
256 | 0x00, 0x01, 0x40, // PLAYER cid=0 dx=1 dy=-1 |
257 | 0x40, // FINISH |
258 | }; |
259 | Tick(Tick: 1); |
260 | Player(ClientId: 0, x: 1, y: 2); |
261 | Tick(Tick: 2); |
262 | Player(ClientId: 0, x: 2, y: 1); |
263 | Finish(); |
264 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
265 | } |
266 | |
267 | TEST_F(TeeHistorian, TickImplicitDescendingClientId) |
268 | { |
269 | const unsigned char EXPECTED[] = { |
270 | 0x42, 0x01, 0x02, 0x03, // PLAYER_NEW cid=1 x=2 y=3 |
271 | 0x42, 0x00, 0x04, 0x05, // PLAYER_NEW cid=0 x=4 y=5 |
272 | 0x40, // FINISH |
273 | }; |
274 | Tick(Tick: 1); |
275 | DeadPlayer(ClientId: 0); |
276 | Player(ClientId: 1, x: 2, y: 3); |
277 | Tick(Tick: 2); |
278 | Player(ClientId: 0, x: 4, y: 5); |
279 | Player(ClientId: 1, x: 2, y: 3); |
280 | Finish(); |
281 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
282 | } |
283 | |
284 | TEST_F(TeeHistorian, TickExplicitAscendingClientId) |
285 | { |
286 | const unsigned char EXPECTED[] = { |
287 | 0x42, 0x00, 0x04, 0x05, // PLAYER_NEW cid=0 x=4 y=5 |
288 | 0x41, 0x00, // TICK_SKIP dt=0 |
289 | 0x42, 0x01, 0x02, 0x03, // PLAYER_NEW cid=1 x=2 y=3 |
290 | 0x40, // FINISH |
291 | }; |
292 | Tick(Tick: 1); |
293 | Player(ClientId: 0, x: 4, y: 5); |
294 | DeadPlayer(ClientId: 1); |
295 | Tick(Tick: 2); |
296 | Player(ClientId: 0, x: 4, y: 5); |
297 | Player(ClientId: 1, x: 2, y: 3); |
298 | Finish(); |
299 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
300 | } |
301 | |
302 | TEST_F(TeeHistorian, TickImplicitEmpty) |
303 | { |
304 | const unsigned char EXPECTED[] = { |
305 | 0x40, // FINISH |
306 | }; |
307 | for(int i = 1; i < 500; i++) |
308 | { |
309 | Tick(Tick: i); |
310 | } |
311 | for(int i = 1000; i < 100000; i += 1000) |
312 | { |
313 | Tick(Tick: i); |
314 | } |
315 | Finish(); |
316 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
317 | } |
318 | |
319 | TEST_F(TeeHistorian, TickExplicitStart) |
320 | { |
321 | const unsigned char EXPECTED[] = { |
322 | 0x41, 0xb3, 0x07, // TICK_SKIP dt=499 |
323 | 0x42, 0x00, 0x40, 0x40, // PLAYER_NEW cid=0 x=-1 y=-1 |
324 | 0x40, // FINISH |
325 | }; |
326 | Tick(Tick: 500); |
327 | Player(ClientId: 0, x: -1, y: -1); |
328 | Finish(); |
329 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
330 | } |
331 | |
332 | TEST_F(TeeHistorian, TickExplicitPlayerMessage) |
333 | { |
334 | const unsigned char EXPECTED[] = { |
335 | 0x41, 0x00, // TICK_SKIP dt=0 |
336 | 0x46, 0x3f, 0x01, 0x00, // MESSAGE cid=63 msg="\0" |
337 | 0x40, // FINISH |
338 | }; |
339 | Tick(Tick: 1); |
340 | Inputs(); |
341 | m_TH.RecordPlayerMessage(ClientId: 63, pMsg: "" , MsgSize: 1); |
342 | Finish(); |
343 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
344 | } |
345 | |
346 | TEST_F(TeeHistorian, ExtraMessage) |
347 | { |
348 | const unsigned char EXPECTED[] = { |
349 | 0x41, 0x00, // TICK_SKIP dt=0 |
350 | // EX uuid=6bb8ba88-0f0b-382e-8dae-dbf4052b8b7d data_len=0 |
351 | 0x4a, |
352 | 0x6b, 0xb8, 0xba, 0x88, 0x0f, 0x0b, 0x38, 0x2e, |
353 | 0x8d, 0xae, 0xdb, 0xf4, 0x05, 0x2b, 0x8b, 0x7d, |
354 | 0x00, |
355 | 0x40, // FINISH |
356 | }; |
357 | Tick(Tick: 1); |
358 | Inputs(); |
359 | m_TH.RecordTestExtra(); |
360 | Finish(); |
361 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
362 | } |
363 | |
364 | TEST_F(TeeHistorian, DDNetVersion) |
365 | { |
366 | const unsigned char EXPECTED[] = { |
367 | // EX uuid=60daba5c-52c4-3aeb-b8ba-b2953fb55a17 data_len=50 |
368 | 0x4a, |
369 | 0x13, 0x97, 0xb6, 0x3e, 0xee, 0x4e, 0x39, 0x19, |
370 | 0xb8, 0x6a, 0xb0, 0x58, 0x88, 0x7f, 0xca, 0xf5, |
371 | 0x32, |
372 | // (DDNETVER) cid=0 connection_id=fb13a576-d35f-4893-b815-eedc6d98015b |
373 | // ddnet_version=13010 ddnet_version_str=DDNet 13.1 (3623f5e4cd184556) |
374 | 0x00, |
375 | 0xfb, 0x13, 0xa5, 0x76, 0xd3, 0x5f, 0x48, 0x93, |
376 | 0xb8, 0x15, 0xee, 0xdc, 0x6d, 0x98, 0x01, 0x5b, |
377 | 0x92, 0xcb, 0x01, 'D', 'D', 'N', 'e', 't', |
378 | ' ', '1', '3', '.', '1', ' ', '(', '3', |
379 | '6', '2', '3', 'f', '5', 'e', '4', 'c', |
380 | 'd', '1', '8', '4', '5', '5', '6', ')', |
381 | 0x00, |
382 | // EX uuid=41b49541-f26f-325d-8715-9baf4b544ef9 data_len=4 |
383 | 0x4a, |
384 | 0x41, 0xb4, 0x95, 0x41, 0xf2, 0x6f, 0x32, 0x5d, |
385 | 0x87, 0x15, 0x9b, 0xaf, 0x4b, 0x54, 0x4e, 0xf9, |
386 | 0x04, |
387 | // (DDNETVER_OLD) cid=1 ddnet_version=13010 |
388 | 0x01, 0x92, 0xcb, 0x01, |
389 | 0x40, // FINISH |
390 | }; |
391 | CUuid ConnectionId = { |
392 | 0xfb, 0x13, 0xa5, 0x76, 0xd3, 0x5f, 0x48, 0x93, |
393 | 0xb8, 0x15, 0xee, 0xdc, 0x6d, 0x98, 0x01, 0x5b}; |
394 | m_TH.RecordDDNetVersion(ClientId: 0, ConnectionId, DDNetVersion: 13010, pDDNetVersionStr: "DDNet 13.1 (3623f5e4cd184556)" ); |
395 | m_TH.RecordDDNetVersionOld(ClientId: 1, DDNetVersion: 13010); |
396 | Finish(); |
397 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
398 | } |
399 | |
400 | TEST_F(TeeHistorian, Auth) |
401 | { |
402 | const unsigned char EXPECTED[] = { |
403 | // EX uuid=60daba5c-52c4-3aeb-b8ba-b2953fb55a17 data_len=16 |
404 | 0x4a, |
405 | 0x60, 0xda, 0xba, 0x5c, 0x52, 0xc4, 0x3a, 0xeb, |
406 | 0xb8, 0xba, 0xb2, 0x95, 0x3f, 0xb5, 0x5a, 0x17, |
407 | 0x10, |
408 | // (AUTH_INIT) cid=0 level=3 auth_name="default_admin" |
409 | 0x00, 0x03, 'd', 'e', 'f', 'a', 'u', 'l', |
410 | 't', '_', 'a', 'd', 'm', 'i', 'n', 0x00, |
411 | // EX uuid=37ecd3b8-9218-3bb9-a71b-a935b86f6a81 data_len=9 |
412 | 0x4a, |
413 | 0x37, 0xec, 0xd3, 0xb8, 0x92, 0x18, 0x3b, 0xb9, |
414 | 0xa7, 0x1b, 0xa9, 0x35, 0xb8, 0x6f, 0x6a, 0x81, |
415 | 0x09, |
416 | // (AUTH_LOGIN) cid=1 level=2 auth_name="foobar" |
417 | 0x01, 0x02, 'f', 'o', 'o', 'b', 'a', 'r', |
418 | 0x00, |
419 | // EX uuid=37ecd3b8-9218-3bb9-a71b-a935b86f6a81 data_len=7 |
420 | 0x4a, |
421 | 0x37, 0xec, 0xd3, 0xb8, 0x92, 0x18, 0x3b, 0xb9, |
422 | 0xa7, 0x1b, 0xa9, 0x35, 0xb8, 0x6f, 0x6a, 0x81, |
423 | 0x07, |
424 | // (AUTH_LOGIN) cid=1 level=2 auth_name="foobar" |
425 | 0x02, 0x01, 'h', 'e', 'l', 'p', 0x00, |
426 | // EX uuid=d4f5abe8-edd2-3fb9-abd8-1c8bb84f4a63 data_len=7 |
427 | 0x4a, |
428 | 0xd4, 0xf5, 0xab, 0xe8, 0xed, 0xd2, 0x3f, 0xb9, |
429 | 0xab, 0xd8, 0x1c, 0x8b, 0xb8, 0x4f, 0x4a, 0x63, |
430 | 0x01, |
431 | // (AUTH_LOGOUT) cid=1 |
432 | 0x01, |
433 | 0x40, // FINISH |
434 | }; |
435 | m_TH.RecordAuthInitial(ClientId: 0, Level: AUTHED_ADMIN, pAuthName: "default_admin" ); |
436 | m_TH.RecordAuthLogin(ClientId: 1, Level: AUTHED_MOD, pAuthName: "foobar" ); |
437 | m_TH.RecordAuthLogin(ClientId: 2, Level: AUTHED_HELPER, pAuthName: "help" ); |
438 | m_TH.RecordAuthLogout(ClientId: 1); |
439 | Finish(); |
440 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
441 | } |
442 | |
443 | TEST_F(TeeHistorian, JoinLeave) |
444 | { |
445 | const unsigned char EXPECTED[] = { |
446 | // EX uuid=1899a382-71e3-36da-937d-c9de6bb95b1d data_len=1 |
447 | 0x4a, |
448 | 0x18, 0x99, 0xa3, 0x82, 0x71, 0xe3, 0x36, 0xda, |
449 | 0x93, 0x7d, 0xc9, 0xde, 0x6b, 0xb9, 0x5b, 0x1d, |
450 | 0x01, |
451 | // (JOINVER6) cid=6 |
452 | 0x06, |
453 | // JOIN cid=7 |
454 | 0x47, 0x06, |
455 | // EX uuid=59239b05-0540-318d-bea4-9aa1e80e7d2b data_len=1 |
456 | 0x4a, |
457 | 0x59, 0x23, 0x9b, 0x05, 0x05, 0x40, 0x31, 0x8d, |
458 | 0xbe, 0xa4, 0x9a, 0xa1, 0xe8, 0x0e, 0x7d, 0x2b, |
459 | 0x01, |
460 | // (JOINVER7) cid=7 |
461 | 0x07, |
462 | // JOIN cid=7 |
463 | 0x47, 0x07, |
464 | // LEAVE cid=6 reason="too many pancakes" |
465 | 0x48, 0x06, 't', 'o', 'o', ' ', 'm', 'a', |
466 | 'n', 'y', ' ', 'p', 'a', 'n', 'c', 'a', |
467 | 'k', 'e', 's', 0x00, |
468 | 0x40, // FINISH |
469 | }; |
470 | m_TH.RecordPlayerJoin(ClientId: 6, Protocol: CTeeHistorian::PROTOCOL_6); |
471 | m_TH.RecordPlayerJoin(ClientId: 7, Protocol: CTeeHistorian::PROTOCOL_7); |
472 | m_TH.RecordPlayerDrop(ClientId: 6, pReason: "too many pancakes" ); |
473 | Finish(); |
474 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
475 | } |
476 | |
477 | TEST_F(TeeHistorian, Input) |
478 | { |
479 | CNetObj_PlayerInput Input = {.m_Direction: 1, .m_TargetX: 2, .m_TargetY: 3, .m_Jump: 4, .m_Fire: 5, .m_Hook: 6, .m_PlayerFlags: 7, .m_WantedWeapon: 8, .m_NextWeapon: 9, .m_PrevWeapon: 10}; |
480 | const unsigned char EXPECTED[] = { |
481 | // TICK_SKIP dt=0 |
482 | 0x41, 0x00, |
483 | // new player -> InputNew |
484 | 0x45, |
485 | 0x00, // ClientId 0 |
486 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, |
487 | // same unique id, same input -> nothing |
488 | // same unique id, different input -> InputDiff |
489 | 0x44, |
490 | 0x00, // ClientId 0 |
491 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
492 | // different unique id, same input -> InputNew |
493 | 0x45, |
494 | 0x00, // ClientId 0 |
495 | 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, |
496 | // FINISH |
497 | 0x40}; |
498 | |
499 | Tick(Tick: 1); |
500 | |
501 | // new player -> InputNew |
502 | m_TH.RecordPlayerInput(ClientId: 0, UniqueClientId: 1, pInput: &Input); |
503 | // same unique id, same input -> nothing |
504 | m_TH.RecordPlayerInput(ClientId: 0, UniqueClientId: 1, pInput: &Input); |
505 | |
506 | Input.m_Direction = 0; |
507 | |
508 | // same unique id, different input -> InputDiff |
509 | m_TH.RecordPlayerInput(ClientId: 0, UniqueClientId: 1, pInput: &Input); |
510 | |
511 | // different unique id, same input -> InputNew |
512 | m_TH.RecordPlayerInput(ClientId: 0, UniqueClientId: 2, pInput: &Input); |
513 | |
514 | Finish(); |
515 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
516 | } |
517 | |
518 | TEST_F(TeeHistorian, SaveSuccess) |
519 | { |
520 | const unsigned char EXPECTED[] = { |
521 | // EX uuid=4560c756-da29-3036-81d4-90a50f0182cd datalen=42 |
522 | 0x4a, |
523 | 0x45, 0x60, 0xc7, 0x56, 0xda, 0x29, 0x30, 0x36, |
524 | 0x81, 0xd4, 0x90, 0xa5, 0x0f, 0x01, 0x82, 0xcd, |
525 | 0x1a, |
526 | // team=21 |
527 | 0x15, |
528 | // save_id |
529 | 0xfb, 0x13, 0xa5, 0x76, 0xd3, 0x5f, 0x48, 0x93, |
530 | 0xb8, 0x15, 0xee, 0xdc, 0x6d, 0x98, 0x01, 0x5b, |
531 | // team_save |
532 | '2', '\t', 'H', '.', '\n', 'l', 'l', '0', 0x00, |
533 | // FINISH |
534 | 0x40}; |
535 | |
536 | CUuid SaveId = { |
537 | 0xfb, 0x13, 0xa5, 0x76, 0xd3, 0x5f, 0x48, 0x93, |
538 | 0xb8, 0x15, 0xee, 0xdc, 0x6d, 0x98, 0x01, 0x5b}; |
539 | const char *pTeamSave = "2\tH.\nll0" ; |
540 | m_TH.RecordTeamSaveSuccess(Team: 21, SaveId, pTeamSave); |
541 | Finish(); |
542 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
543 | } |
544 | |
545 | TEST_F(TeeHistorian, SaveFailed) |
546 | { |
547 | const unsigned char EXPECTED[] = { |
548 | // EX uuid=b29901d5-1244-3bd0-bbde-23d04b1f7ba9 datalen=42 |
549 | 0x4a, |
550 | 0xb2, 0x99, 0x01, 0xd5, 0x12, 0x44, 0x3b, 0xd0, |
551 | 0xbb, 0xde, 0x23, 0xd0, 0x4b, 0x1f, 0x7b, 0xa9, |
552 | 0x01, |
553 | // team=12 |
554 | 0x0c, |
555 | 0x40}; |
556 | |
557 | m_TH.RecordTeamSaveFailure(Team: 12); |
558 | Finish(); |
559 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
560 | } |
561 | |
562 | TEST_F(TeeHistorian, LoadSuccess) |
563 | { |
564 | const unsigned char EXPECTED[] = { |
565 | // EX uuid=e05408d3-a313-33df-9eb3-ddb990ab954a datalen=42 |
566 | 0x4a, |
567 | 0xe0, 0x54, 0x08, 0xd3, 0xa3, 0x13, 0x33, 0xdf, |
568 | 0x9e, 0xb3, 0xdd, 0xb9, 0x90, 0xab, 0x95, 0x4a, |
569 | 0x1a, |
570 | // team=21 |
571 | 0x15, |
572 | // save_id |
573 | 0xfb, 0x13, 0xa5, 0x76, 0xd3, 0x5f, 0x48, 0x93, |
574 | 0xb8, 0x15, 0xee, 0xdc, 0x6d, 0x98, 0x01, 0x5b, |
575 | // team_save |
576 | '2', '\t', 'H', '.', '\n', 'l', 'l', '0', 0x00, |
577 | // FINISH |
578 | 0x40}; |
579 | |
580 | CUuid SaveId = { |
581 | 0xfb, 0x13, 0xa5, 0x76, 0xd3, 0x5f, 0x48, 0x93, |
582 | 0xb8, 0x15, 0xee, 0xdc, 0x6d, 0x98, 0x01, 0x5b}; |
583 | const char *pTeamSave = "2\tH.\nll0" ; |
584 | m_TH.RecordTeamLoadSuccess(Team: 21, SaveId, pTeamSave); |
585 | Finish(); |
586 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
587 | } |
588 | |
589 | TEST_F(TeeHistorian, LoadFailed) |
590 | { |
591 | const unsigned char EXPECTED[] = { |
592 | // EX uuid=ef8905a2-c695-3591-a1cd-53d2015992dd datalen=42 |
593 | 0x4a, |
594 | 0xef, 0x89, 0x05, 0xa2, 0xc6, 0x95, 0x35, 0x91, |
595 | 0xa1, 0xcd, 0x53, 0xd2, 0x01, 0x59, 0x92, 0xdd, |
596 | 0x01, |
597 | // team=12 |
598 | 0x0c, |
599 | 0x40}; |
600 | |
601 | m_TH.RecordTeamLoadFailure(Team: 12); |
602 | Finish(); |
603 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
604 | } |
605 | |
606 | TEST_F(TeeHistorian, PlayerSwap) |
607 | { |
608 | const unsigned char EXPECTED[] = { |
609 | // TICK_SKIP dt=0 |
610 | 0x41, 0x00, |
611 | // EX uuid=5de9b633-49cf-3e99-9a25-d4a78e9717d7 datalen=2 |
612 | 0x4a, |
613 | 0x5d, 0xe9, 0xb6, 0x33, 0x49, 0xcf, 0x3e, 0x99, |
614 | 0x9a, 0x25, 0xd4, 0xa7, 0x8e, 0x97, 0x17, 0xd7, |
615 | 0x02, |
616 | // playerId1=11 |
617 | 0x0b, |
618 | // playerId2=21 |
619 | 0x15, |
620 | // FINISH |
621 | 0x40}; |
622 | Tick(Tick: 1); |
623 | m_TH.RecordPlayerSwap(ClientId1: 11, ClientId2: 21); |
624 | Finish(); |
625 | |
626 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
627 | } |
628 | |
629 | TEST_F(TeeHistorian, PlayerTeam) |
630 | { |
631 | const unsigned char EXPECTED[] = { |
632 | // TICK_SKIP dt=0 |
633 | 0x41, 0x00, |
634 | // EX uuid=a111c04e-1ea8-38e0-90b1-d7f993ca0da9 datalen=2 |
635 | 0x4a, |
636 | 0xa1, 0x11, 0xc0, 0x4e, 0x1e, 0xa8, 0x38, 0xe0, |
637 | 0x90, 0xb1, 0xd7, 0xf9, 0x93, 0xca, 0x0d, 0xa9, |
638 | 0x02, |
639 | // (PLAYER_TEAM) cid=33 team=54 |
640 | 0x21, 0x36, |
641 | // TICK_SKIP dt=0 |
642 | 0x41, 0x00, |
643 | // EX uuid=a111c04e-1ea8-38e0-90b1-d7f993ca0da9 datalen=2 |
644 | 0x4a, |
645 | 0xa1, 0x11, 0xc0, 0x4e, 0x1e, 0xa8, 0x38, 0xe0, |
646 | 0x90, 0xb1, 0xd7, 0xf9, 0x93, 0xca, 0x0d, 0xa9, |
647 | 0x02, |
648 | // (PLAYER_TEAM) cid=3 team=12 |
649 | 0x03, 0x0c, |
650 | // EX uuid=a111c04e-1ea8-38e0-90b1-d7f993ca0da9 datalen=2 |
651 | 0x4a, |
652 | 0xa1, 0x11, 0xc0, 0x4e, 0x1e, 0xa8, 0x38, 0xe0, |
653 | 0x90, 0xb1, 0xd7, 0xf9, 0x93, 0xca, 0x0d, 0xa9, |
654 | 0x02, |
655 | // (PLAYER_TEAM) cid=33 team=0 |
656 | 0x21, 0x00, |
657 | // FINISH |
658 | 0x40}; |
659 | |
660 | Tick(Tick: 1); |
661 | m_TH.RecordPlayerTeam(ClientId: 3, Team: 0); |
662 | m_TH.RecordPlayerTeam(ClientId: 33, Team: 54); |
663 | m_TH.RecordPlayerTeam(ClientId: 45, Team: 0); |
664 | Tick(Tick: 2); |
665 | m_TH.RecordPlayerTeam(ClientId: 3, Team: 12); |
666 | m_TH.RecordPlayerTeam(ClientId: 33, Team: 0); |
667 | m_TH.RecordPlayerTeam(ClientId: 45, Team: 0); |
668 | Finish(); |
669 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
670 | } |
671 | |
672 | TEST_F(TeeHistorian, TeamPractice) |
673 | { |
674 | const unsigned char EXPECTED[] = { |
675 | // TICK_SKIP dt=0 |
676 | 0x41, 0x00, |
677 | // EX uuid=5792834e-81d1-34c9-a29b-b5ff25dac3bc datalen=2 |
678 | 0x4a, |
679 | 0x57, 0x92, 0x83, 0x4e, 0x81, 0xd1, 0x34, 0xc9, |
680 | 0xa2, 0x9b, 0xb5, 0xff, 0x25, 0xda, 0xc3, 0xbc, |
681 | 0x02, |
682 | // (TEAM_PRACTICE) team=23 practice=1 |
683 | 0x17, 0x01, |
684 | // TICK_SKIP dt=0 |
685 | 0x41, 0x00, |
686 | // EX uuid=5792834e-81d1-34c9-a29b-b5ff25dac3bc datalen=2 |
687 | 0x4a, |
688 | 0x57, 0x92, 0x83, 0x4e, 0x81, 0xd1, 0x34, 0xc9, |
689 | 0xa2, 0x9b, 0xb5, 0xff, 0x25, 0xda, 0xc3, 0xbc, |
690 | 0x02, |
691 | // (TEAM_PRACTICE) team=1 practice=1 |
692 | 0x01, 0x01, |
693 | // EX uuid=5792834e-81d1-34c9-a29b-b5ff25dac3bc datalen=2 |
694 | 0x4a, |
695 | 0x57, 0x92, 0x83, 0x4e, 0x81, 0xd1, 0x34, 0xc9, |
696 | 0xa2, 0x9b, 0xb5, 0xff, 0x25, 0xda, 0xc3, 0xbc, |
697 | 0x02, |
698 | // (TEAM_PRACTICE) team=23 practice=0 |
699 | 0x17, 0x00, |
700 | // FINISH |
701 | 0x40}; |
702 | |
703 | Tick(Tick: 1); |
704 | m_TH.RecordTeamPractice(Team: 1, Practice: false); |
705 | m_TH.RecordTeamPractice(Team: 16, Practice: false); |
706 | m_TH.RecordTeamPractice(Team: 23, Practice: true); |
707 | Tick(Tick: 2); |
708 | m_TH.RecordTeamPractice(Team: 1, Practice: true); |
709 | m_TH.RecordTeamPractice(Team: 16, Practice: false); |
710 | m_TH.RecordTeamPractice(Team: 23, Practice: false); |
711 | Finish(); |
712 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
713 | } |
714 | |
715 | TEST_F(TeeHistorian, PlayerRejoinVer6) |
716 | { |
717 | const unsigned char EXPECTED[] = { |
718 | // EX uuid=c1e921d5-96f5-37bb-8a45-7a06f163d27e datalen=1 |
719 | 0x4a, |
720 | 0xc1, 0xe9, 0x21, 0xd5, 0x96, 0xf5, 0x37, 0xbb, |
721 | 0x8a, 0x45, 0x7a, 0x06, 0xf1, 0x63, 0xd2, 0x7e, |
722 | 0x01, |
723 | // (PLAYER_REJOIN) cid=2 |
724 | 0x02, |
725 | // FINISH |
726 | 0x40}; |
727 | |
728 | m_TH.RecordPlayerRejoin(ClientId: 2); |
729 | Finish(); |
730 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
731 | } |
732 | |
733 | TEST_F(TeeHistorian, PlayerReady) |
734 | { |
735 | const unsigned char EXPECTED[] = { |
736 | // EX uuid=638587c9-3f75-3887-918e-a3c2614ffaa0 datalen=1 |
737 | 0x4a, |
738 | 0x63, 0x85, 0x87, 0xc9, 0x3f, 0x75, 0x38, 0x87, |
739 | 0x91, 0x8e, 0xa3, 0xc2, 0x61, 0x4f, 0xfa, 0xa0, |
740 | 0x01, |
741 | // (PLAYER_READY) cid=63 |
742 | 0x3f, |
743 | // FINISH |
744 | 0x40}; |
745 | |
746 | m_TH.RecordPlayerReady(ClientId: 63); |
747 | Finish(); |
748 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
749 | } |
750 | |
751 | TEST_F(TeeHistorian, PlayerReadyMultiple) |
752 | { |
753 | const unsigned char EXPECTED[] = { |
754 | // TICK_SKIP dt=0 |
755 | 0x41, 0x00, |
756 | // EX uuid=638587c9-3f75-3887-918e-a3c2614ffaa0 datalen=1 |
757 | 0x4a, |
758 | 0x63, 0x85, 0x87, 0xc9, 0x3f, 0x75, 0x38, 0x87, |
759 | 0x91, 0x8e, 0xa3, 0xc2, 0x61, 0x4f, 0xfa, 0xa0, |
760 | 0x01, |
761 | // (PLAYER_READY) cid=0 |
762 | 0x00, |
763 | // EX uuid=638587c9-3f75-3887-918e-a3c2614ffaa0 datalen=1 |
764 | 0x4a, |
765 | 0x63, 0x85, 0x87, 0xc9, 0x3f, 0x75, 0x38, 0x87, |
766 | 0x91, 0x8e, 0xa3, 0xc2, 0x61, 0x4f, 0xfa, 0xa0, |
767 | 0x01, |
768 | // (PLAYER_READY) cid=11 |
769 | 0x0b, |
770 | // TICK_SKIP dt=0 |
771 | 0x41, 0x00, |
772 | // EX uuid=638587c9-3f75-3887-918e-a3c2614ffaa0 datalen=1 |
773 | 0x4a, |
774 | 0x63, 0x85, 0x87, 0xc9, 0x3f, 0x75, 0x38, 0x87, |
775 | 0x91, 0x8e, 0xa3, 0xc2, 0x61, 0x4f, 0xfa, 0xa0, |
776 | 0x01, |
777 | // (PLAYER_READY) cid=63 |
778 | 0x3f, |
779 | 0x40}; |
780 | |
781 | Tick(Tick: 1); |
782 | m_TH.RecordPlayerReady(ClientId: 0); |
783 | m_TH.RecordPlayerReady(ClientId: 11); |
784 | Tick(Tick: 2); |
785 | m_TH.RecordPlayerReady(ClientId: 63); |
786 | Finish(); |
787 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
788 | } |
789 | |
790 | TEST_F(TeeHistorian, AntibotEmpty) |
791 | { |
792 | const unsigned char EXPECTED[] = { |
793 | // EX uuid=866bfdac-fb49-3c0b-a887-5fe1f3ea00b8 datalen=0 |
794 | 0x4a, |
795 | 0x86, 0x6b, 0xfd, 0xac, 0xfb, 0x49, 0x3c, 0x0b, |
796 | 0xa8, 0x87, 0x5f, 0xe1, 0xf3, 0xea, 0x00, 0xb8, |
797 | 0x00, |
798 | // (ANTIBOT) antibot_data |
799 | }; |
800 | |
801 | m_TH.RecordAntibot(pData: "" , DataSize: 0); |
802 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
803 | } |
804 | |
805 | TEST_F(TeeHistorian, AntibotEmptyNulBytes) |
806 | { |
807 | const unsigned char EXPECTED[] = { |
808 | // EX uuid=866bfdac-fb49-3c0b-a887-5fe1f3ea00b8 datalen=4 |
809 | 0x4a, |
810 | 0x86, 0x6b, 0xfd, 0xac, 0xfb, 0x49, 0x3c, 0x0b, |
811 | 0xa8, 0x87, 0x5f, 0xe1, 0xf3, 0xea, 0x00, 0xb8, |
812 | 0x04, |
813 | // (ANTIBOT) antibot_data |
814 | 0x00, |
815 | 0x00, |
816 | 0x00, |
817 | 0x00}; |
818 | |
819 | m_TH.RecordAntibot(pData: "\0\0\0\0" , DataSize: 4); |
820 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
821 | } |
822 | |
823 | TEST_F(TeeHistorian, AntibotEmptyMessage) |
824 | { |
825 | const unsigned char EXPECTED[] = { |
826 | // EX uuid=866bfdac-fb49-3c0b-a887-5fe1f3ea00b8 datalen=4 |
827 | 0x4a, |
828 | 0x86, 0x6b, 0xfd, 0xac, 0xfb, 0x49, 0x3c, 0x0b, |
829 | 0xa8, 0x87, 0x5f, 0xe1, 0xf3, 0xea, 0x00, 0xb8, |
830 | 0x04, |
831 | // (ANTIBOT) antibot_data |
832 | 0xf0, |
833 | 0x9f, |
834 | 0xa4, |
835 | 0x96}; |
836 | |
837 | m_TH.RecordAntibot(pData: "🤖" , DataSize: 4); |
838 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
839 | } |
840 | |
841 | TEST_F(TeeHistorian, PlayerName) |
842 | { |
843 | const unsigned char EXPECTED[] = { |
844 | // EX uuid=d016f9b9-4151-3b87-87e5-3a6087eb5f26 datalen=14 |
845 | 0x4a, |
846 | 0xd0, 0x16, 0xf9, 0xb9, 0x41, 0x51, 0x3b, 0x87, |
847 | 0x87, 0xe5, 0x3a, 0x60, 0x87, 0xeb, 0x5f, 0x26, |
848 | 0x0e, |
849 | // (PLAYER_NAME) id=21 name="nameless tee" |
850 | 0x15, |
851 | 0x6e, 0x61, 0x6d, 0x65, 0x6c, 0x65, 0x73, 0x73, |
852 | 0x20, 0x74, 0x65, 0x65, 0x00}; |
853 | |
854 | m_TH.RecordPlayerName(ClientId: 21, pName: "nameless tee" ); |
855 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
856 | } |
857 | |
858 | TEST_F(TeeHistorian, PlayerFinish) |
859 | { |
860 | const unsigned char EXPECTED[] = { |
861 | // EX uuid=68943c01-2348-3e01-9490-3f27f8269d94 datalen=4 |
862 | 0x4a, |
863 | 0x68, 0x94, 0x3c, 0x01, 0x23, 0x48, 0x3e, 0x01, |
864 | 0x94, 0x90, 0x3f, 0x27, 0xf8, 0x26, 0x9d, 0x94, |
865 | 0x04, |
866 | // (PLAYER_FINISH) id=1 time=1000000 |
867 | 0x01, 0x80, 0x89, 0x7a}; |
868 | |
869 | m_TH.RecordPlayerFinish(ClientId: 1, TimeTicks: 1000000); |
870 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
871 | } |
872 | |
873 | TEST_F(TeeHistorian, TeamFinish) |
874 | { |
875 | const unsigned char EXPECTED[] = { |
876 | // EX uuid=9588b9af-3fdc-3760-8043-82deeee317a5 datalen=3 |
877 | 0x4a, |
878 | 0x95, 0x88, 0xb9, 0xaf, 0x3f, 0xdc, 0x37, 0x60, |
879 | 0x80, 0x43, 0x82, 0xde, 0xee, 0xe3, 0x17, 0xa5, |
880 | 0x03, |
881 | // (TEAM_FINISH) team=63 Time=1000 |
882 | 0x3f, 0xa8, 0x0f}; |
883 | |
884 | m_TH.RecordTeamFinish(TeamId: 63, TimeTicks: 1000); |
885 | Expect(pOutput: EXPECTED, OutputSize: sizeof(EXPECTED)); |
886 | } |
887 | |
888 | TEST_F(TeeHistorian, PrevGameUuid) |
889 | { |
890 | m_GameInfo.m_HavePrevGameUuid = true; |
891 | CUuid PrevGameUuid = {.m_aData: { |
892 | // fe19c218-f555-4002-a273-126c59ccc17a |
893 | 0xfe, 0x19, 0xc2, 0x18, 0xf5, 0x55, 0x40, 0x02, |
894 | 0xa2, 0x73, 0x12, 0x6c, 0x59, 0xcc, 0xc1, 0x7a, |
895 | // |
896 | }}; |
897 | m_GameInfo.m_PrevGameUuid = PrevGameUuid; |
898 | Reset(pGameInfo: &m_GameInfo); |
899 | Finish(); |
900 | json_value *pJson = json_parse(json: (const char *)m_vBuffer.data() + 16, length: -1); |
901 | ASSERT_TRUE(pJson); |
902 | const json_value &JsonPrevGameUuid = (*pJson)["prev_game_uuid" ]; |
903 | ASSERT_EQ(JsonPrevGameUuid.type, json_string); |
904 | EXPECT_STREQ(JsonPrevGameUuid, "fe19c218-f555-4002-a273-126c59ccc17a" ); |
905 | json_value_free(pJson); |
906 | } |
907 | |