From f78e906f1102790cc08f2c197d011ad18069d8f4 Mon Sep 17 00:00:00 2001 From: JP Dillingham Date: Tue, 1 Sep 2026 19:43:28 -0500 Subject: [PATCH 1/8] add ReportUnreadMessageData flag --- src/SoulseekClient.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/SoulseekClient.cs b/src/SoulseekClient.cs index 24ac01495..49865b146 100644 --- a/src/SoulseekClient.cs +++ b/src/SoulseekClient.cs @@ -518,6 +518,11 @@ internal SoulseekClient( /// public static bool RaiseEventsAsynchronously { get; set; } + /// + /// Gets or sets a value indicating whether to report unread message data as a diagnostic warning. + /// + public static bool ReportUnreadMessageData { get; set; } + /// /// Gets the unresolved server address. /// From 22371d052df3b34e1238aeffe3433cc2c66614e1 Mon Sep 17 00:00:00 2001 From: JP Dillingham Date: Wed, 2 Sep 2026 08:42:53 -0500 Subject: [PATCH 2/8] add logging to distributed messages --- src/Messaging/Messages/Distributed/DistributedBranchLevel.cs | 5 +++++ src/Messaging/Messages/Distributed/DistributedBranchRoot.cs | 5 +++++ src/Messaging/Messages/Distributed/DistributedChildDepth.cs | 5 +++++ src/Messaging/Messages/Distributed/DistributedPingRequest.cs | 5 +++++ .../Messages/Distributed/DistributedPingResponse.cs | 5 +++++ .../Messages/Distributed/DistributedSearchRequest.cs | 5 +++++ 6 files changed, 30 insertions(+) diff --git a/src/Messaging/Messages/Distributed/DistributedBranchLevel.cs b/src/Messaging/Messages/Distributed/DistributedBranchLevel.cs index ba5bdd332..780314b5b 100644 --- a/src/Messaging/Messages/Distributed/DistributedBranchLevel.cs +++ b/src/Messaging/Messages/Distributed/DistributedBranchLevel.cs @@ -59,6 +59,11 @@ public static DistributedBranchLevel FromByteArray(byte[] bytes) var level = reader.ReadInteger(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Distributed.BranchLevel)} finalized with {reader.Remaining} unread bytes"); + } + return new DistributedBranchLevel(level); } diff --git a/src/Messaging/Messages/Distributed/DistributedBranchRoot.cs b/src/Messaging/Messages/Distributed/DistributedBranchRoot.cs index 417bf52f8..9fa773213 100644 --- a/src/Messaging/Messages/Distributed/DistributedBranchRoot.cs +++ b/src/Messaging/Messages/Distributed/DistributedBranchRoot.cs @@ -59,6 +59,11 @@ public static DistributedBranchRoot FromByteArray(byte[] bytes) var username = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Distributed.BranchRoot)} finalized with {reader.Remaining} unread bytes"); + } + return new DistributedBranchRoot(username); } diff --git a/src/Messaging/Messages/Distributed/DistributedChildDepth.cs b/src/Messaging/Messages/Distributed/DistributedChildDepth.cs index 306c9a9ae..a2ddb8878 100644 --- a/src/Messaging/Messages/Distributed/DistributedChildDepth.cs +++ b/src/Messaging/Messages/Distributed/DistributedChildDepth.cs @@ -59,6 +59,11 @@ public static DistributedChildDepth FromByteArray(byte[] bytes) var depth = reader.ReadInteger(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Distributed.ChildDepth)} finalized with {reader.Remaining} unread bytes"); + } + return new DistributedChildDepth(depth); } diff --git a/src/Messaging/Messages/Distributed/DistributedPingRequest.cs b/src/Messaging/Messages/Distributed/DistributedPingRequest.cs index 0c79b56fc..3901017df 100644 --- a/src/Messaging/Messages/Distributed/DistributedPingRequest.cs +++ b/src/Messaging/Messages/Distributed/DistributedPingRequest.cs @@ -50,6 +50,11 @@ public static DistributedPingRequest FromByteArray(byte[] bytes) throw new MessageException($"Message Code mismatch creating {nameof(DistributedPingRequest)} (expected: {(int)MessageCode.Distributed.Ping}, received: {(int)code})"); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Distributed.Ping)} finalized with {reader.Remaining} unread bytes"); + } + return new DistributedPingRequest(); } diff --git a/src/Messaging/Messages/Distributed/DistributedPingResponse.cs b/src/Messaging/Messages/Distributed/DistributedPingResponse.cs index 261386d75..84164bf55 100644 --- a/src/Messaging/Messages/Distributed/DistributedPingResponse.cs +++ b/src/Messaging/Messages/Distributed/DistributedPingResponse.cs @@ -64,6 +64,11 @@ public static DistributedPingResponse FromByteArray(byte[] bytes) token = reader.ReadInteger(); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Distributed.Ping)} finalized with {reader.Remaining} unread bytes"); + } + return new DistributedPingResponse(token); } diff --git a/src/Messaging/Messages/Distributed/DistributedSearchRequest.cs b/src/Messaging/Messages/Distributed/DistributedSearchRequest.cs index ed058e3a7..4c9e575bd 100644 --- a/src/Messaging/Messages/Distributed/DistributedSearchRequest.cs +++ b/src/Messaging/Messages/Distributed/DistributedSearchRequest.cs @@ -78,6 +78,11 @@ public static DistributedSearchRequest FromByteArray(byte[] bytes) var token = reader.ReadInteger(); var query = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Distributed.SearchRequest)} finalized with {reader.Remaining} unread bytes"); + } + return new DistributedSearchRequest(username, token, query); } From d98deaecf9cd37dffda1b346a6c238195f661f9a Mon Sep 17 00:00:00 2001 From: JP Dillingham Date: Wed, 2 Sep 2026 08:43:26 -0500 Subject: [PATCH 3/8] add logging to initialization messages --- src/Messaging/Messages/Initialization/PeerInit.cs | 5 +++++ src/Messaging/Messages/Initialization/PierceFirewall.cs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/Messaging/Messages/Initialization/PeerInit.cs b/src/Messaging/Messages/Initialization/PeerInit.cs index e48158d6f..04a3aa965 100644 --- a/src/Messaging/Messages/Initialization/PeerInit.cs +++ b/src/Messaging/Messages/Initialization/PeerInit.cs @@ -79,6 +79,11 @@ public static bool TryFromByteArray(byte[] bytes, out PeerInit response) var transferType = reader.ReadString(); var token = reader.ReadInteger(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Initialization.PeerInit)} finalized with {reader.Remaining} unread bytes"); + } + response = new PeerInit(username, transferType, token); return true; } diff --git a/src/Messaging/Messages/Initialization/PierceFirewall.cs b/src/Messaging/Messages/Initialization/PierceFirewall.cs index f49f3fb80..488d62ee2 100644 --- a/src/Messaging/Messages/Initialization/PierceFirewall.cs +++ b/src/Messaging/Messages/Initialization/PierceFirewall.cs @@ -63,6 +63,11 @@ public static bool TryFromByteArray(byte[] bytes, out PierceFirewall response) var token = reader.ReadInteger(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Initialization.PierceFirewall)} finalized with {reader.Remaining} unread bytes"); + } + response = new PierceFirewall(token); return true; } From c2ee32421ae2b62cbfad2ab0698f3805a14f7de3 Mon Sep 17 00:00:00 2001 From: JP Dillingham Date: Wed, 2 Sep 2026 08:45:59 -0500 Subject: [PATCH 4/8] add logging for unread data --- src/Messaging/Messages/Peer/BrowseResponseFactory.cs | 5 +++++ src/Messaging/Messages/Peer/FolderContentsRequest.cs | 5 +++++ src/Messaging/Messages/Peer/FolderContentsResponse.cs | 5 +++++ src/Messaging/Messages/Peer/PeerSearchRequest.cs | 5 +++++ src/Messaging/Messages/Peer/PlaceInQueueRequest.cs | 5 +++++ src/Messaging/Messages/Peer/PlaceInQueueResponse.cs | 5 +++++ src/Messaging/Messages/Peer/QueueDownloadRequest.cs | 6 ++++++ src/Messaging/Messages/Peer/SearchResponseFactory.cs | 5 +++++ src/Messaging/Messages/Peer/TransferRequest.cs | 5 +++++ src/Messaging/Messages/Peer/UploadDenied.cs | 5 +++++ src/Messaging/Messages/Peer/UploadFailed.cs | 5 +++++ src/Messaging/Messages/Server/CannotConnect.cs | 5 +++++ .../Messages/Server/CannotJoinRoomNotification.cs | 5 +++++ src/Messaging/Messages/Server/ConnectToPeerResponse.cs | 5 +++++ .../Messages/Server/ExcludedSearchPhrasesNotification.cs | 5 +++++ .../Messages/Server/GlobalMessageNotification.cs | 5 +++++ src/Messaging/Messages/Server/IntegerResponse.cs | 9 ++++++++- src/Messaging/Messages/Server/JoinRoomResponse.cs | 5 +++++ src/Messaging/Messages/Server/LeaveRoomResponse.cs | 5 +++++ src/Messaging/Messages/Server/LoginResponse.cs | 5 +++++ src/Messaging/Messages/Server/NetInfoNotification.cs | 5 +++++ src/Messaging/Messages/Server/NewPassword.cs | 5 +++++ .../Messages/Server/PrivateMessageNotification.cs | 5 +++++ src/Messaging/Messages/Server/PrivateRoomAddOperator.cs | 5 +++++ src/Messaging/Messages/Server/PrivateRoomAddUser.cs | 5 +++++ .../Messages/Server/PrivateRoomOwnedListNotification.cs | 5 +++++ .../Messages/Server/PrivateRoomRemoveOperator.cs | 5 +++++ 27 files changed, 139 insertions(+), 1 deletion(-) diff --git a/src/Messaging/Messages/Peer/BrowseResponseFactory.cs b/src/Messaging/Messages/Peer/BrowseResponseFactory.cs index be73234ec..57f4a43cd 100644 --- a/src/Messaging/Messages/Peer/BrowseResponseFactory.cs +++ b/src/Messaging/Messages/Peer/BrowseResponseFactory.cs @@ -72,6 +72,11 @@ public static BrowseResponse FromByteArray(byte[] bytes) } } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.BrowseResponse)} finalized with {reader.Remaining} unread bytes"); + } + return new BrowseResponse(directoryList, lockedDirectoryList); } diff --git a/src/Messaging/Messages/Peer/FolderContentsRequest.cs b/src/Messaging/Messages/Peer/FolderContentsRequest.cs index ce0a83241..bc95b7ec6 100644 --- a/src/Messaging/Messages/Peer/FolderContentsRequest.cs +++ b/src/Messaging/Messages/Peer/FolderContentsRequest.cs @@ -67,6 +67,11 @@ public static FolderContentsRequest FromByteArray(byte[] bytes) var token = reader.ReadInteger(); var directoryName = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.FolderContentsRequest)} finalized with {reader.Remaining} unread bytes"); + } + return new FolderContentsRequest(token, directoryName); } diff --git a/src/Messaging/Messages/Peer/FolderContentsResponse.cs b/src/Messaging/Messages/Peer/FolderContentsResponse.cs index 215a2b08f..f31544b9e 100644 --- a/src/Messaging/Messages/Peer/FolderContentsResponse.cs +++ b/src/Messaging/Messages/Peer/FolderContentsResponse.cs @@ -94,6 +94,11 @@ public static FolderContentsResponse FromByteArray(byte[] bytes) directoryList.Add(reader.ReadDirectory()); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.FolderContentsResponse)} finalized with {reader.Remaining} unread bytes"); + } + return new FolderContentsResponse(token, rootDirectory, directoryList); } diff --git a/src/Messaging/Messages/Peer/PeerSearchRequest.cs b/src/Messaging/Messages/Peer/PeerSearchRequest.cs index f9d91b0b0..eb2595d96 100644 --- a/src/Messaging/Messages/Peer/PeerSearchRequest.cs +++ b/src/Messaging/Messages/Peer/PeerSearchRequest.cs @@ -67,6 +67,11 @@ public static PeerSearchRequest FromByteArray(byte[] bytes) var token = reader.ReadInteger(); var query = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.SearchRequest)} finalized with {reader.Remaining} unread bytes"); + } + return new PeerSearchRequest(token, query); } } diff --git a/src/Messaging/Messages/Peer/PlaceInQueueRequest.cs b/src/Messaging/Messages/Peer/PlaceInQueueRequest.cs index e37dad103..a242e4652 100644 --- a/src/Messaging/Messages/Peer/PlaceInQueueRequest.cs +++ b/src/Messaging/Messages/Peer/PlaceInQueueRequest.cs @@ -59,6 +59,11 @@ public static PlaceInQueueRequest FromByteArray(byte[] bytes) var filename = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.PlaceInQueueRequest)} finalized with {reader.Remaining} unread bytes"); + } + return new PlaceInQueueRequest(filename); } diff --git a/src/Messaging/Messages/Peer/PlaceInQueueResponse.cs b/src/Messaging/Messages/Peer/PlaceInQueueResponse.cs index 2abfc325c..01ddbb42a 100644 --- a/src/Messaging/Messages/Peer/PlaceInQueueResponse.cs +++ b/src/Messaging/Messages/Peer/PlaceInQueueResponse.cs @@ -67,6 +67,11 @@ public static PlaceInQueueResponse FromByteArray(byte[] bytes) var filename = reader.ReadString(); var placeInQueue = reader.ReadInteger(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.PlaceInQueueResponse)} finalized with {reader.Remaining} unread bytes"); + } + return new PlaceInQueueResponse(filename, placeInQueue); } diff --git a/src/Messaging/Messages/Peer/QueueDownloadRequest.cs b/src/Messaging/Messages/Peer/QueueDownloadRequest.cs index 81e35ec0b..4fd9fe0ee 100644 --- a/src/Messaging/Messages/Peer/QueueDownloadRequest.cs +++ b/src/Messaging/Messages/Peer/QueueDownloadRequest.cs @@ -58,6 +58,12 @@ public static QueueDownloadRequest FromByteArray(byte[] bytes) } var filename = reader.ReadString(); + + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.QueueDownload)} finalized with {reader.Remaining} unread bytes"); + } + return new QueueDownloadRequest(filename); } diff --git a/src/Messaging/Messages/Peer/SearchResponseFactory.cs b/src/Messaging/Messages/Peer/SearchResponseFactory.cs index 70f6536e8..73fff7005 100644 --- a/src/Messaging/Messages/Peer/SearchResponseFactory.cs +++ b/src/Messaging/Messages/Peer/SearchResponseFactory.cs @@ -73,6 +73,11 @@ public static SearchResponse FromByteArray(byte[] bytes) lockedFileList = reader.ReadFiles(count); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.SearchResponse)} finalized with {reader.Remaining} unread bytes"); + } + return new SearchResponse(username, token, hasFreeUploadSlot: freeUploadSlots > 0, uploadSpeed, queueLength, fileList, lockedFileList); } diff --git a/src/Messaging/Messages/Peer/TransferRequest.cs b/src/Messaging/Messages/Peer/TransferRequest.cs index d6f3de927..0ee3f8980 100644 --- a/src/Messaging/Messages/Peer/TransferRequest.cs +++ b/src/Messaging/Messages/Peer/TransferRequest.cs @@ -89,6 +89,11 @@ public static TransferRequest FromByteArray(byte[] bytes) fileSize = reader.ReadLong(); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.TransferRequest)} finalized with {reader.Remaining} unread bytes"); + } + return new TransferRequest(direction, token, filename, fileSize); } diff --git a/src/Messaging/Messages/Peer/UploadDenied.cs b/src/Messaging/Messages/Peer/UploadDenied.cs index e7a0041b4..cd77ad10e 100644 --- a/src/Messaging/Messages/Peer/UploadDenied.cs +++ b/src/Messaging/Messages/Peer/UploadDenied.cs @@ -67,6 +67,11 @@ public static UploadDenied FromByteArray(byte[] bytes) var filename = reader.ReadString(); var msg = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.UploadDenied)} finalized with {reader.Remaining} unread bytes"); + } + return new UploadDenied(filename, msg); } diff --git a/src/Messaging/Messages/Peer/UploadFailed.cs b/src/Messaging/Messages/Peer/UploadFailed.cs index 3521fb69d..8502096d1 100644 --- a/src/Messaging/Messages/Peer/UploadFailed.cs +++ b/src/Messaging/Messages/Peer/UploadFailed.cs @@ -59,6 +59,11 @@ public static UploadFailed FromByteArray(byte[] bytes) var filename = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.UploadFailed)} finalized with {reader.Remaining} unread bytes"); + } + return new UploadFailed(filename); } diff --git a/src/Messaging/Messages/Server/CannotConnect.cs b/src/Messaging/Messages/Server/CannotConnect.cs index dadce8976..3aa787fae 100644 --- a/src/Messaging/Messages/Server/CannotConnect.cs +++ b/src/Messaging/Messages/Server/CannotConnect.cs @@ -73,6 +73,11 @@ public static CannotConnect FromByteArray(byte[] bytes) username = reader.ReadString(); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.CannotConnect)} finalized with {reader.Remaining} unread bytes"); + } + return new CannotConnect(token, username); } diff --git a/src/Messaging/Messages/Server/CannotJoinRoomNotification.cs b/src/Messaging/Messages/Server/CannotJoinRoomNotification.cs index 4986f59da..fe22feaf3 100644 --- a/src/Messaging/Messages/Server/CannotJoinRoomNotification.cs +++ b/src/Messaging/Messages/Server/CannotJoinRoomNotification.cs @@ -59,6 +59,11 @@ public static CannotJoinRoomNotification FromByteArray(byte[] bytes) var roomName = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.CannotJoinRoom)} finalized with {reader.Remaining} unread bytes"); + } + return new CannotJoinRoomNotification(roomName); } } diff --git a/src/Messaging/Messages/Server/ConnectToPeerResponse.cs b/src/Messaging/Messages/Server/ConnectToPeerResponse.cs index 6a20efc45..d1b5004b8 100644 --- a/src/Messaging/Messages/Server/ConnectToPeerResponse.cs +++ b/src/Messaging/Messages/Server/ConnectToPeerResponse.cs @@ -126,6 +126,11 @@ public static ConnectToPeerResponse FromByteArray(byte[] bytes) var token = reader.ReadInteger(); var isPrivileged = reader.ReadByte() > 0; + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.ConnectToPeer)} finalized with {reader.Remaining} unread bytes"); + } + return new ConnectToPeerResponse(username, type, ipAddress, port, token, isPrivileged); } } diff --git a/src/Messaging/Messages/Server/ExcludedSearchPhrasesNotification.cs b/src/Messaging/Messages/Server/ExcludedSearchPhrasesNotification.cs index 2d68710b7..0041f09b3 100644 --- a/src/Messaging/Messages/Server/ExcludedSearchPhrasesNotification.cs +++ b/src/Messaging/Messages/Server/ExcludedSearchPhrasesNotification.cs @@ -53,6 +53,11 @@ public static IReadOnlyCollection FromByteArray(byte[] bytes) list.Add(reader.ReadString()); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.ExcludedSearchPhrases)} finalized with {reader.Remaining} unread bytes"); + } + return list.AsReadOnly(); } } diff --git a/src/Messaging/Messages/Server/GlobalMessageNotification.cs b/src/Messaging/Messages/Server/GlobalMessageNotification.cs index c8e80b3a0..f51abe889 100644 --- a/src/Messaging/Messages/Server/GlobalMessageNotification.cs +++ b/src/Messaging/Messages/Server/GlobalMessageNotification.cs @@ -45,6 +45,11 @@ public static string FromByteArray(byte[] bytes) var msg = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.GlobalAdminMessage)} finalized with {reader.Remaining} unread bytes"); + } + return msg; } } diff --git a/src/Messaging/Messages/Server/IntegerResponse.cs b/src/Messaging/Messages/Server/IntegerResponse.cs index 2ce741fe3..c461fd9c2 100644 --- a/src/Messaging/Messages/Server/IntegerResponse.cs +++ b/src/Messaging/Messages/Server/IntegerResponse.cs @@ -41,7 +41,14 @@ public static int FromByteArray(byte[] bytes) where T : Enum { var reader = new MessageReader(bytes); - return reader.ReadInteger(); + var value = reader.ReadInteger(); + + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {reader.ReadCode()} finalized with {reader.Remaining} unread bytes"); + } + + return value; } } } \ No newline at end of file diff --git a/src/Messaging/Messages/Server/JoinRoomResponse.cs b/src/Messaging/Messages/Server/JoinRoomResponse.cs index 6480d1a3d..ddbc5eba7 100644 --- a/src/Messaging/Messages/Server/JoinRoomResponse.cs +++ b/src/Messaging/Messages/Server/JoinRoomResponse.cs @@ -121,6 +121,11 @@ internal static RoomData FromByteArray(byte[] bytes) } } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.JoinRoom)} finalized with {reader.Remaining} unread bytes"); + } + return new RoomData(roomName, users, owner != null, owner, operatorList); } } diff --git a/src/Messaging/Messages/Server/LeaveRoomResponse.cs b/src/Messaging/Messages/Server/LeaveRoomResponse.cs index 22a9956f7..8c03fdd05 100644 --- a/src/Messaging/Messages/Server/LeaveRoomResponse.cs +++ b/src/Messaging/Messages/Server/LeaveRoomResponse.cs @@ -59,6 +59,11 @@ public static LeaveRoomResponse FromByteArray(byte[] bytes) var roomName = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.LeaveRoom)} finalized with {reader.Remaining} unread bytes"); + } + return new LeaveRoomResponse(roomName); } } diff --git a/src/Messaging/Messages/Server/LoginResponse.cs b/src/Messaging/Messages/Server/LoginResponse.cs index 378a651b5..27c50b31f 100644 --- a/src/Messaging/Messages/Server/LoginResponse.cs +++ b/src/Messaging/Messages/Server/LoginResponse.cs @@ -114,6 +114,11 @@ public static LoginResponse FromByteArray(byte[] bytes) msg += string.IsNullOrWhiteSpace(detail) ? string.Empty : ": " + detail; } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.Login)} finalized with {reader.Remaining} unread bytes"); + } + return new LoginResponse(succeeded, msg, ipAddress, hash, isSupporter); } } diff --git a/src/Messaging/Messages/Server/NetInfoNotification.cs b/src/Messaging/Messages/Server/NetInfoNotification.cs index 78d872fb3..95feeca4c 100644 --- a/src/Messaging/Messages/Server/NetInfoNotification.cs +++ b/src/Messaging/Messages/Server/NetInfoNotification.cs @@ -85,6 +85,11 @@ public static NetInfoNotification FromByteArray(byte[] bytes) parents.Add((username, ipAddress, port)); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.NetInfo)} finalized with {reader.Remaining} unread bytes"); + } + return new NetInfoNotification(parentCount, parents.AsReadOnly()); } } diff --git a/src/Messaging/Messages/Server/NewPassword.cs b/src/Messaging/Messages/Server/NewPassword.cs index 3a6aa1821..a39a5046d 100644 --- a/src/Messaging/Messages/Server/NewPassword.cs +++ b/src/Messaging/Messages/Server/NewPassword.cs @@ -59,6 +59,11 @@ public static NewPassword FromByteArray(byte[] bytes) var password = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.NewPassword)} finalized with {reader.Remaining} unread bytes"); + } + return new NewPassword(password); } diff --git a/src/Messaging/Messages/Server/PrivateMessageNotification.cs b/src/Messaging/Messages/Server/PrivateMessageNotification.cs index 76e2aef13..1fd957982 100644 --- a/src/Messaging/Messages/Server/PrivateMessageNotification.cs +++ b/src/Messaging/Messages/Server/PrivateMessageNotification.cs @@ -97,6 +97,11 @@ public static PrivateMessageNotification FromByteArray(byte[] bytes) var replayed = reader.ReadByte() != 1; + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PrivateMessage)} finalized with {reader.Remaining} unread bytes"); + } + return new PrivateMessageNotification(id, timestamp, username, msg, replayed); } } diff --git a/src/Messaging/Messages/Server/PrivateRoomAddOperator.cs b/src/Messaging/Messages/Server/PrivateRoomAddOperator.cs index bc3196dff..7511e2779 100644 --- a/src/Messaging/Messages/Server/PrivateRoomAddOperator.cs +++ b/src/Messaging/Messages/Server/PrivateRoomAddOperator.cs @@ -67,6 +67,11 @@ public static PrivateRoomAddOperator FromByteArray(byte[] bytes) var roomName = reader.ReadString(); var username = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PrivateRoomAddOperator)} finalized with {reader.Remaining} unread bytes"); + } + return new PrivateRoomAddOperator(roomName, username); } diff --git a/src/Messaging/Messages/Server/PrivateRoomAddUser.cs b/src/Messaging/Messages/Server/PrivateRoomAddUser.cs index 86fba38f1..bbd45c702 100644 --- a/src/Messaging/Messages/Server/PrivateRoomAddUser.cs +++ b/src/Messaging/Messages/Server/PrivateRoomAddUser.cs @@ -67,6 +67,11 @@ public static PrivateRoomAddUser FromByteArray(byte[] bytes) var roomName = reader.ReadString(); var username = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PrivateRoomAddUser)} finalized with {reader.Remaining} unread bytes"); + } + return new PrivateRoomAddUser(roomName, username); } diff --git a/src/Messaging/Messages/Server/PrivateRoomOwnedListNotification.cs b/src/Messaging/Messages/Server/PrivateRoomOwnedListNotification.cs index 1354cb3e0..d062d1ed7 100644 --- a/src/Messaging/Messages/Server/PrivateRoomOwnedListNotification.cs +++ b/src/Messaging/Messages/Server/PrivateRoomOwnedListNotification.cs @@ -55,6 +55,11 @@ public static RoomInfo FromByteArray(byte[] bytes) userList.Add(reader.ReadString()); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PrivateRoomOwned)} finalized with {reader.Remaining} unread bytes"); + } + return new RoomInfo(roomName, userList); } } diff --git a/src/Messaging/Messages/Server/PrivateRoomRemoveOperator.cs b/src/Messaging/Messages/Server/PrivateRoomRemoveOperator.cs index 28366160e..12d63d2c5 100644 --- a/src/Messaging/Messages/Server/PrivateRoomRemoveOperator.cs +++ b/src/Messaging/Messages/Server/PrivateRoomRemoveOperator.cs @@ -67,6 +67,11 @@ public static PrivateRoomRemoveOperator FromByteArray(byte[] bytes) var roomName = reader.ReadString(); var username = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PrivateRoomRemoveOperator)} finalized with {reader.Remaining} unread bytes"); + } + return new PrivateRoomRemoveOperator(roomName, username); } From e24a3384d2a3bf0aa321f18561b34fac757f722f Mon Sep 17 00:00:00 2001 From: JP Dillingham Date: Wed, 2 Sep 2026 08:47:30 -0500 Subject: [PATCH 5/8] add logging of unread data --- src/Messaging/Messages/Server/PrivateRoomRemoveUser.cs | 5 +++++ src/Messaging/Messages/Server/PrivateRoomToggle.cs | 5 +++++ .../Messages/Server/PrivateRoomUserListNotification.cs | 5 +++++ src/Messaging/Messages/Server/PrivilegeNotification.cs | 5 +++++ .../Messages/Server/PrivilegedUserListNotification.cs | 5 +++++ .../Messages/Server/PrivilegedUserNotification.cs | 5 +++++ .../Messages/Server/PublicChatMessageNotification.cs | 5 +++++ src/Messaging/Messages/Server/RoomListResponseFactory.cs | 5 +++++ src/Messaging/Messages/Server/RoomMessageNotification.cs | 5 +++++ .../Messages/Server/RoomTickerAddedNotification.cs | 5 +++++ .../Messages/Server/RoomTickerListNotification.cs | 5 +++++ .../Messages/Server/RoomTickerRemovedNotification.cs | 5 +++++ src/Messaging/Messages/Server/ServerPing.cs | 5 +++++ src/Messaging/Messages/Server/ServerSearchRequest.cs | 5 +++++ src/Messaging/Messages/Server/StringResponse.cs | 9 ++++++++- src/Messaging/Messages/Server/UserAddressResponse.cs | 5 +++++ .../Messages/Server/UserJoinedRoomNotification.cs | 5 +++++ .../Messages/Server/UserLeftRoomNotification.cs | 5 +++++ src/Messaging/Messages/Server/UserPrivilegeResponse.cs | 5 +++++ .../Messages/Server/UserStatisticsResponseFactory.cs | 5 +++++ .../Messages/Server/UserStatusResponseFactory.cs | 5 +++++ src/Messaging/Messages/Server/WatchUserResponse.cs | 5 +++++ 22 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/Messaging/Messages/Server/PrivateRoomRemoveUser.cs b/src/Messaging/Messages/Server/PrivateRoomRemoveUser.cs index ae9ed1a32..369d7cd12 100644 --- a/src/Messaging/Messages/Server/PrivateRoomRemoveUser.cs +++ b/src/Messaging/Messages/Server/PrivateRoomRemoveUser.cs @@ -67,6 +67,11 @@ public static PrivateRoomRemoveUser FromByteArray(byte[] bytes) var roomName = reader.ReadString(); var username = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PrivateRoomRemoveUser)} finalized with {reader.Remaining} unread bytes"); + } + return new PrivateRoomRemoveUser(roomName, username); } diff --git a/src/Messaging/Messages/Server/PrivateRoomToggle.cs b/src/Messaging/Messages/Server/PrivateRoomToggle.cs index 77b454dbb..ff443e0f9 100644 --- a/src/Messaging/Messages/Server/PrivateRoomToggle.cs +++ b/src/Messaging/Messages/Server/PrivateRoomToggle.cs @@ -59,6 +59,11 @@ public static PrivateRoomToggle FromByteArray(byte[] bytes) var acceptInvitations = reader.ReadByte() > 0; + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PrivateRoomToggle)} finalized with {reader.Remaining} unread bytes"); + } + return new PrivateRoomToggle(acceptInvitations); } diff --git a/src/Messaging/Messages/Server/PrivateRoomUserListNotification.cs b/src/Messaging/Messages/Server/PrivateRoomUserListNotification.cs index 4a9724995..f8466fe0c 100644 --- a/src/Messaging/Messages/Server/PrivateRoomUserListNotification.cs +++ b/src/Messaging/Messages/Server/PrivateRoomUserListNotification.cs @@ -55,6 +55,11 @@ public static RoomInfo FromByteArray(byte[] bytes) userList.Add(reader.ReadString()); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PrivateRoomUsers)} finalized with {reader.Remaining} unread bytes"); + } + return new RoomInfo(roomName, userList); } } diff --git a/src/Messaging/Messages/Server/PrivilegeNotification.cs b/src/Messaging/Messages/Server/PrivilegeNotification.cs index 350b44358..ab2e8dfc8 100644 --- a/src/Messaging/Messages/Server/PrivilegeNotification.cs +++ b/src/Messaging/Messages/Server/PrivilegeNotification.cs @@ -72,6 +72,11 @@ public static PrivilegeNotification FromByteArray(byte[] bytes) var id = reader.ReadInteger(); var username = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.NotifyPrivileges)} finalized with {reader.Remaining} unread bytes"); + } + return new PrivilegeNotification(id, username); } } diff --git a/src/Messaging/Messages/Server/PrivilegedUserListNotification.cs b/src/Messaging/Messages/Server/PrivilegedUserListNotification.cs index 039280151..ad93fc05e 100644 --- a/src/Messaging/Messages/Server/PrivilegedUserListNotification.cs +++ b/src/Messaging/Messages/Server/PrivilegedUserListNotification.cs @@ -53,6 +53,11 @@ public static IReadOnlyCollection FromByteArray(byte[] bytes) list.Add(reader.ReadString()); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PrivilegedUsers)} finalized with {reader.Remaining} unread bytes"); + } + return list.AsReadOnly(); } } diff --git a/src/Messaging/Messages/Server/PrivilegedUserNotification.cs b/src/Messaging/Messages/Server/PrivilegedUserNotification.cs index f5f63fb5a..01f249237 100644 --- a/src/Messaging/Messages/Server/PrivilegedUserNotification.cs +++ b/src/Messaging/Messages/Server/PrivilegedUserNotification.cs @@ -45,6 +45,11 @@ public static string FromByteArray(byte[] bytes) var username = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.AddPrivilegedUser)} finalized with {reader.Remaining} unread bytes"); + } + return username; } } diff --git a/src/Messaging/Messages/Server/PublicChatMessageNotification.cs b/src/Messaging/Messages/Server/PublicChatMessageNotification.cs index 6f5ced3d2..7c5e5cddc 100644 --- a/src/Messaging/Messages/Server/PublicChatMessageNotification.cs +++ b/src/Messaging/Messages/Server/PublicChatMessageNotification.cs @@ -75,6 +75,11 @@ public static PublicChatMessageNotification FromByteArray(byte[] bytes) var username = reader.ReadString(); var msg = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.PublicChat)} finalized with {reader.Remaining} unread bytes"); + } + return new PublicChatMessageNotification(roomName, username, msg); } } diff --git a/src/Messaging/Messages/Server/RoomListResponseFactory.cs b/src/Messaging/Messages/Server/RoomListResponseFactory.cs index d861710a4..a5821d193 100644 --- a/src/Messaging/Messages/Server/RoomListResponseFactory.cs +++ b/src/Messaging/Messages/Server/RoomListResponseFactory.cs @@ -50,6 +50,11 @@ public static RoomList FromByteArray(byte[] bytes) var privateRooms = ReadRoomInfoList(reader); var moderatedRoomNames = ReadRoomNameList(reader); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.RoomList)} finalized with {reader.Remaining} unread bytes"); + } + return new RoomList( publicList: rooms, privateList: privateRooms, diff --git a/src/Messaging/Messages/Server/RoomMessageNotification.cs b/src/Messaging/Messages/Server/RoomMessageNotification.cs index 84c3b6d41..cdf4b4ae6 100644 --- a/src/Messaging/Messages/Server/RoomMessageNotification.cs +++ b/src/Messaging/Messages/Server/RoomMessageNotification.cs @@ -75,6 +75,11 @@ public static RoomMessageNotification FromByteArray(byte[] bytes) var username = reader.ReadString(); var msg = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.SayInChatRoom)} finalized with {reader.Remaining} unread bytes"); + } + return new RoomMessageNotification(roomName, username, msg); } } diff --git a/src/Messaging/Messages/Server/RoomTickerAddedNotification.cs b/src/Messaging/Messages/Server/RoomTickerAddedNotification.cs index 7d78549fe..0846ae014 100644 --- a/src/Messaging/Messages/Server/RoomTickerAddedNotification.cs +++ b/src/Messaging/Messages/Server/RoomTickerAddedNotification.cs @@ -70,6 +70,11 @@ public static RoomTickerAddedNotification FromByteArray(byte[] bytes) var username = reader.ReadString(); var message = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.RoomTickerAdd)} finalized with {reader.Remaining} unread bytes"); + } + return new RoomTickerAddedNotification(roomName, new RoomTicker(username, message)); } } diff --git a/src/Messaging/Messages/Server/RoomTickerListNotification.cs b/src/Messaging/Messages/Server/RoomTickerListNotification.cs index 1a224e3f3..de8126514 100644 --- a/src/Messaging/Messages/Server/RoomTickerListNotification.cs +++ b/src/Messaging/Messages/Server/RoomTickerListNotification.cs @@ -89,6 +89,11 @@ public static RoomTickerListNotification FromByteArray(byte[] bytes) tickers.Add(new RoomTicker(username, message)); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.RoomTickers)} finalized with {reader.Remaining} unread bytes"); + } + return new RoomTickerListNotification(roomName, tickerCount, tickers); } } diff --git a/src/Messaging/Messages/Server/RoomTickerRemovedNotification.cs b/src/Messaging/Messages/Server/RoomTickerRemovedNotification.cs index 1af15de73..ac0f8b8ac 100644 --- a/src/Messaging/Messages/Server/RoomTickerRemovedNotification.cs +++ b/src/Messaging/Messages/Server/RoomTickerRemovedNotification.cs @@ -69,6 +69,11 @@ public static RoomTickerRemovedNotification FromByteArray(byte[] bytes) var roomName = reader.ReadString(); var username = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.RoomTickerRemove)} finalized with {reader.Remaining} unread bytes"); + } + return new RoomTickerRemovedNotification(roomName, username); } } diff --git a/src/Messaging/Messages/Server/ServerPing.cs b/src/Messaging/Messages/Server/ServerPing.cs index 7f1dbd718..b9807e086 100644 --- a/src/Messaging/Messages/Server/ServerPing.cs +++ b/src/Messaging/Messages/Server/ServerPing.cs @@ -50,6 +50,11 @@ public static ServerPing FromByteArray(byte[] bytes) throw new MessageException($"Message Code mismatch creating {nameof(ServerPing)} (expected: {(int)MessageCode.Server.Ping}, received: {(int)code})"); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.Ping)} finalized with {reader.Remaining} unread bytes"); + } + return new ServerPing(); } diff --git a/src/Messaging/Messages/Server/ServerSearchRequest.cs b/src/Messaging/Messages/Server/ServerSearchRequest.cs index 92815f9cc..0797a4b82 100644 --- a/src/Messaging/Messages/Server/ServerSearchRequest.cs +++ b/src/Messaging/Messages/Server/ServerSearchRequest.cs @@ -79,6 +79,11 @@ public static ServerSearchRequest FromByteArray(byte[] bytes) var token = reader.ReadInteger(); var query = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.FileSearch)} finalized with {reader.Remaining} unread bytes"); + } + return new ServerSearchRequest(username, token, query); } } diff --git a/src/Messaging/Messages/Server/StringResponse.cs b/src/Messaging/Messages/Server/StringResponse.cs index a81a32f19..5aceccf6a 100644 --- a/src/Messaging/Messages/Server/StringResponse.cs +++ b/src/Messaging/Messages/Server/StringResponse.cs @@ -41,7 +41,14 @@ public static string FromByteArray(byte[] bytes) where T : Enum { var reader = new MessageReader(bytes); - return reader.ReadString(); + var value = reader.ReadString(); + + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {reader.ReadCode()} finalized with {reader.Remaining} unread bytes"); + } + + return value; } } } \ No newline at end of file diff --git a/src/Messaging/Messages/Server/UserAddressResponse.cs b/src/Messaging/Messages/Server/UserAddressResponse.cs index e90fb7804..e789e99d7 100644 --- a/src/Messaging/Messages/Server/UserAddressResponse.cs +++ b/src/Messaging/Messages/Server/UserAddressResponse.cs @@ -99,6 +99,11 @@ public static UserAddressResponse FromByteArray(byte[] bytes) var port = reader.ReadInteger(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.GetPeerAddress)} finalized with {reader.Remaining} unread bytes"); + } + return new UserAddressResponse(username, ipAddress, port); } } diff --git a/src/Messaging/Messages/Server/UserJoinedRoomNotification.cs b/src/Messaging/Messages/Server/UserJoinedRoomNotification.cs index 30908704c..862ff79ca 100644 --- a/src/Messaging/Messages/Server/UserJoinedRoomNotification.cs +++ b/src/Messaging/Messages/Server/UserJoinedRoomNotification.cs @@ -84,6 +84,11 @@ public static UserJoinedRoomNotification FromByteArray(byte[] bytes) var userData = new UserData(username, status, averageSpeed, downloadCount, fileCount, directoryCount, countryCode, slotsFree); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.UserJoinedRoom)} finalized with {reader.Remaining} unread bytes"); + } + return new UserJoinedRoomNotification(roomName, username, userData); } } diff --git a/src/Messaging/Messages/Server/UserLeftRoomNotification.cs b/src/Messaging/Messages/Server/UserLeftRoomNotification.cs index 936eea41e..d4819530d 100644 --- a/src/Messaging/Messages/Server/UserLeftRoomNotification.cs +++ b/src/Messaging/Messages/Server/UserLeftRoomNotification.cs @@ -67,6 +67,11 @@ public static UserLeftRoomNotification FromByteArray(byte[] bytes) var roomName = reader.ReadString(); var username = reader.ReadString(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.UserLeftRoom)} finalized with {reader.Remaining} unread bytes"); + } + return new UserLeftRoomNotification(roomName, username); } } diff --git a/src/Messaging/Messages/Server/UserPrivilegeResponse.cs b/src/Messaging/Messages/Server/UserPrivilegeResponse.cs index f34bc4a14..6da9b9e37 100644 --- a/src/Messaging/Messages/Server/UserPrivilegeResponse.cs +++ b/src/Messaging/Messages/Server/UserPrivilegeResponse.cs @@ -67,6 +67,11 @@ public static UserPrivilegeResponse FromByteArray(byte[] bytes) var username = reader.ReadString(); var privileged = reader.ReadByte() > 0; + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.UserPrivileges)} finalized with {reader.Remaining} unread bytes"); + } + return new UserPrivilegeResponse(username, privileged); } } diff --git a/src/Messaging/Messages/Server/UserStatisticsResponseFactory.cs b/src/Messaging/Messages/Server/UserStatisticsResponseFactory.cs index 4d89152ee..6d8a87e8a 100644 --- a/src/Messaging/Messages/Server/UserStatisticsResponseFactory.cs +++ b/src/Messaging/Messages/Server/UserStatisticsResponseFactory.cs @@ -49,6 +49,11 @@ public static UserStatistics FromByteArray(byte[] bytes) var fileCount = reader.ReadInteger(); var directoryCount = reader.ReadInteger(); + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.GetUserStats)} finalized with {reader.Remaining} unread bytes"); + } + return new UserStatistics(username, averageSpeed, uploadCount, fileCount, directoryCount); } } diff --git a/src/Messaging/Messages/Server/UserStatusResponseFactory.cs b/src/Messaging/Messages/Server/UserStatusResponseFactory.cs index 6bbd1dd5e..752e8d1b8 100644 --- a/src/Messaging/Messages/Server/UserStatusResponseFactory.cs +++ b/src/Messaging/Messages/Server/UserStatusResponseFactory.cs @@ -47,6 +47,11 @@ public static UserStatus FromByteArray(byte[] bytes) var presence = (UserPresence)reader.ReadInteger(); var privileged = reader.ReadByte() > 0; + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.GetStatus)} finalized with {reader.Remaining} unread bytes"); + } + return new UserStatus(username, presence, privileged); } } diff --git a/src/Messaging/Messages/Server/WatchUserResponse.cs b/src/Messaging/Messages/Server/WatchUserResponse.cs index 8e52f2780..77f26d4a1 100644 --- a/src/Messaging/Messages/Server/WatchUserResponse.cs +++ b/src/Messaging/Messages/Server/WatchUserResponse.cs @@ -93,6 +93,11 @@ public static WatchUserResponse FromByteArray(byte[] bytes) user = new UserData(username, status, averageSpeed, downloadCount, fileCount, directoryCount, countryCode); } + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Server.WatchUser)} finalized with {reader.Remaining} unread bytes"); + } + return new WatchUserResponse(username, exists, user); } } From 7ee6a266601fac831256551abaa0836d0650eef8 Mon Sep 17 00:00:00 2001 From: JP Dillingham Date: Wed, 2 Sep 2026 08:47:53 -0500 Subject: [PATCH 6/8] fix namespace --- src/Messaging/Messages/Peer/UserInfoResponseFactory.cs | 4 +--- .../Messaging/Messages/Peer/UserInfoResponseFactoryTests.cs | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Messaging/Messages/Peer/UserInfoResponseFactory.cs b/src/Messaging/Messages/Peer/UserInfoResponseFactory.cs index 6473f5c95..58e10e32e 100644 --- a/src/Messaging/Messages/Peer/UserInfoResponseFactory.cs +++ b/src/Messaging/Messages/Peer/UserInfoResponseFactory.cs @@ -21,10 +21,8 @@ // SPDX-License-Identifier: GPL-3.0-only // -namespace Soulseek +namespace Soulseek.Messaging.Messages { - using Soulseek.Messaging; - /// /// The response to a user info request. /// diff --git a/tests/Soulseek.Tests.Unit/Messaging/Messages/Peer/UserInfoResponseFactoryTests.cs b/tests/Soulseek.Tests.Unit/Messaging/Messages/Peer/UserInfoResponseFactoryTests.cs index 8cbe455ea..a1d7309c9 100644 --- a/tests/Soulseek.Tests.Unit/Messaging/Messages/Peer/UserInfoResponseFactoryTests.cs +++ b/tests/Soulseek.Tests.Unit/Messaging/Messages/Peer/UserInfoResponseFactoryTests.cs @@ -19,6 +19,7 @@ namespace Soulseek.Tests.Unit.Messaging.Messages { using AutoFixture.Xunit2; using Soulseek.Messaging; + using Soulseek.Messaging.Messages; using Xunit; public class UserInfoResponseFactoryTests From b98eeac206841836bf640a749a23a5950c635ed4 Mon Sep 17 00:00:00 2001 From: JP Dillingham Date: Wed, 2 Sep 2026 08:48:19 -0500 Subject: [PATCH 7/8] add logging of unread data --- src/Messaging/Messages/Peer/TransferResponse.cs | 17 ++++++++++++++--- .../Messages/Peer/UserInfoResponseFactory.cs | 5 +++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Messaging/Messages/Peer/TransferResponse.cs b/src/Messaging/Messages/Peer/TransferResponse.cs index 8a790597d..de5239f45 100644 --- a/src/Messaging/Messages/Peer/TransferResponse.cs +++ b/src/Messaging/Messages/Peer/TransferResponse.cs @@ -100,18 +100,29 @@ public static TransferResponse FromByteArray(byte[] bytes) var token = reader.ReadInteger(); var allowed = reader.ReadByte() == 1; + TransferResponse response; + if (allowed && reader.HasMoreData) { var fileSize = reader.ReadLong(); - return new TransferResponse(token, fileSize); + response = new TransferResponse(token, fileSize); } else if (!allowed) { var msg = reader.ReadString(); - return new TransferResponse(token, msg); + response = new TransferResponse(token, msg); + } + else + { + response = new TransferResponse(token); + } + + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.TransferResponse)} finalized with {reader.Remaining} unread bytes"); } - return new TransferResponse(token); + return response; } /// diff --git a/src/Messaging/Messages/Peer/UserInfoResponseFactory.cs b/src/Messaging/Messages/Peer/UserInfoResponseFactory.cs index 58e10e32e..2b2333488 100644 --- a/src/Messaging/Messages/Peer/UserInfoResponseFactory.cs +++ b/src/Messaging/Messages/Peer/UserInfoResponseFactory.cs @@ -57,6 +57,11 @@ public static UserInfo FromByteArray(byte[] bytes) var queueLength = reader.ReadInteger(); var hasFreeUploadSlot = reader.ReadByte() > 0; + if (SoulseekClient.ReportUnreadMessageData && reader.HasMoreData) + { + Diagnostics.GlobalDiagnostic.Warning($"Message reader for {nameof(MessageCode.Peer.InfoResponse)} finalized with {reader.Remaining} unread bytes"); + } + return new UserInfo(description, uploadSlots, queueLength, hasFreeUploadSlot, picture); } From cddbf13b4b2cb24be3751b5a8ce34638b214b22f Mon Sep 17 00:00:00 2001 From: JP Dillingham Date: Sat, 5 Sep 2026 15:29:10 -0500 Subject: [PATCH 8/8] move all tests into one file for easy deletion --- .../Messages/UnreadMessageDataTests.cs | 3110 +++++++++++++++++ 1 file changed, 3110 insertions(+) create mode 100644 tests/Soulseek.Tests.Unit/Messaging/Messages/UnreadMessageDataTests.cs diff --git a/tests/Soulseek.Tests.Unit/Messaging/Messages/UnreadMessageDataTests.cs b/tests/Soulseek.Tests.Unit/Messaging/Messages/UnreadMessageDataTests.cs new file mode 100644 index 000000000..0ac5d62ff --- /dev/null +++ b/tests/Soulseek.Tests.Unit/Messaging/Messages/UnreadMessageDataTests.cs @@ -0,0 +1,3110 @@ +// +// Copyright (c) JP Dillingham. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see https://www.gnu.org/licenses/. +// + +// The tests in this file cover the unread message data reporting added to the message parsers. +// They live together in one file, rather than alongside the tests for each message, so that the +// whole lot can be deleted in one step if the reporting is removed. +#pragma warning disable SA1402 // File may only contain a single type + +namespace Soulseek.Tests.Unit.Messaging.Messages +{ + using System; + using System.Collections.Generic; + using Soulseek.Diagnostics; + using Soulseek.Messaging; + using Soulseek.Messaging.Messages; + using Xunit; + + /// + /// Tests for the unread message data reported by the message parsers when + /// is enabled. + /// + [Collection(UnreadMessageDataTests.CollectionName)] + public class UnreadMessageDataTests + { + /// + /// The name of the xunit collection to which these tests belong. + /// + public const string CollectionName = "UnreadMessageData"; + + // DistributedBranchLevel + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedBranchLevel FromByteArray reports unread data when reporting is enabled")] + public void DistributedBranchLevel_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.BranchLevel) + .WriteInteger(1) // level + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedBranchLevel.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedBranchLevel FromByteArray does not report unread data when there is none")] + public void DistributedBranchLevel_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.BranchLevel) + .WriteInteger(1) // level + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedBranchLevel.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedBranchLevel FromByteArray does not report unread data when reporting is disabled")] + public void DistributedBranchLevel_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.BranchLevel) + .WriteInteger(1) // level + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => DistributedBranchLevel.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // DistributedBranchRoot + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedBranchRoot FromByteArray reports unread data when reporting is enabled")] + public void DistributedBranchRoot_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.BranchRoot) + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedBranchRoot.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedBranchRoot FromByteArray does not report unread data when there is none")] + public void DistributedBranchRoot_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.BranchRoot) + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedBranchRoot.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedBranchRoot FromByteArray does not report unread data when reporting is disabled")] + public void DistributedBranchRoot_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.BranchRoot) + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => DistributedBranchRoot.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // DistributedChildDepth + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedChildDepth FromByteArray reports unread data when reporting is enabled")] + public void DistributedChildDepth_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.ChildDepth) + .WriteInteger(1) // depth + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedChildDepth.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedChildDepth FromByteArray does not report unread data when there is none")] + public void DistributedChildDepth_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.ChildDepth) + .WriteInteger(1) // depth + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedChildDepth.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedChildDepth FromByteArray does not report unread data when reporting is disabled")] + public void DistributedChildDepth_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.ChildDepth) + .WriteInteger(1) // depth + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => DistributedChildDepth.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // DistributedPingRequest + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedPingRequest FromByteArray reports unread data when reporting is enabled")] + public void DistributedPingRequest_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.Ping) + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedPingRequest.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedPingRequest FromByteArray does not report unread data when there is none")] + public void DistributedPingRequest_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.Ping) + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedPingRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedPingRequest FromByteArray does not report unread data when reporting is disabled")] + public void DistributedPingRequest_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.Ping) + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => DistributedPingRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // DistributedPingResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedPingResponse FromByteArray reports unread data when reporting is enabled")] + public void DistributedPingResponse_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.Ping) + .WriteInteger(1) // token + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedPingResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedPingResponse FromByteArray does not report unread data when there is none")] + public void DistributedPingResponse_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.Ping) + .WriteInteger(1) // token + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedPingResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedPingResponse FromByteArray does not report unread data when reporting is disabled")] + public void DistributedPingResponse_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.Ping) + .WriteInteger(1) // token + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => DistributedPingResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // DistributedSearchRequest + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedSearchRequest FromByteArray reports unread data when reporting is enabled")] + public void DistributedSearchRequest_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.SearchRequest) + .WriteInteger(0) // unknown + .WriteString("username") + .WriteInteger(1) // token + .WriteString("query") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedSearchRequest.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedSearchRequest FromByteArray does not report unread data when there is none")] + public void DistributedSearchRequest_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.SearchRequest) + .WriteInteger(0) // unknown + .WriteString("username") + .WriteInteger(1) // token + .WriteString("query") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => DistributedSearchRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "DistributedSearchRequest FromByteArray does not report unread data when reporting is disabled")] + public void DistributedSearchRequest_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Distributed.SearchRequest) + .WriteInteger(0) // unknown + .WriteString("username") + .WriteInteger(1) // token + .WriteString("query") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => DistributedSearchRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PeerInit + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PeerInit TryFromByteArray reports unread data when reporting is enabled")] + public void PeerInit_TryFromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Initialization.PeerInit) + .WriteString("username") + .WriteString("P") + .WriteInteger(1) // token + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PeerInit.TryFromByteArray(msg, out _)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PeerInit TryFromByteArray does not report unread data when there is none")] + public void PeerInit_TryFromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Initialization.PeerInit) + .WriteString("username") + .WriteString("P") + .WriteInteger(1) // token + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PeerInit.TryFromByteArray(msg, out _)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PeerInit TryFromByteArray does not report unread data when reporting is disabled")] + public void PeerInit_TryFromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Initialization.PeerInit) + .WriteString("username") + .WriteString("P") + .WriteInteger(1) // token + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PeerInit.TryFromByteArray(msg, out _)); + + Assert.Empty(warnings); + } + + // PierceFirewall + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PierceFirewall TryFromByteArray reports unread data when reporting is enabled")] + public void PierceFirewall_TryFromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Initialization.PierceFirewall) + .WriteInteger(1) // token + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PierceFirewall.TryFromByteArray(msg, out _)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PierceFirewall TryFromByteArray does not report unread data when there is none")] + public void PierceFirewall_TryFromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Initialization.PierceFirewall) + .WriteInteger(1) // token + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PierceFirewall.TryFromByteArray(msg, out _)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PierceFirewall TryFromByteArray does not report unread data when reporting is disabled")] + public void PierceFirewall_TryFromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Initialization.PierceFirewall) + .WriteInteger(1) // token + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PierceFirewall.TryFromByteArray(msg, out _)); + + Assert.Empty(warnings); + } + + // BrowseResponseFactory + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "BrowseResponseFactory Parse reports unread data when reporting is enabled")] + public void BrowseResponseFactory_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.BrowseResponse) + .WriteInteger(0) // directory count + .WriteInteger(0) // unknown + .WriteInteger(0) // locked directory count + .WriteInteger(0) // extra, unread data + .Compress() + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => BrowseResponseFactory.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "BrowseResponseFactory Parse does not report unread data when there is none")] + public void BrowseResponseFactory_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.BrowseResponse) + .WriteInteger(0) // directory count + .Compress() + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => BrowseResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "BrowseResponseFactory Parse does not report unread data when reporting is disabled")] + public void BrowseResponseFactory_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.BrowseResponse) + .WriteInteger(0) // directory count + .WriteInteger(0) // unknown + .WriteInteger(0) // locked directory count + .WriteInteger(0) // extra, unread data + .Compress() + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => BrowseResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // FolderContentsRequest + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "FolderContentsRequest FromByteArray reports unread data when reporting is enabled")] + public void FolderContentsRequest_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.FolderContentsRequest) + .WriteInteger(1) // token + .WriteString("directory") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => FolderContentsRequest.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "FolderContentsRequest FromByteArray does not report unread data when there is none")] + public void FolderContentsRequest_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.FolderContentsRequest) + .WriteInteger(1) // token + .WriteString("directory") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => FolderContentsRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "FolderContentsRequest FromByteArray does not report unread data when reporting is disabled")] + public void FolderContentsRequest_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.FolderContentsRequest) + .WriteInteger(1) // token + .WriteString("directory") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => FolderContentsRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // FolderContentsResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "FolderContentsResponse Parse reports unread data when reporting is enabled")] + public void FolderContentsResponse_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.FolderContentsResponse) + .WriteInteger(1) // token + .WriteString("directory") + .WriteInteger(1) // directory count + .WriteString("directory") + .WriteInteger(0) // file count + .WriteInteger(0) // extra, unread data + .Compress() + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => FolderContentsResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "FolderContentsResponse Parse does not report unread data when there is none")] + public void FolderContentsResponse_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.FolderContentsResponse) + .WriteInteger(1) // token + .WriteString("directory") + .WriteInteger(1) // directory count + .WriteString("directory") + .WriteInteger(0) // file count + .Compress() + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => FolderContentsResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "FolderContentsResponse Parse does not report unread data when reporting is disabled")] + public void FolderContentsResponse_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.FolderContentsResponse) + .WriteInteger(1) // token + .WriteString("directory") + .WriteInteger(1) // directory count + .WriteString("directory") + .WriteInteger(0) // file count + .WriteInteger(0) // extra, unread data + .Compress() + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => FolderContentsResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PeerSearchRequest + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PeerSearchRequest FromByteArray reports unread data when reporting is enabled")] + public void PeerSearchRequest_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.SearchRequest) + .WriteInteger(1) // token + .WriteString("query") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PeerSearchRequest.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PeerSearchRequest FromByteArray does not report unread data when there is none")] + public void PeerSearchRequest_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.SearchRequest) + .WriteInteger(1) // token + .WriteString("query") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PeerSearchRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PeerSearchRequest FromByteArray does not report unread data when reporting is disabled")] + public void PeerSearchRequest_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.SearchRequest) + .WriteInteger(1) // token + .WriteString("query") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PeerSearchRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PlaceInQueueRequest + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PlaceInQueueRequest FromByteArray reports unread data when reporting is enabled")] + public void PlaceInQueueRequest_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.PlaceInQueueRequest) + .WriteString("filename") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PlaceInQueueRequest.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PlaceInQueueRequest FromByteArray does not report unread data when there is none")] + public void PlaceInQueueRequest_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.PlaceInQueueRequest) + .WriteString("filename") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PlaceInQueueRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PlaceInQueueRequest FromByteArray does not report unread data when reporting is disabled")] + public void PlaceInQueueRequest_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.PlaceInQueueRequest) + .WriteString("filename") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PlaceInQueueRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PlaceInQueueResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PlaceInQueueResponse FromByteArray reports unread data when reporting is enabled")] + public void PlaceInQueueResponse_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.PlaceInQueueResponse) + .WriteString("filename") + .WriteInteger(1) // place in queue + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PlaceInQueueResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PlaceInQueueResponse FromByteArray does not report unread data when there is none")] + public void PlaceInQueueResponse_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.PlaceInQueueResponse) + .WriteString("filename") + .WriteInteger(1) // place in queue + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PlaceInQueueResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PlaceInQueueResponse FromByteArray does not report unread data when reporting is disabled")] + public void PlaceInQueueResponse_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.PlaceInQueueResponse) + .WriteString("filename") + .WriteInteger(1) // place in queue + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PlaceInQueueResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // QueueDownloadRequest + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "QueueDownloadRequest FromByteArray reports unread data when reporting is enabled")] + public void QueueDownloadRequest_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.QueueDownload) + .WriteString("filename") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => QueueDownloadRequest.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "QueueDownloadRequest FromByteArray does not report unread data when there is none")] + public void QueueDownloadRequest_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.QueueDownload) + .WriteString("filename") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => QueueDownloadRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "QueueDownloadRequest FromByteArray does not report unread data when reporting is disabled")] + public void QueueDownloadRequest_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.QueueDownload) + .WriteString("filename") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => QueueDownloadRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // SearchResponseFactory + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "SearchResponseFactory Parse reports unread data when reporting is enabled")] + public void SearchResponseFactory_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.SearchResponse) + .WriteString("username") + .WriteInteger(1) // token + .WriteInteger(0) // file count + .WriteByte(0x1) // has free upload slot + .WriteInteger(1) // upload speed + .WriteInteger(0) // queue length + .WriteInteger(0) // unknown + .WriteInteger(0) // locked file count + .WriteInteger(0) // extra, unread data + .Compress() + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => SearchResponseFactory.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "SearchResponseFactory Parse does not report unread data when there is none")] + public void SearchResponseFactory_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.SearchResponse) + .WriteString("username") + .WriteInteger(1) // token + .WriteInteger(0) // file count + .WriteByte(0x1) // has free upload slot + .WriteInteger(1) // upload speed + .WriteInteger(0) // queue length + .Compress() + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => SearchResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "SearchResponseFactory Parse does not report unread data when reporting is disabled")] + public void SearchResponseFactory_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.SearchResponse) + .WriteString("username") + .WriteInteger(1) // token + .WriteInteger(0) // file count + .WriteByte(0x1) // has free upload slot + .WriteInteger(1) // upload speed + .WriteInteger(0) // queue length + .WriteInteger(0) // unknown + .WriteInteger(0) // locked file count + .WriteInteger(0) // extra, unread data + .Compress() + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => SearchResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // TransferRequest + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "TransferRequest FromByteArray reports unread data when reporting is enabled")] + public void TransferRequest_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.TransferRequest) + .WriteInteger(0) // direction + .WriteInteger(1) // token + .WriteString("filename") + .WriteLong(1) // file size + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => TransferRequest.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "TransferRequest FromByteArray does not report unread data when there is none")] + public void TransferRequest_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.TransferRequest) + .WriteInteger(0) // direction + .WriteInteger(1) // token + .WriteString("filename") + .WriteLong(1) // file size + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => TransferRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "TransferRequest FromByteArray does not report unread data when reporting is disabled")] + public void TransferRequest_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.TransferRequest) + .WriteInteger(0) // direction + .WriteInteger(1) // token + .WriteString("filename") + .WriteLong(1) // file size + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => TransferRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // TransferResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "TransferResponse Parse reports unread data when reporting is enabled")] + public void TransferResponse_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.TransferResponse) + .WriteInteger(1) // token + .WriteByte(0x1) // allowed + .WriteLong(1) // file size + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => TransferResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "TransferResponse Parse does not report unread data when there is none")] + public void TransferResponse_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.TransferResponse) + .WriteInteger(1) // token + .WriteByte(0x1) // allowed + .WriteLong(1) // file size + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => TransferResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "TransferResponse Parse does not report unread data when reporting is disabled")] + public void TransferResponse_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.TransferResponse) + .WriteInteger(1) // token + .WriteByte(0x1) // allowed + .WriteLong(1) // file size + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => TransferResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "TransferResponse Parse reports unread data when not allowed and reporting is enabled")] + public void TransferResponse_Parse_Reports_Unread_Data_When_Not_Allowed_And_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.TransferResponse) + .WriteInteger(1) // token + .WriteByte(0x0) // allowed + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => TransferResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + // UploadDenied + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UploadDenied FromByteArray reports unread data when reporting is enabled")] + public void UploadDenied_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.UploadDenied) + .WriteString("filename") + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UploadDenied.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UploadDenied FromByteArray does not report unread data when there is none")] + public void UploadDenied_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.UploadDenied) + .WriteString("filename") + .WriteString("message") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UploadDenied.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UploadDenied FromByteArray does not report unread data when reporting is disabled")] + public void UploadDenied_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.UploadDenied) + .WriteString("filename") + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => UploadDenied.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // UploadFailed + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UploadFailed FromByteArray reports unread data when reporting is enabled")] + public void UploadFailed_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.UploadFailed) + .WriteString("filename") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UploadFailed.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UploadFailed FromByteArray does not report unread data when there is none")] + public void UploadFailed_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.UploadFailed) + .WriteString("filename") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UploadFailed.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UploadFailed FromByteArray does not report unread data when reporting is disabled")] + public void UploadFailed_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.UploadFailed) + .WriteString("filename") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => UploadFailed.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // UserInfoResponseFactory + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserInfoResponseFactory Parse reports unread data when reporting is enabled")] + public void UserInfoResponseFactory_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.InfoResponse) + .WriteString("description") + .WriteByte(0) // has picture + .WriteInteger(1) // upload slots + .WriteInteger(0) // queue length + .WriteByte(1) // has free upload slot + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserInfoResponseFactory.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserInfoResponseFactory Parse does not report unread data when there is none")] + public void UserInfoResponseFactory_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.InfoResponse) + .WriteString("description") + .WriteByte(0) // has picture + .WriteInteger(1) // upload slots + .WriteInteger(0) // queue length + .WriteByte(1) // has free upload slot + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserInfoResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserInfoResponseFactory Parse does not report unread data when reporting is disabled")] + public void UserInfoResponseFactory_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Peer.InfoResponse) + .WriteString("description") + .WriteByte(0) // has picture + .WriteInteger(1) // upload slots + .WriteInteger(0) // queue length + .WriteByte(1) // has free upload slot + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => UserInfoResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // CannotConnect + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "CannotConnect FromByteArray reports unread data when reporting is enabled")] + public void CannotConnect_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.CannotConnect) + .WriteInteger(1) // token + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => CannotConnect.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "CannotConnect FromByteArray does not report unread data when there is none")] + public void CannotConnect_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.CannotConnect) + .WriteInteger(1) // token + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => CannotConnect.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "CannotConnect FromByteArray does not report unread data when reporting is disabled")] + public void CannotConnect_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.CannotConnect) + .WriteInteger(1) // token + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => CannotConnect.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // CannotJoinRoomNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "CannotJoinRoomNotification FromByteArray reports unread data when reporting is enabled")] + public void CannotJoinRoomNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.CannotJoinRoom) + .WriteString("room") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => CannotJoinRoomNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "CannotJoinRoomNotification FromByteArray does not report unread data when there is none")] + public void CannotJoinRoomNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.CannotJoinRoom) + .WriteString("room") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => CannotJoinRoomNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "CannotJoinRoomNotification FromByteArray does not report unread data when reporting is disabled")] + public void CannotJoinRoomNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.CannotJoinRoom) + .WriteString("room") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => CannotJoinRoomNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // ConnectToPeerResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ConnectToPeerResponse FromByteArray reports unread data when reporting is enabled")] + public void ConnectToPeerResponse_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.ConnectToPeer) + .WriteString("username") + .WriteString("P") + .WriteBytes(new byte[] { 0x0, 0x0, 0x0, 0x0 }) // ip address + .WriteInteger(1) // port + .WriteInteger(1) // token + .WriteByte(0) // is privileged + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => ConnectToPeerResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ConnectToPeerResponse FromByteArray does not report unread data when there is none")] + public void ConnectToPeerResponse_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.ConnectToPeer) + .WriteString("username") + .WriteString("P") + .WriteBytes(new byte[] { 0x0, 0x0, 0x0, 0x0 }) // ip address + .WriteInteger(1) // port + .WriteInteger(1) // token + .WriteByte(0) // is privileged + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => ConnectToPeerResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ConnectToPeerResponse FromByteArray does not report unread data when reporting is disabled")] + public void ConnectToPeerResponse_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.ConnectToPeer) + .WriteString("username") + .WriteString("P") + .WriteBytes(new byte[] { 0x0, 0x0, 0x0, 0x0 }) // ip address + .WriteInteger(1) // port + .WriteInteger(1) // token + .WriteByte(0) // is privileged + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => ConnectToPeerResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // ExcludedSearchPhrases + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ExcludedSearchPhrases Parse reports unread data when reporting is enabled")] + public void ExcludedSearchPhrases_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.ExcludedSearchPhrases) + .WriteInteger(0) // phrase count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => ExcludedSearchPhrasesNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ExcludedSearchPhrases Parse does not report unread data when there is none")] + public void ExcludedSearchPhrases_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.ExcludedSearchPhrases) + .WriteInteger(0) // phrase count + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => ExcludedSearchPhrasesNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ExcludedSearchPhrases Parse does not report unread data when reporting is disabled")] + public void ExcludedSearchPhrases_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.ExcludedSearchPhrases) + .WriteInteger(0) // phrase count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => ExcludedSearchPhrasesNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // GlobalMessageNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "GlobalMessageNotification FromByteArray reports unread data when reporting is enabled")] + public void GlobalMessageNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GlobalAdminMessage) + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => GlobalMessageNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "GlobalMessageNotification FromByteArray does not report unread data when there is none")] + public void GlobalMessageNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GlobalAdminMessage) + .WriteString("message") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => GlobalMessageNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "GlobalMessageNotification FromByteArray does not report unread data when reporting is disabled")] + public void GlobalMessageNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GlobalAdminMessage) + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => GlobalMessageNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // IntegerResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "IntegerResponse Parse reports unread data when reporting is enabled")] + public void IntegerResponse_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetPeerAddress) + .WriteInteger(1) // value + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => IntegerResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "IntegerResponse Parse does not report unread data when there is none")] + public void IntegerResponse_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetPeerAddress) + .WriteInteger(1) // value + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => IntegerResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "IntegerResponse Parse does not report unread data when reporting is disabled")] + public void IntegerResponse_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetPeerAddress) + .WriteInteger(1) // value + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => IntegerResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // JoinRoomResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "JoinRoomResponse Parse reports unread data when reporting is enabled")] + public void JoinRoomResponse_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.JoinRoom) + .WriteString("room") + .WriteInteger(0) // user count + .WriteInteger(0) // status count + .WriteInteger(0) // data count + .WriteInteger(0) // slots free count + .WriteInteger(0) // country count + .WriteString("owner") + .WriteInteger(0) // operator count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => JoinRoomResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "JoinRoomResponse Parse does not report unread data when there is none")] + public void JoinRoomResponse_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.JoinRoom) + .WriteString("room") + .WriteInteger(0) // user count + .WriteInteger(0) // status count + .WriteInteger(0) // data count + .WriteInteger(0) // slots free count + .WriteInteger(0) // country count + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => JoinRoomResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "JoinRoomResponse Parse does not report unread data when reporting is disabled")] + public void JoinRoomResponse_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.JoinRoom) + .WriteString("room") + .WriteInteger(0) // user count + .WriteInteger(0) // status count + .WriteInteger(0) // data count + .WriteInteger(0) // slots free count + .WriteInteger(0) // country count + .WriteString("owner") + .WriteInteger(0) // operator count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => JoinRoomResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // LeaveRoomResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "LeaveRoomResponse FromByteArray reports unread data when reporting is enabled")] + public void LeaveRoomResponse_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.LeaveRoom) + .WriteString("room") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => LeaveRoomResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "LeaveRoomResponse FromByteArray does not report unread data when there is none")] + public void LeaveRoomResponse_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.LeaveRoom) + .WriteString("room") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => LeaveRoomResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "LeaveRoomResponse FromByteArray does not report unread data when reporting is disabled")] + public void LeaveRoomResponse_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.LeaveRoom) + .WriteString("room") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => LeaveRoomResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // LoginResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "LoginResponse Parse reports unread data when reporting is enabled")] + public void LoginResponse_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.Login) + .WriteByte(1) // succeeded + .WriteString("message") + .WriteBytes(new byte[] { 0x0, 0x0, 0x0, 0x0 }) // ip address + .WriteString("hash") + .WriteByte(0) // is supporter + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => LoginResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "LoginResponse Parse does not report unread data when there is none")] + public void LoginResponse_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.Login) + .WriteByte(1) // succeeded + .WriteString("message") + .WriteBytes(new byte[] { 0x0, 0x0, 0x0, 0x0 }) // ip address + .WriteString("hash") + .WriteByte(0) // is supporter + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => LoginResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "LoginResponse Parse does not report unread data when reporting is disabled")] + public void LoginResponse_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.Login) + .WriteByte(1) // succeeded + .WriteString("message") + .WriteBytes(new byte[] { 0x0, 0x0, 0x0, 0x0 }) // ip address + .WriteString("hash") + .WriteByte(0) // is supporter + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => LoginResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // NetInfo + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "NetInfo Parse reports unread data when reporting is enabled")] + public void NetInfo_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.NetInfo) + .WriteInteger(0) // parent count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => NetInfoNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "NetInfo Parse does not report unread data when there is none")] + public void NetInfo_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.NetInfo) + .WriteInteger(0) // parent count + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => NetInfoNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "NetInfo Parse does not report unread data when reporting is disabled")] + public void NetInfo_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.NetInfo) + .WriteInteger(0) // parent count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => NetInfoNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // NewPassword + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "NewPassword FromByteArray reports unread data when reporting is enabled")] + public void NewPassword_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.NewPassword) + .WriteString("password") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => NewPassword.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "NewPassword FromByteArray does not report unread data when there is none")] + public void NewPassword_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.NewPassword) + .WriteString("password") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => NewPassword.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "NewPassword FromByteArray does not report unread data when reporting is disabled")] + public void NewPassword_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.NewPassword) + .WriteString("password") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => NewPassword.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivateMessageNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateMessageNotification FromByteArray reports unread data when reporting is enabled")] + public void PrivateMessageNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateMessage) + .WriteInteger(1) // id + .WriteInteger(0) // timestamp + .WriteString("username") + .WriteString("message") + .WriteByte(1) // is replayed + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateMessageNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateMessageNotification FromByteArray does not report unread data when there is none")] + public void PrivateMessageNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateMessage) + .WriteInteger(1) // id + .WriteInteger(0) // timestamp + .WriteString("username") + .WriteString("message") + .WriteByte(1) // is replayed + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateMessageNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateMessageNotification FromByteArray does not report unread data when reporting is disabled")] + public void PrivateMessageNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateMessage) + .WriteInteger(1) // id + .WriteInteger(0) // timestamp + .WriteString("username") + .WriteString("message") + .WriteByte(1) // is replayed + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivateMessageNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivateRoomAddOperator + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomAddOperator FromByteArray reports unread data when reporting is enabled")] + public void PrivateRoomAddOperator_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomAddOperator) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomAddOperator.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomAddOperator FromByteArray does not report unread data when there is none")] + public void PrivateRoomAddOperator_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomAddOperator) + .WriteString("room") + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomAddOperator.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomAddOperator FromByteArray does not report unread data when reporting is disabled")] + public void PrivateRoomAddOperator_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomAddOperator) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivateRoomAddOperator.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivateRoomAddUser + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomAddUser FromByteArray reports unread data when reporting is enabled")] + public void PrivateRoomAddUser_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomAddUser) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomAddUser.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomAddUser FromByteArray does not report unread data when there is none")] + public void PrivateRoomAddUser_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomAddUser) + .WriteString("room") + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomAddUser.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomAddUser FromByteArray does not report unread data when reporting is disabled")] + public void PrivateRoomAddUser_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomAddUser) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivateRoomAddUser.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivateRoomOwnedListNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomOwnedListNotification FromByteArray reports unread data when reporting is enabled")] + public void PrivateRoomOwnedListNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomOwned) + .WriteString("room") + .WriteInteger(0) // user count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomOwnedListNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomOwnedListNotification FromByteArray does not report unread data when there is none")] + public void PrivateRoomOwnedListNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomOwned) + .WriteString("room") + .WriteInteger(0) // user count + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomOwnedListNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomOwnedListNotification FromByteArray does not report unread data when reporting is disabled")] + public void PrivateRoomOwnedListNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomOwned) + .WriteString("room") + .WriteInteger(0) // user count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivateRoomOwnedListNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivateRoomRemoveOperator + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomRemoveOperator FromByteArray reports unread data when reporting is enabled")] + public void PrivateRoomRemoveOperator_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomRemoveOperator) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomRemoveOperator.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomRemoveOperator FromByteArray does not report unread data when there is none")] + public void PrivateRoomRemoveOperator_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomRemoveOperator) + .WriteString("room") + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomRemoveOperator.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomRemoveOperator FromByteArray does not report unread data when reporting is disabled")] + public void PrivateRoomRemoveOperator_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomRemoveOperator) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivateRoomRemoveOperator.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivateRoomRemoveUser + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomRemoveUser FromByteArray reports unread data when reporting is enabled")] + public void PrivateRoomRemoveUser_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomRemoveUser) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomRemoveUser.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomRemoveUser FromByteArray does not report unread data when there is none")] + public void PrivateRoomRemoveUser_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomRemoveUser) + .WriteString("room") + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomRemoveUser.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomRemoveUser FromByteArray does not report unread data when reporting is disabled")] + public void PrivateRoomRemoveUser_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomRemoveUser) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivateRoomRemoveUser.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivateRoomToggle + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomToggle FromByteArray reports unread data when reporting is enabled")] + public void PrivateRoomToggle_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomToggle) + .WriteByte(1) // accept invitations + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomToggle.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomToggle FromByteArray does not report unread data when there is none")] + public void PrivateRoomToggle_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomToggle) + .WriteByte(1) // accept invitations + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomToggle.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomToggle FromByteArray does not report unread data when reporting is disabled")] + public void PrivateRoomToggle_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomToggle) + .WriteByte(1) // accept invitations + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivateRoomToggle.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivateRoomUserListNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomUserListNotification FromByteArray reports unread data when reporting is enabled")] + public void PrivateRoomUserListNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomUsers) + .WriteString("room") + .WriteInteger(0) // user count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomUserListNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomUserListNotification FromByteArray does not report unread data when there is none")] + public void PrivateRoomUserListNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomUsers) + .WriteString("room") + .WriteInteger(0) // user count + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivateRoomUserListNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivateRoomUserListNotification FromByteArray does not report unread data when reporting is disabled")] + public void PrivateRoomUserListNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivateRoomUsers) + .WriteString("room") + .WriteInteger(0) // user count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivateRoomUserListNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivilegeNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivilegeNotification FromByteArray reports unread data when reporting is enabled")] + public void PrivilegeNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.NotifyPrivileges) + .WriteInteger(1) // id + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivilegeNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivilegeNotification FromByteArray does not report unread data when there is none")] + public void PrivilegeNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.NotifyPrivileges) + .WriteInteger(1) // id + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivilegeNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivilegeNotification FromByteArray does not report unread data when reporting is disabled")] + public void PrivilegeNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.NotifyPrivileges) + .WriteInteger(1) // id + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivilegeNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivilegedUserList + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivilegedUserList Parse reports unread data when reporting is enabled")] + public void PrivilegedUserList_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivilegedUsers) + .WriteInteger(0) // user count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivilegedUserListNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivilegedUserList Parse does not report unread data when there is none")] + public void PrivilegedUserList_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivilegedUsers) + .WriteInteger(0) // user count + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivilegedUserListNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivilegedUserList Parse does not report unread data when reporting is disabled")] + public void PrivilegedUserList_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PrivilegedUsers) + .WriteInteger(0) // user count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivilegedUserListNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PrivilegedUserNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivilegedUserNotification FromByteArray reports unread data when reporting is enabled")] + public void PrivilegedUserNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.AddPrivilegedUser) + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivilegedUserNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivilegedUserNotification FromByteArray does not report unread data when there is none")] + public void PrivilegedUserNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.AddPrivilegedUser) + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PrivilegedUserNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PrivilegedUserNotification FromByteArray does not report unread data when reporting is disabled")] + public void PrivilegedUserNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.AddPrivilegedUser) + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PrivilegedUserNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // PublicChatMessageNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PublicChatMessageNotification FromByteArray reports unread data when reporting is enabled")] + public void PublicChatMessageNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PublicChat) + .WriteString("room") + .WriteString("username") + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PublicChatMessageNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PublicChatMessageNotification FromByteArray does not report unread data when there is none")] + public void PublicChatMessageNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PublicChat) + .WriteString("room") + .WriteString("username") + .WriteString("message") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => PublicChatMessageNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "PublicChatMessageNotification FromByteArray does not report unread data when reporting is disabled")] + public void PublicChatMessageNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.PublicChat) + .WriteString("room") + .WriteString("username") + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => PublicChatMessageNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // RoomJoinedNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomJoinedNotification Parse reports unread data when reporting is enabled")] + public void RoomJoinedNotification_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.UserJoinedRoom) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // status + .WriteInteger(0) // average speed + .WriteLong(0) // download count + .WriteInteger(0) // file count + .WriteInteger(0) // directory count + .WriteInteger(0) // slots free + .WriteString("US") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserJoinedRoomNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomJoinedNotification Parse does not report unread data when there is none")] + public void RoomJoinedNotification_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.UserJoinedRoom) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // status + .WriteInteger(0) // average speed + .WriteLong(0) // download count + .WriteInteger(0) // file count + .WriteInteger(0) // directory count + .WriteInteger(0) // slots free + .WriteString("US") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserJoinedRoomNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomJoinedNotification Parse does not report unread data when reporting is disabled")] + public void RoomJoinedNotification_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.UserJoinedRoom) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // status + .WriteInteger(0) // average speed + .WriteLong(0) // download count + .WriteInteger(0) // file count + .WriteInteger(0) // directory count + .WriteInteger(0) // slots free + .WriteString("US") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => UserJoinedRoomNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // RoomLeftNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomLeftNotification Parse reports unread data when reporting is enabled")] + public void RoomLeftNotification_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.UserLeftRoom) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserLeftRoomNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomLeftNotification Parse does not report unread data when there is none")] + public void RoomLeftNotification_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.UserLeftRoom) + .WriteString("room") + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserLeftRoomNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomLeftNotification Parse does not report unread data when reporting is disabled")] + public void RoomLeftNotification_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.UserLeftRoom) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => UserLeftRoomNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // RoomList + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomList Parse reports unread data when reporting is enabled")] + public void RoomList_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomList) + .WriteInteger(0) // public room count + .WriteInteger(0) // public room user count count + .WriteInteger(0) // owned room count + .WriteInteger(0) // owned room user count count + .WriteInteger(0) // private room count + .WriteInteger(0) // private room user count count + .WriteInteger(0) // moderated room count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomListResponseFactory.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomList Parse does not report unread data when there is none")] + public void RoomList_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomList) + .WriteInteger(0) // public room count + .WriteInteger(0) // public room user count count + .WriteInteger(0) // owned room count + .WriteInteger(0) // owned room user count count + .WriteInteger(0) // private room count + .WriteInteger(0) // private room user count count + .WriteInteger(0) // moderated room count + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomListResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomList Parse does not report unread data when reporting is disabled")] + public void RoomList_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomList) + .WriteInteger(0) // public room count + .WriteInteger(0) // public room user count count + .WriteInteger(0) // owned room count + .WriteInteger(0) // owned room user count count + .WriteInteger(0) // private room count + .WriteInteger(0) // private room user count count + .WriteInteger(0) // moderated room count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => RoomListResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // RoomMessageNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomMessageNotification FromByteArray reports unread data when reporting is enabled")] + public void RoomMessageNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.SayInChatRoom) + .WriteString("room") + .WriteString("username") + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomMessageNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomMessageNotification FromByteArray does not report unread data when there is none")] + public void RoomMessageNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.SayInChatRoom) + .WriteString("room") + .WriteString("username") + .WriteString("message") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomMessageNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomMessageNotification FromByteArray does not report unread data when reporting is disabled")] + public void RoomMessageNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.SayInChatRoom) + .WriteString("room") + .WriteString("username") + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => RoomMessageNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // RoomTickerAddedNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomTickerAddedNotification FromByteArray reports unread data when reporting is enabled")] + public void RoomTickerAddedNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomTickerAdd) + .WriteString("room") + .WriteString("username") + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomTickerAddedNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomTickerAddedNotification FromByteArray does not report unread data when there is none")] + public void RoomTickerAddedNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomTickerAdd) + .WriteString("room") + .WriteString("username") + .WriteString("message") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomTickerAddedNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomTickerAddedNotification FromByteArray does not report unread data when reporting is disabled")] + public void RoomTickerAddedNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomTickerAdd) + .WriteString("room") + .WriteString("username") + .WriteString("message") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => RoomTickerAddedNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // RoomTickerListNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomTickerListNotification FromByteArray reports unread data when reporting is enabled")] + public void RoomTickerListNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomTickers) + .WriteString("room") + .WriteInteger(0) // ticker count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomTickerListNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomTickerListNotification FromByteArray does not report unread data when there is none")] + public void RoomTickerListNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomTickers) + .WriteString("room") + .WriteInteger(0) // ticker count + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomTickerListNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomTickerListNotification FromByteArray does not report unread data when reporting is disabled")] + public void RoomTickerListNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomTickers) + .WriteString("room") + .WriteInteger(0) // ticker count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => RoomTickerListNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // RoomTickerRemovedNotification + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomTickerRemovedNotification FromByteArray reports unread data when reporting is enabled")] + public void RoomTickerRemovedNotification_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomTickerRemove) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomTickerRemovedNotification.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomTickerRemovedNotification FromByteArray does not report unread data when there is none")] + public void RoomTickerRemovedNotification_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomTickerRemove) + .WriteString("room") + .WriteString("username") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => RoomTickerRemovedNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "RoomTickerRemovedNotification FromByteArray does not report unread data when reporting is disabled")] + public void RoomTickerRemovedNotification_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.RoomTickerRemove) + .WriteString("room") + .WriteString("username") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => RoomTickerRemovedNotification.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // ServerPing + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ServerPing FromByteArray reports unread data when reporting is enabled")] + public void ServerPing_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.Ping) + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => ServerPing.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ServerPing FromByteArray does not report unread data when there is none")] + public void ServerPing_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.Ping) + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => ServerPing.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ServerPing FromByteArray does not report unread data when reporting is disabled")] + public void ServerPing_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.Ping) + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => ServerPing.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // ServerSearchRequest + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ServerSearchRequest FromByteArray reports unread data when reporting is enabled")] + public void ServerSearchRequest_FromByteArray_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.FileSearch) + .WriteString("username") + .WriteInteger(1) // token + .WriteString("query") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => ServerSearchRequest.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ServerSearchRequest FromByteArray does not report unread data when there is none")] + public void ServerSearchRequest_FromByteArray_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.FileSearch) + .WriteString("username") + .WriteInteger(1) // token + .WriteString("query") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => ServerSearchRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "ServerSearchRequest FromByteArray does not report unread data when reporting is disabled")] + public void ServerSearchRequest_FromByteArray_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.FileSearch) + .WriteString("username") + .WriteInteger(1) // token + .WriteString("query") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => ServerSearchRequest.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // StringResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "StringResponse Parse reports unread data when reporting is enabled")] + public void StringResponse_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetPeerAddress) + .WriteString("value") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => StringResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "StringResponse Parse does not report unread data when there is none")] + public void StringResponse_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetPeerAddress) + .WriteString("value") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => StringResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "StringResponse Parse does not report unread data when reporting is disabled")] + public void StringResponse_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetPeerAddress) + .WriteString("value") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => StringResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // UserAddressResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserAddressResponse Parse reports unread data when reporting is enabled")] + public void UserAddressResponse_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetPeerAddress) + .WriteString("username") + .WriteBytes(new byte[] { 0x0, 0x0, 0x0, 0x0 }) // ip address + .WriteInteger(1) // port + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserAddressResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserAddressResponse Parse does not report unread data when there is none")] + public void UserAddressResponse_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetPeerAddress) + .WriteString("username") + .WriteBytes(new byte[] { 0x0, 0x0, 0x0, 0x0 }) // ip address + .WriteInteger(1) // port + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserAddressResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserAddressResponse Parse does not report unread data when reporting is disabled")] + public void UserAddressResponse_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetPeerAddress) + .WriteString("username") + .WriteBytes(new byte[] { 0x0, 0x0, 0x0, 0x0 }) // ip address + .WriteInteger(1) // port + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => UserAddressResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // UserPrivilegeResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserPrivilegeResponse Parse reports unread data when reporting is enabled")] + public void UserPrivilegeResponse_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.UserPrivileges) + .WriteString("username") + .WriteByte(1) // privileged + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserPrivilegeResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserPrivilegeResponse Parse does not report unread data when there is none")] + public void UserPrivilegeResponse_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.UserPrivileges) + .WriteString("username") + .WriteByte(1) // privileged + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserPrivilegeResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserPrivilegeResponse Parse does not report unread data when reporting is disabled")] + public void UserPrivilegeResponse_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.UserPrivileges) + .WriteString("username") + .WriteByte(1) // privileged + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => UserPrivilegeResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // UserStatisticsResponseFactory + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserStatisticsResponseFactory Parse reports unread data when reporting is enabled")] + public void UserStatisticsResponseFactory_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetUserStats) + .WriteString("username") + .WriteInteger(0) // average speed + .WriteLong(0) // upload count + .WriteInteger(0) // file count + .WriteInteger(0) // directory count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserStatisticsResponseFactory.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserStatisticsResponseFactory Parse does not report unread data when there is none")] + public void UserStatisticsResponseFactory_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetUserStats) + .WriteString("username") + .WriteInteger(0) // average speed + .WriteLong(0) // upload count + .WriteInteger(0) // file count + .WriteInteger(0) // directory count + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserStatisticsResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserStatisticsResponseFactory Parse does not report unread data when reporting is disabled")] + public void UserStatisticsResponseFactory_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetUserStats) + .WriteString("username") + .WriteInteger(0) // average speed + .WriteLong(0) // upload count + .WriteInteger(0) // file count + .WriteInteger(0) // directory count + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => UserStatisticsResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // UserStatusResponseFactory + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserStatusResponseFactory Parse reports unread data when reporting is enabled")] + public void UserStatusResponseFactory_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetStatus) + .WriteString("username") + .WriteInteger(0) // presence + .WriteByte(0) // privileged + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserStatusResponseFactory.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserStatusResponseFactory Parse does not report unread data when there is none")] + public void UserStatusResponseFactory_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetStatus) + .WriteString("username") + .WriteInteger(0) // presence + .WriteByte(0) // privileged + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => UserStatusResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "UserStatusResponseFactory Parse does not report unread data when reporting is disabled")] + public void UserStatusResponseFactory_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.GetStatus) + .WriteString("username") + .WriteInteger(0) // presence + .WriteByte(0) // privileged + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => UserStatusResponseFactory.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + // WatchUserResponse + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "WatchUserResponse Parse reports unread data when reporting is enabled")] + public void WatchUserResponse_Parse_Reports_Unread_Data_When_Reporting_Is_Enabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.WatchUser) + .WriteString("username") + .WriteByte(1) // exists + .WriteInteger(0) // status + .WriteInteger(0) // average speed + .WriteLong(0) // download count + .WriteInteger(0) // file count + .WriteInteger(0) // directory count + .WriteString("US") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => WatchUserResponse.FromByteArray(msg)); + + Assert.Single(warnings); + Assert.Contains("unread bytes", warnings[0]); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "WatchUserResponse Parse does not report unread data when there is none")] + public void WatchUserResponse_Parse_Does_Not_Report_Unread_Data_When_There_Is_None() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.WatchUser) + .WriteString("username") + .WriteByte(1) // exists + .WriteInteger(0) // status + .WriteInteger(0) // average speed + .WriteLong(0) // download count + .WriteInteger(0) // file count + .WriteInteger(0) // directory count + .WriteString("US") + .Build(); + + var warnings = Capture(reportUnreadMessageData: true, () => WatchUserResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + [Trait("Category", "ReportUnreadMessageData")] + [Fact(DisplayName = "WatchUserResponse Parse does not report unread data when reporting is disabled")] + public void WatchUserResponse_Parse_Does_Not_Report_Unread_Data_When_Reporting_Is_Disabled() + { + var msg = new MessageBuilder() + .WriteCode(MessageCode.Server.WatchUser) + .WriteString("username") + .WriteByte(1) // exists + .WriteInteger(0) // status + .WriteInteger(0) // average speed + .WriteLong(0) // download count + .WriteInteger(0) // file count + .WriteInteger(0) // directory count + .WriteString("US") + .WriteInteger(0) // extra, unread data + .Build(); + + var warnings = Capture(reportUnreadMessageData: false, () => WatchUserResponse.FromByteArray(msg)); + + Assert.Empty(warnings); + } + + /// + /// Invokes the given action with + /// set to the given value, and returns the diagnostic warnings + /// raised while doing so. + /// + /// A value indicating whether unread message data should be reported. + /// The action which parses the message under test. + /// The messages of the diagnostic warnings raised by the given action. + private static List Capture(bool reportUnreadMessageData, Action parse) + { + var warnings = new List(); + + GlobalDiagnostic.Init(new DiagnosticFactory(minimumLevel: DiagnosticLevel.Warning, eventHandler: (e) => warnings.Add(e.Message))); + SoulseekClient.ReportUnreadMessageData = reportUnreadMessageData; + + try + { + parse(); + } + finally + { + SoulseekClient.ReportUnreadMessageData = false; + GlobalDiagnostic.Init(null); + } + + return warnings; + } + } + + /// + /// Serializes the tests which toggle and swap the + /// static diagnostic factory; both are global, so these tests can't run in parallel with anything else. + /// + [CollectionDefinition(UnreadMessageDataTests.CollectionName, DisableParallelization = true)] + public class UnreadMessageDataTestsCollection + { + } +}