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