public async Task SearchInternalAsync_Adds_Search_To_ActiveSearches(string searchText, int token) { var options = new SearchOptions(searchTimeout: 1000, fileLimit: 1); using (var search = new SearchInternal(searchText, token, options) { State = SearchStates.InProgress, }) { var conn = new Mock <IMessageConnection>(); conn.Setup(m => m.WriteAsync(It.IsAny <byte[]>(), null)) .Returns(Task.CompletedTask); using (var cts = new CancellationTokenSource(1000)) using (var s = new SoulseekClient(serverConnection: conn.Object)) { s.SetProperty("State", SoulseekClientStates.Connected | SoulseekClientStates.LoggedIn); var task = s.SearchAsync(SearchQuery.FromText(searchText), SearchScope.Default, token, options, cts.Token); var active = s.GetProperty <ConcurrentDictionary <int, SearchInternal> >("Searches").ToList(); cts.Cancel(); await Record.ExceptionAsync(() => task); // swallow the cancellation exception Assert.Single(active); Assert.Contains(active, kvp => kvp.Key == token); } } }
public async Task SearchAsync_Fires_SearchStateChanged_Event(string searchText, int token) { var fired = false; var options = new SearchOptions(searchTimeout: 1000, fileLimit: 1); using (var search = new SearchInternal(searchText, token, options) { State = SearchStates.InProgress, }) { var conn = new Mock <IMessageConnection>(); conn.Setup(m => m.WriteAsync(It.IsAny <byte[]>(), null)) .Returns(Task.CompletedTask); using (var s = new SoulseekClient(serverConnection: conn.Object)) { s.SearchStateChanged += (sender, e) => fired = true; s.SetProperty("State", SoulseekClientStates.Connected | SoulseekClientStates.LoggedIn); var task = s.SearchAsync(SearchQuery.FromText(searchText), SearchScope.Default, token, options, null); await task; Assert.True(fired); } } }
public void Disconnect_Clears_Searches() { var c = new Mock <IMessageConnection>(); using (var s = new SoulseekClient(Guid.NewGuid().ToString(), new Random().Next(65535), serverConnection: c.Object)) { s.SetProperty("State", SoulseekClientStates.Connected); using (var search1 = new SearchInternal(string.Empty, 0, new SearchOptions())) using (var search2 = new SearchInternal(string.Empty, 1, new SearchOptions())) { var searches = new ConcurrentDictionary <int, SearchInternal>(); searches.TryAdd(0, search1); searches.TryAdd(1, search2); s.SetProperty("Searches", searches); var ex = Record.Exception(() => s.Disconnect()); Assert.Null(ex); Assert.Equal(SoulseekClientStates.Disconnected, s.State); Assert.Empty(searches); } } }
public async Task Disconnect_Cancels_Searches() { var c = new Mock <IMessageConnection>(); var p = new Mock <IPeerConnectionManager>(); using (var search = new SearchInternal("foo", 1)) { var searches = new ConcurrentDictionary <int, SearchInternal>(); searches.TryAdd(1, search); using (var s = new SoulseekClient(serverConnection: c.Object, peerConnectionManager: p.Object)) { s.SetProperty("State", SoulseekClientStates.Connected); s.SetProperty("Searches", searches); var searchWait = search.WaitForCompletion(CancellationToken.None); s.Disconnect(); var ex = await Record.ExceptionAsync(() => searchWait); Assert.NotNull(ex); Assert.IsType <OperationCanceledException>(ex); } } }
/// <summary> /// Initializes a new instance of the <see cref="Search"/> class. /// </summary> /// <param name="searchInternal">The internal instance from which to copy data.</param> internal Search(SearchInternal searchInternal) : this( searchInternal.SearchText, searchInternal.Token, searchInternal.State, searchInternal.ResponseCount, searchInternal.FileCount) { }
public void Disposes_Without_Throwing() { var s = new SearchInternal("foo", 42); var ex = Record.Exception(() => s.Dispose()); Assert.Null(ex); s.Dispose(); }
public void SearchEventArgs_Instantiates_With_Valid_Search(string searchText, int token, SearchOptions options) { using (var search = new SearchInternal(searchText, token, options)) { var s = new Search(search); var e = new SearchEventArgs(s); Assert.Equal(s, e.Search); } }
internal void Instantiates_With_Expected_Data_Given_SearchInternal(SearchInternal i) { var s = new Search(i); Assert.Equal(i.SearchText, s.SearchText); Assert.Equal(i.Token, s.Token); Assert.Equal(i.State, s.State); Assert.Equal(i.ResponseCount, s.ResponseCount); Assert.Equal(i.FileCount, s.FileCount); }
public void Complete_Sets_State() { var s = new SearchInternal("foo", 42); s.Complete(SearchStates.Cancelled); Assert.True(s.State.HasFlag(SearchStates.Completed)); Assert.True(s.State.HasFlag(SearchStates.Cancelled)); s.Dispose(); }
public void Response_Filter_Respects_MinimumResponseFileCount_Option(int actual, int option, bool expected) { var s = new SearchInternal("foo", 42, new SearchOptions(filterResponses: true, minimumResponseFileCount: option)); var response = new SearchResponseSlim("u", 1, actual, 1, 1, 1, null); var filter = s.InvokeMethod <bool>("SlimResponseMeetsOptionCriteria", response); Assert.Equal(expected, filter); s.Dispose(); }
public void Response_Filter_Returns_True_When_FilterResponses_Option_Is_False() { var s = new SearchInternal("foo", 42, new SearchOptions(filterResponses: false)); var response = new SearchResponseSlim("u", 1, 1, 1, 1, 1, null); var filter = s.InvokeMethod <bool>("SlimResponseMeetsOptionCriteria", response); Assert.True(filter); s.Dispose(); }
public void Instantiates_With_Expected_Data(string searchText, int token, SearchOptions options) { var s = new SearchInternal(searchText, token, options); Assert.Equal(searchText, s.SearchText); Assert.Equal(token, s.Token); Assert.Equal(options, s.Options); Assert.Equal(SearchStates.None, s.State); s.Dispose(); }
public async Task Cancel_Cancels() { using (var s = new SearchInternal("foo", 1)) { s.Cancel(); var ex = await Record.ExceptionAsync(() => s.WaitForCompletion(CancellationToken.None)); Assert.NotNull(ex); Assert.IsType <OperationCanceledException>(ex); } }
public void Response_Filter_Respects_MinimumResponseFileCount_Option(int actual, int option, bool expected) { var fixture = new Fixture(); var file = fixture.Create <File>(); var s = new SearchInternal("foo", 42, new SearchOptions(filterResponses: true, minimumResponseFileCount: option)); var response = new SearchResponse("u", 1, 1, 1, 1, DuplicateFile(file, actual)); var filter = s.InvokeMethod <bool>("ResponseMeetsOptionCriteria", response); Assert.Equal(expected, filter); s.Dispose(); }
public void SearchResponseReceivedEventArgs_Instantiates_With_Valid_Search_And_SearchResponse() { var searchText = Guid.NewGuid().ToString(); var token = new Random().Next(); using (var search = new SearchInternal(searchText, token, new SearchOptions())) { var response = new SearchResponse("foo", 1, 1, 1, 1, new List <File>()); var s = new Search(search); var e = new SearchResponseReceivedEventArgs(response, s); Assert.Equal(s, e.Search); Assert.Equal(response, e.Response); } }
public void TryAddResponse_Adds_Response(string username, int token, byte code, string filename, int size, string extension) { var s = new SearchInternal("foo", token, new SearchOptions(filterResponses: true, minimumResponseFileCount: 1)) { State = SearchStates.InProgress, }; var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.SearchResponse) .WriteString(username) .WriteInteger(token) // token .WriteInteger(1) // file count .WriteByte(code) // code .WriteString(filename) // filename .WriteLong(size) // size .WriteString(extension) // extension .WriteInteger(1) // attribute count .WriteInteger((int)FileAttributeType.BitDepth) // attribute[0].type .WriteInteger(4) // attribute[0].value .WriteByte(1) // free upload slots .WriteInteger(1) // upload speed .WriteLong(0) // queue length .WriteBytes(new byte[4]) // unknown 4 bytes .Build(); var reader = new MessageReader <MessageCode.Peer>(msg); reader.Seek(username.Length + 12); // seek to the start of the file list var responses = new List <SearchResponse>(); s.ResponseReceived = (r) => responses.Add(r); s.TryAddResponse(new SearchResponseSlim(username, token, 1, 1, 1, 1, reader)); Assert.Single(responses); var response = responses[0]; var files = response.Files.ToList(); Assert.Equal(1, response.FileCount); Assert.Equal(username, response.Username); Assert.Equal(filename, files[0].Filename); Assert.Equal(size, files[0].Size); s.Dispose(); }
public void TryAddResponse_Ignores_Response_When_Response_Criteria_Not_Met() { var s = new SearchInternal("foo", 42, new SearchOptions(filterResponses: true, minimumResponseFileCount: 1)) { State = SearchStates.InProgress, }; s.TryAddResponse(new SearchResponseSlim("bar", 42, 0, 1, 1, 1, null)); var invoked = false; s.ResponseReceived = (r) => invoked = true; Assert.False(invoked); s.Dispose(); }
public void TryAddResponse_Ignores_Response_When_Search_Is_Not_In_Progress() { var s = new SearchInternal("foo", 42) { State = SearchStates.Completed, }; s.TryAddResponse(new SearchResponseSlim("bar", 42, 1, 1, 1, 1, null)); var invoked = false; s.ResponseReceived = (r) => invoked = true; Assert.False(invoked); s.Dispose(); }
public async Task TryAddResponse_Completes_Search_And_Invokes_Completed_Event_When_Response_Limit_Reached(string username, int token, byte code, string filename, int size, string extension) { var options = new SearchOptions( filterResponses: false, minimumResponseFileCount: 1, responseLimit: 1, fileLimit: 10000000); var s = new SearchInternal("foo", token, options) { State = SearchStates.InProgress, }; var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.SearchResponse) .WriteString(username) .WriteInteger(token) // token .WriteInteger(1) // file count .WriteByte(code) // code .WriteString(filename) // filename .WriteLong(size) // size .WriteString(extension) // extension .WriteInteger(1) // attribute count .WriteInteger((int)FileAttributeType.BitDepth) // attribute[0].type .WriteInteger(4) // attribute[0].value .WriteByte(1) // free upload slots .WriteInteger(1) // upload speed .WriteLong(0) // queue length .WriteBytes(new byte[4]) // unknown 4 bytes .Build(); var reader = new MessageReader <MessageCode.Peer>(msg); reader.Seek(username.Length + 12); // seek to the start of the file lists var task = s.WaitForCompletion(CancellationToken.None); s.TryAddResponse(new SearchResponseSlim(username, token, 1, 1, 1, 1, reader)); await task; Assert.True(s.State.HasFlag(SearchStates.Completed)); Assert.True(s.State.HasFlag(SearchStates.ResponseLimitReached)); s.Dispose(); }
public void SearchStateChangedEventArgs_Instantiates_With_Valid_Search() { var searchText = Guid.NewGuid().ToString(); var token = new Random().Next(); using (var search = new SearchInternal(searchText, token, new SearchOptions())) { search.SetProperty("State", SearchStates.Completed); var s = new Search(search); var e = new SearchStateChangedEventArgs(SearchStates.None, s); Assert.Equal(s, e.Search); Assert.Equal(SearchStates.None, e.PreviousState); Assert.Equal(SearchStates.Completed, e.Search.State); } }
public void TryAddResponse_Ignores_Response_When_Token_Does_Not_Match() { var s = new SearchInternal("foo", 42) { State = SearchStates.InProgress, }; s.TryAddResponse(new SearchResponseSlim("bar", 24, 1, 1, 1, 1, null)); var invoked = false; s.ResponseReceived = (r) => invoked = true; Assert.False(invoked); s.Dispose(); }
public void TryAddResponse_Ignores_Response_When_All_Files_Are_Filtered_And_Response_Filtering_Is_Enabled(string username, int token, byte code, string filename, int size, string extension) { var options = new SearchOptions( filterResponses: true, minimumResponseFileCount: 1, fileFilter: (f) => false); var s = new SearchInternal("foo", token, options) { State = SearchStates.InProgress, }; var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.SearchResponse) .WriteString(username) .WriteInteger(token) // token .WriteInteger(1) // file count .WriteByte(code) // code .WriteString(filename) // filename .WriteLong(size) // size .WriteString(extension) // extension .WriteInteger(1) // attribute count .WriteInteger((int)FileAttributeType.BitDepth) // attribute[0].type .WriteInteger(4) // attribute[0].value .WriteByte(1) // free upload slots .WriteInteger(1) // upload speed .WriteLong(0) // queue length .WriteBytes(new byte[4]) // unknown 4 bytes .Build(); var reader = new MessageReader <MessageCode.Peer>(msg); reader.Seek(username.Length + 12); // seek to the start of the file list s.TryAddResponse(new SearchResponseSlim(username, token, 1, 1, 1, 1, reader)); var invoked = false; s.ResponseReceived = (r) => invoked = true; Assert.False(invoked); s.Dispose(); }
public void TryAddResponse_Ignores_Response_When_Custom_Response_Filter_Returns_False() { bool Filter(SearchResponse response) => false; var s = new SearchInternal("foo", 42, new SearchOptions(filterResponses: true, minimumResponseFileCount: 0, responseFilter: Filter)) { State = SearchStates.InProgress, }; s.TryAddResponse(new SearchResponse("bar", 42, 1, 1, 1, null)); var invoked = false; s.ResponseReceived = (r) => invoked = true; Assert.False(invoked); s.Dispose(); }
public async Task SearchAsync_Delegate_Throws_DuplicateTokenException_Given_A_Token_In_Use(string text, int token) { using (var search = new SearchInternal(text, token, new SearchOptions())) { var dict = new ConcurrentDictionary <int, SearchInternal>(); dict.TryAdd(token, search); using (var s = new SoulseekClient()) { s.SetProperty("State", SoulseekClientStates.Connected | SoulseekClientStates.LoggedIn); s.SetProperty("Searches", dict); var ex = await Record.ExceptionAsync(() => s.SearchAsync(SearchQuery.FromText(text), (r) => { }, token: token)); Assert.NotNull(ex); Assert.IsType <DuplicateTokenException>(ex); } } }
public async Task TryAddResponse_Completes_Search_And_Invokes_Completed_Event_When_File_Limit_Reached(string username, int token, File file) { var options = new SearchOptions( filterResponses: false, minimumResponseFileCount: 1, fileLimit: 1); var s = new SearchInternal("foo", token, options) { State = SearchStates.InProgress, }; var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.SearchResponse) .WriteString(username) .WriteInteger(token) // token .WriteInteger(1) // file count .WriteFile(file) .WriteByte(1) // free upload slots .WriteInteger(1) // upload speed .WriteLong(0) // queue length .WriteBytes(new byte[4]) // unknown 4 bytes .Build(); var reader = new MessageReader <MessageCode.Peer>(msg); reader.Seek(username.Length + 12); // seek to the start of the file lists var task = s.WaitForCompletion(CancellationToken.None); s.TryAddResponse(new SearchResponse(username, token, 1, 1, 1, new List <File>() { file })); await task; Assert.True(s.State.HasFlag(SearchStates.Completed)); Assert.True(s.State.HasFlag(SearchStates.FileLimitReached)); s.Dispose(); }
public void TryAddResponse_Ignores_Response_When_Custom_File_Filter_Removes_Locked_Files() { bool Filter(File file) => false; var s = new SearchInternal("foo", 42, new SearchOptions(filterResponses: true, minimumResponseFileCount: 1, fileFilter: Filter)) { State = SearchStates.InProgress, }; s.TryAddResponse(new SearchResponse("bar", 42, 1, 1, 1, null, lockedFileList: new List <File>() { new File(1, "a", 1, "b") })); var invoked = false; s.ResponseReceived = (r) => invoked = true; Assert.False(invoked); s.Dispose(); }
public void Appends_Active_Search_Response(string username, IPEndPoint endpoint, int token, byte freeUploadSlots, int uploadSpeed, int queueLength) { var(handler, mocks) = GetFixture(username, endpoint); var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.SearchResponse) .WriteString(username) .WriteInteger(token) .WriteInteger(1) // file count .WriteByte(0x2) // code .WriteString("filename") // filename .WriteLong(3) // size .WriteString("ext") // extension .WriteInteger(1) // attribute count .WriteInteger((int)FileAttributeType.BitDepth) // attribute[0].type .WriteInteger(4) // attribute[0].value .WriteByte(freeUploadSlots) .WriteInteger(uploadSpeed) .WriteLong(queueLength) .WriteBytes(new byte[4]) // unknown 4 bytes .Compress() .Build(); var responses = new List <SearchResponse>(); using (var search = new SearchInternal("foo", token) { State = SearchStates.InProgress, ResponseReceived = (r) => responses.Add(r), }) { mocks.Searches.TryAdd(token, search); handler.HandleMessageRead(mocks.PeerConnection.Object, msg); Assert.Single(responses); Assert.Contains(responses, r => r.Username == username && r.Token == token); } }
public void TryAddResponse_Swallows_Exceptions(string username, int token, File file) { var s = new SearchInternal("foo", token, new SearchOptions(filterResponses: true, minimumResponseFileCount: 1)) { State = SearchStates.InProgress, }; var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.SearchResponse) .WriteString(username) .WriteInteger(token) // token .WriteInteger(1) // file count .WriteFile(file) .WriteByte(1) // free upload slots .WriteInteger(1) // upload speed .WriteLong(0) // queue length .WriteBytes(new byte[4]) // unknown 4 bytes .Build(); var reader = new MessageReader <MessageCode.Peer>(msg); reader.Seek(username.Length + 12); // seek to the start of the file list var invoked = false; s.ResponseReceived += (r) => invoked = true; var ex = Record.Exception(() => s.TryAddResponse(new SearchResponse(username, token, 1, 1, 1, new List <File>() { file }))); Assert.Null(ex); Assert.True(invoked); s.Dispose(); }
public void TryAddResponse_Invokes_Response_Received_Event_Handler(string username, int token, File file) { SearchResponse addResponse = null; var s = new SearchInternal("foo", token, new SearchOptions(filterResponses: true, minimumResponseFileCount: 1)) { State = SearchStates.InProgress, }; s.ResponseReceived += (response) => addResponse = response; var msg = new MessageBuilder() .WriteCode(MessageCode.Peer.SearchResponse) .WriteString(username) .WriteInteger(token) // token .WriteInteger(1) // file count .WriteFile(file) .WriteByte(1) // free upload slots .WriteInteger(1) // upload speed .WriteLong(0) // queue length .WriteBytes(new byte[4]) // unknown 4 bytes .Build(); var reader = new MessageReader <MessageCode.Peer>(msg); reader.Seek(username.Length + 12); // seek to the start of the file list s.TryAddResponse(new SearchResponse(username, token, 1, 1, 1, new List <File>() { file })); Assert.NotNull(addResponse); Assert.Equal(file.Filename, addResponse.Files.ToList()[0].Filename); s.Dispose(); }