Moved all unit tests into a separate directory

This commit is contained in:
Markus Ewald 2024-07-24 18:38:59 +02:00 committed by cygon
parent 29c1e2a48d
commit 3081163258
11 changed files with 0 additions and 210 deletions

View file

@ -1,70 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
#if UNITTEST
using System;
using System.IO;
using System.Windows.Forms;
using NUnit.Framework;
using Nuclex.Support;
namespace Nuclex.Windows.Forms {
/// <summary>Unit Test for the asynchronously updating progress bar</summary>
[TestFixture, Explicit]
public class AsyncProgressBarTest {
/// <summary>
/// Verifies that asynchronous progress assignment is working
/// </summary>
[Test]
public void TestProgressAssignment() {
using(AsyncProgressBar progressBar = new AsyncProgressBar()) {
// Let the control create its window handle
progressBar.CreateControl();
progressBar.Minimum = 0;
progressBar.Maximum = 100;
Assert.AreEqual(0, progressBar.Value);
// Assign the new value. This will be done asynchronously, so we call
// Application.DoEvents() to execute the message pump once, guaranteeing
// that the call will have been executed after Application.DoEvents() returns.
progressBar.AsyncSetValue(0.33f);
Application.DoEvents();
Assert.AreEqual(33, progressBar.Value);
progressBar.AsyncSetValue(0.66f);
Application.DoEvents();
Assert.AreEqual(66, progressBar.Value);
}
}
}
} // namespace Nuclex.Windows.Forms
#endif // UNITTEST

View file

@ -1,82 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
#if UNITTEST
using System;
using System.IO;
using System.Windows.Forms;
using NUnit.Framework;
using Nuclex.Support;
namespace Nuclex.Windows.Forms {
/// <summary>Unit Test for the control container list view</summary>
[TestFixture, Explicit]
public class ContainerListViewTest {
/// <summary>
/// Verifies that the asynchronous progress bar's constructor is working
/// </summary>
[Test]
public void TestConstructor() {
using(ContainerListView listView = new ContainerListView()) {
// Let the control create its window handle
listView.CreateControl();
listView.Columns.Add("Numeric");
listView.Columns.Add("Spelled");
listView.Columns.Add("Nonsense");
addRow(listView, "1", "One");
addRow(listView, "2", "Two");
addRow(listView, "3", "Three");
using(CheckBox checkBox = new CheckBox()) {
listView.EmbeddedControls.Add(new ListViewEmbeddedControl(checkBox, 2, 0));
listView.EmbeddedControls.Clear();
listView.Refresh();
ListViewEmbeddedControl embeddedControl = new ListViewEmbeddedControl(
checkBox, 2, 0
);
listView.EmbeddedControls.Add(embeddedControl);
listView.EmbeddedControls.Remove(embeddedControl);
listView.Refresh();
}
}
}
/// <summary>Adds a row to a control container list view</summary>
/// <param name="listView">List view control the row will be added to</param>
/// <param name="columns">Values that will appear in the individual columns</param>
private void addRow(ContainerListView listView, params string[] columns) {
listView.Items.Add(new ListViewItem(columns));
}
}
} // namespace Nuclex.Windows.Forms
#endif // UNITTEST

View file

@ -1,48 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
using System;
using System.Windows.Forms;
using NUnit.Framework;
namespace Nuclex.Windows.Forms.Messages {
/// <summary>Unit tests for the message box event argument container</summary>
[TestFixture]
internal class MessageEventArgsTest {
/// <summary>Verifies that the image associated with the message gets stored</summary>
[Test]
public void ImageIsStored() {
var arguments = new MessageEventArgs(MessageBoxIcon.Exclamation, null);
Assert.AreEqual(MessageBoxIcon.Exclamation, arguments.Image);
}
/// <summary>Verifies that the text associated with the message gets stored</summary>
[Test]
public void TextIsStored() {
var text = new MessageText();
var arguments = new MessageEventArgs(MessageBoxIcon.None, text);
Assert.AreSame(text, arguments.Text);
}
}
} // namespace Nuclex.Windows.Forms.Messages

View file

@ -1,50 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
using System;
using System.Windows;
using NUnit.Framework;
namespace Nuclex.Windows.Forms.Messages {
/// <summary>Unit tests for the message text container</summary>
[TestFixture]
internal class MessageTextTest {
/// <summary>Ensures that the message text class provides a copy constructor</summary>
[Test]
public void HasCopyConstructor() {
var text = new MessageText() {
Caption = "Caption",
Message = "Message",
Details = "Details",
ExpandedDetails = "ExpandedDetails"
};
var copy = new MessageText(text);
Assert.AreEqual(text.Caption, copy.Caption);
Assert.AreEqual(text.Message, copy.Message);
Assert.AreEqual(text.Details, copy.Details);
Assert.AreEqual(text.ExpandedDetails, copy.ExpandedDetails);
}
}
} // namespace Nuclex.Windows.Forms.Messages

View file

@ -1,155 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
#if UNITTEST
using System;
using NUnit.Framework;
namespace Nuclex.Windows.Forms.ViewModels {
/// <summary>Unit test for the dialog view model</summary>
[TestFixture]
public class DialogViewModelTest {
#region class DialogViewModelSubscriber
/// <summary>Subscriber for the events offered by a dialog view model</summary>
private class DialogViewModelSubscriber {
/// <summary>Indicates that the user has accepted the dialog</summary>
public void Confirmed(object sender, EventArgs arguments) {
++this.confirmCallCount;
}
/// <summary>Indicates that the user has cancelled the dialog</summary>
public void Cancelled(object sender, EventArgs arguments) {
++this.cancelCallCount;
}
/// <summary>Indicates that the dialog was simply closed</summary>
public void Submitted(object sender, EventArgs arguments) {
++this.submitCallCount;
}
/// <summary>How many times the Confirmed() method was called</summary>
public int ConfirmCallCount {
get { return this.confirmCallCount; }
}
/// <summary>How many times the Cancelled() method was called</summary>
public int CancelCallCount {
get { return this.cancelCallCount; }
}
/// <summary>How many times the Submitted() method was called</summary>
public int SubmitCallCount {
get { return this.submitCallCount; }
}
/// <summary>How many times the Confirmed() method was called</summary>
private int confirmCallCount;
/// <summary>How many times the Cancelled() method was called</summary>
private int cancelCallCount;
/// <summary>How many times the Submitted() method was called</summary>
private int submitCallCount;
}
#endregion // class DialogViewModelSubscriber
/// <summary>Verifies that the dialog view model has a default constructor</summary>
[Test]
public void HasDefaultConstructor() {
Assert.DoesNotThrow(
delegate() { new DialogViewModel(); }
);
}
/// <summary>
/// Verifies that calling Confirm() on the dialog view model triggers
/// the 'Confirmed' event
/// </summary>
[Test]
public void ConfirmTriggersConfirmedEvent() {
var viewModel = new DialogViewModel();
var subscriber = createSubscriber(viewModel);
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
viewModel.Confirm();
Assert.AreEqual(1, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
}
/// <summary>
/// Verifies that calling Cancel() on the dialog view model triggers
/// the 'Cancelled' event
/// </summary>
[Test]
public void CancelTriggersCancelledEvent() {
var viewModel = new DialogViewModel();
var subscriber = createSubscriber(viewModel);
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
viewModel.Cancel();
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(1, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
}
/// <summary>
/// Verifies that calling Submitm() on the dialog view model triggers
/// the 'Submitted' event
/// </summary>
[Test]
public void SubmitTriggersSubmittedEvent() {
var viewModel = new DialogViewModel();
var subscriber = createSubscriber(viewModel);
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
viewModel.Submit();
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(1, subscriber.SubmitCallCount);
}
/// <summary>Constructs a new subscriber for the dialog view model's events</summary>
/// <param name="viewModel">View model a subscriber will be created for</param>
/// <returns>A subscriber for the events of the specified view model</returns>
private DialogViewModelSubscriber createSubscriber(DialogViewModel viewModel) {
var subscriber = new DialogViewModelSubscriber();
viewModel.Confirmed += subscriber.Confirmed;
viewModel.Canceled += subscriber.Cancelled;
viewModel.Submitted += subscriber.Submitted;
return subscriber;
}
}
} // namespace Nuclex.Windows.Forms.ViewModels
#endif // UNITTEST

View file

@ -1,270 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
#if UNITTEST
using System;
using System.ComponentModel;
using System.Threading;
using NUnit.Framework;
namespace Nuclex.Windows.Forms.ViewModels {
/// <summary>Unit test for the threaded action class</summary>
[TestFixture]
public class ThreadedActionTest {
#region class DummyContext
/// <summary>Synchronization context that does absolutely nothing</summary>
private class DummyContext : ISynchronizeInvoke {
#region class SimpleAsyncResult
/// <summary>Barebones implementation of an asynchronous result</summary>
private class SimpleAsyncResult : IAsyncResult {
/// <summary>Ehether the asynchronous operation is complete</summary>
/// <remarks>
/// Always true because it completes synchronously
/// </remarks>
public bool IsCompleted { get { return true; } }
/// <summary>
/// Wait handle that can be used to wait for the asynchronous operation
/// </summary>
public WaitHandle AsyncWaitHandle {
get { throw new NotImplementedException("Not implemented"); }
}
/// <summary>Custom state that can be used to pass information around</summary>
public object AsyncState {
get { throw new NotImplementedException("Not implemented"); }
}
/// <summary>Whether the asynchronous operation completed synchronously</summary>
public bool CompletedSynchronously { get { return true; } }
/// <summary>The value returned from the asynchronous operation</summary>
public object ReturnedValue;
}
#endregion // class SimpleAsyncResult
/// <summary>Whether the calling thread needs to use Invoke()</summary>
public bool InvokeRequired {
get { return true; }
}
/// <summary>Schedules the specified method for execution in the target thread</summary>
/// <param name="method">Method the target thread will execute when it is idle</param>
/// <param name="arguments">Arguments that will be passed to the method</param>
/// <returns>
/// An asynchronous result handle that can be used to check on the status of
/// the call and wait for its completion
/// </returns>
public IAsyncResult BeginInvoke(Delegate method, object[] arguments) {
var asyncResult = new SimpleAsyncResult();
asyncResult.ReturnedValue = method.Method.Invoke(method.Target, arguments);
return asyncResult;
}
/// <summary>Waits for the asychronous call to complete</summary>
/// <param name="result">
/// Asynchronous result handle returned by the <see cref="BeginInvoke" /> method
/// </param>
/// <returns>The original result returned by the asychronously called method</returns>
public object EndInvoke(IAsyncResult result) {
return ((SimpleAsyncResult)result).ReturnedValue;
}
/// <summary>
/// Schedules the specified method for execution in the target thread and waits
/// for it to complete
/// </summary>
/// <param name="method">Method that will be executed by the target thread</param>
/// <param name="arguments">Arguments that will be passed to the method</param>
/// <returns>The result returned by the specified method</returns>
public object Invoke(Delegate method, object[] arguments) {
return method.Method.Invoke(method.Target, arguments);
}
}
#endregion // class DummyContext
#region class DummyThreadedAction
/// <summary>Implementation of a threaded action for the unit test</summary>
private class DummyThreadedAction : ThreadedAction {
/// <summary>
/// Initializes a new threaded action, letting the base class figure out the UI thread
/// </summary>
public DummyThreadedAction() : base() {
this.finishedGate = new ManualResetEvent(initialState: false);
}
/// <summary>
/// Initializes a new view model using the specified UI context explicitly
/// </summary>
public DummyThreadedAction(ISynchronizeInvoke uiContext) : base(uiContext) {
this.finishedGate = new ManualResetEvent(initialState: false);
}
/// <summary>Immediately releases all resources owned by the instance</summary>
public override void Dispose() {
base.Dispose();
if(this.finishedGate != null) {
this.finishedGate.Dispose();
this.finishedGate = null;
}
}
/// <summary>Waits until the first background operation is finished</summary>
/// <returns>
/// True if the background operation is finished, false if it is ongoing
/// </returns>
public bool WaitUntilFinished() {
return this.finishedGate.WaitOne(100);
}
/// <summary>Selects the value that will be assigned when the action runs</summary>
/// <param name="valueToAssign">Value the action will assigned when it runs</param>
public void SetValueToAssign(int valueToAssign) {
this.valueToAssign = valueToAssign;
}
/// <summary>Sets up an error the action will fail with when run</summary>
/// <param name="errorToFailWith">Error the action will fail with</param>
public void SetErrorToFailWith(Exception errorToFailWith) {
this.errorToFailWith = errorToFailWith;
}
/// <summary>Last error that was reported by the threaded view model</summary>
public Exception ReportedError {
get { return this.reportedError; }
}
/// <summary>Value that has been assigned from the background thread</summary>
public int AssignedValue {
get { return this.assignedValue; }
}
/// <summary>Executes the threaded action from the background thread</summary>
/// <param name="cancellationToken">Token by which execution can be canceled</param>
protected override void Run(CancellationToken cancellationToken) {
if(this.errorToFailWith != null) {
throw this.errorToFailWith;
}
this.assignedValue = this.valueToAssign;
this.finishedGate.Set();
}
/// <summary>Called when an error occurs in the background thread</summary>
/// <param name="exception">Exception that was thrown in the background thread</param>
protected override void ReportError(Exception exception) {
this.reportedError = exception;
this.finishedGate.Set();
}
/// <summary>Error the action will fail with, if set</summary>
private Exception errorToFailWith;
/// <summary>Value the action will assign to its same-named field</summary>
private int valueToAssign;
/// <summary>Last error that was reported by the threaded view model</summary>
private volatile Exception reportedError;
/// <summary>Triggered when the </summary>
private ManualResetEvent finishedGate;
/// <summary>Value that is assigned through the background thread</summary>
private volatile int assignedValue;
}
#endregion // class DummyThreadedAction
/// <summary>Verifies that the threaded action has a default constructor</summary>
[Test, Explicit]
public void HasDefaultConstructor() {
using(var mainForm = new System.Windows.Forms.Form()) {
mainForm.Show();
try {
mainForm.Visible = false;
using(new DummyThreadedAction()) { }
}
finally {
mainForm.Close();
}
}
}
/// <summary>
/// Verifies that the threaded action can be constructed with a custom UI context
/// </summary>
[Test]
public void HasCustomSychronizationContextConstructor() {
using(new DummyThreadedAction(new DummyContext())) { }
}
/// <summary>Checks that a new threadd action starts out idle and not busy</summary>
[Test]
public void NewInstanceIsNotBusy() {
using(var action = new DummyThreadedAction(new DummyContext())) {
Assert.IsFalse(action.IsBusy);
}
}
/// <summary>
/// Verifies that errors happening in the background processing threads are
/// reported to the main thread
/// </summary>
[Test]
public void ErrorsInBackgroundThreadAreReported() {
using(var action = new DummyThreadedAction(new DummyContext())) {
var testError = new ArgumentException("Mooh");
action.SetErrorToFailWith(testError);
action.Start();
action.WaitUntilFinished();
Assert.AreSame(testError, action.ReportedError);
}
}
/// <summary>
/// Verifies that the background thread actually executes and can do work
/// </summary>
[Test]
public void BackgroundThreadExecutesTasks() {
using(var action = new DummyThreadedAction(new DummyContext())) {
action.SetValueToAssign(42001);
action.Start();
action.WaitUntilFinished();
Assert.AreEqual(42001, action.AssignedValue);
}
}
}
} // namespace Nuclex.Windows.Forms.ViewModels
#endif // UNITTEST

View file

@ -1,173 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
#if UNITTEST
using System;
using NUnit.Framework;
namespace Nuclex.Windows.Forms.ViewModels {
/// <summary>Unit test for the threaded dialog view model</summary>
[TestFixture]
public class ThreadedDialogViewModelTest {
#region class DialogViewModelSubscriber
/// <summary>Subscriber for the events offered by a dialog view model</summary>
private class DialogViewModelSubscriber {
/// <summary>Indicates that the user has accepted the dialog</summary>
public void Confirmed(object sender, EventArgs arguments) {
++this.confirmCallCount;
}
/// <summary>Indicates that the user has cancelled the dialog</summary>
public void Cancelled(object sender, EventArgs arguments) {
++this.cancelCallCount;
}
/// <summary>Indicates that the dialog was simply closed</summary>
public void Submitted(object sender, EventArgs arguments) {
++this.submitCallCount;
}
/// <summary>How many times the Confirmed() method was called</summary>
public int ConfirmCallCount {
get { return this.confirmCallCount; }
}
/// <summary>How many times the Cancelled() method was called</summary>
public int CancelCallCount {
get { return this.cancelCallCount; }
}
/// <summary>How many times the Submitted() method was called</summary>
public int SubmitCallCount {
get { return this.submitCallCount; }
}
/// <summary>How many times the Confirmed() method was called</summary>
private int confirmCallCount;
/// <summary>How many times the Cancelled() method was called</summary>
private int cancelCallCount;
/// <summary>How many times the Submitted() method was called</summary>
private int submitCallCount;
}
#endregion // class DialogViewModelSubscriber
#region class TestViewModel
private class TestViewModel : ThreadedDialogViewModel {
public Exception ReportedError {
get { return this.reportedError; }
}
protected override void ReportError(Exception exception) {
this.reportedError = exception;
}
private Exception reportedError;
}
#endregion // class TestViewModel
/// <summary>Verifies that the dialog view model has a default constructor</summary>
[Test]
public void HasDefaultConstructor() {
Assert.DoesNotThrow(
delegate() { new TestViewModel(); }
);
}
/// <summary>
/// Verifies that calling Confirm() on the dialog view model triggers
/// the 'Confirmed' event
/// </summary>
[Test]
public void ConfirmTriggersConfirmedEvent() {
var viewModel = new TestViewModel();
var subscriber = createSubscriber(viewModel);
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
viewModel.Confirm();
Assert.AreEqual(1, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
}
/// <summary>
/// Verifies that calling Cancel() on the dialog view model triggers
/// the 'Cancelled' event
/// </summary>
[Test]
public void CancelTriggersCancelledEvent() {
var viewModel = new TestViewModel();
var subscriber = createSubscriber(viewModel);
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
viewModel.Cancel();
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(1, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
}
/// <summary>
/// Verifies that calling Submitm() on the dialog view model triggers
/// the 'Submitted' event
/// </summary>
[Test]
public void SubmitTriggersSubmittedEvent() {
var viewModel = new TestViewModel();
var subscriber = createSubscriber(viewModel);
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(0, subscriber.SubmitCallCount);
viewModel.Submit();
Assert.AreEqual(0, subscriber.ConfirmCallCount);
Assert.AreEqual(0, subscriber.CancelCallCount);
Assert.AreEqual(1, subscriber.SubmitCallCount);
}
/// <summary>Constructs a new subscriber for the dialog view model's events</summary>
/// <param name="viewModel">View model a subscriber will be created for</param>
/// <returns>A subscriber for the events of the specified view model</returns>
private DialogViewModelSubscriber createSubscriber(ThreadedDialogViewModel viewModel) {
var subscriber = new DialogViewModelSubscriber();
viewModel.Confirmed += subscriber.Confirmed;
viewModel.Canceled += subscriber.Cancelled;
viewModel.Submitted += subscriber.Submitted;
return subscriber;
}
}
} // namespace Nuclex.Windows.Forms.ViewModels
#endif // UNITTEST

View file

@ -1,261 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
#if UNITTEST
using System;
using System.ComponentModel;
using System.Threading;
using NUnit.Framework;
namespace Nuclex.Windows.Forms.ViewModels {
/// <summary>Unit test for the threaded view model base class</summary>
[TestFixture]
public class ThreadedViewModelTest {
#region class DummyContext
/// <summary>Synchronization context that does absolutely nothing</summary>
private class DummyContext : ISynchronizeInvoke {
#region class SimpleAsyncResult
/// <summary>Barebones implementation of an asynchronous result</summary>
private class SimpleAsyncResult : IAsyncResult {
/// <summary>Ehether the asynchronous operation is complete</summary>
/// <remarks>
/// Always true because it completes synchronously
/// </remarks>
public bool IsCompleted { get { return true; } }
/// <summary>
/// Wait handle that can be used to wait for the asynchronous operation
/// </summary>
public WaitHandle AsyncWaitHandle {
get { throw new NotImplementedException("Not implemented"); }
}
/// <summary>Custom state that can be used to pass information around</summary>
public object AsyncState {
get { throw new NotImplementedException("Not implemented"); }
}
/// <summary>Whether the asynchronous operation completed synchronously</summary>
public bool CompletedSynchronously { get { return true; } }
/// <summary>The value returned from the asynchronous operation</summary>
public object ReturnedValue;
}
#endregion // class SimpleAsyncResult
/// <summary>Whether the calling thread needs to use Invoke()</summary>
public bool InvokeRequired {
get { return true; }
}
/// <summary>Schedules the specified method for execution in the target thread</summary>
/// <param name="method">Method the target thread will execute when it is idle</param>
/// <param name="arguments">Arguments that will be passed to the method</param>
/// <returns>
/// An asynchronous result handle that can be used to check on the status of
/// the call and wait for its completion
/// </returns>
public IAsyncResult BeginInvoke(Delegate method, object[] arguments) {
var asyncResult = new SimpleAsyncResult();
asyncResult.ReturnedValue = method.Method.Invoke(method.Target, arguments);
return asyncResult;
}
/// <summary>Waits for the asychronous call to complete</summary>
/// <param name="result">
/// Asynchronous result handle returned by the <see cref="BeginInvoke" /> method
/// </param>
/// <returns>The original result returned by the asychronously called method</returns>
public object EndInvoke(IAsyncResult result) {
return ((SimpleAsyncResult)result).ReturnedValue;
}
/// <summary>
/// Schedules the specified method for execution in the target thread and waits
/// for it to complete
/// </summary>
/// <param name="method">Method that will be executed by the target thread</param>
/// <param name="arguments">Arguments that will be passed to the method</param>
/// <returns>The result returned by the specified method</returns>
public object Invoke(Delegate method, object[] arguments) {
return method.Method.Invoke(method.Target, arguments);
}
}
#endregion // class DummyContext
#region class TestViewModel
/// <summary>View model used to unit test the threaded view model base class</summary>
private class TestViewModel : ThreadedViewModel {
/// <summary>
/// Initializes a new view model, letting the base class figure out the UI thread
/// </summary>
public TestViewModel() : base() {
this.finishedGate = new ManualResetEvent(initialState: false);
}
/// <summary>
/// Initializes a new view model, using the specified context for the UI thread
/// </summary>
/// <param name="uiContext">Synchronization context of the UI thread</param>
public TestViewModel(ISynchronizeInvoke uiContext) : base(uiContext) {
this.finishedGate = new ManualResetEvent(initialState: false);
}
/// <summary>Immediately releases all resources owned by the instance</summary>
public override void Dispose() {
base.Dispose();
if(this.finishedGate != null) {
this.finishedGate.Dispose();
this.finishedGate = null;
}
}
/// <summary>Waits until the first background operation is finished</summary>
/// <returns>
/// True if the background operation is finished, false if it is ongoing
/// </returns>
public bool WaitUntilFinished() {
return this.finishedGate.WaitOne(100);
}
/// <summary>Runs a background process that causes the specified error</summary>
/// <param name="error">Error that will be caused in the background process</param>
public void CauseErrorInBackgroundThread(Exception error) {
RunInBackground(
delegate() { throw error; }
);
}
/// <summary>
/// Assigns the specified value to the same-named property from a background thread
/// </summary>
/// <param name="value">Value that will be assigned to the same-named property</param>
public void AssignValueInBackgroundThread(int value) {
RunInBackground(
delegate () {
this.assignedValue = value;
this.finishedGate.Set();
}
);
}
/// <summary>Last error that was reported by the threaded view model</summary>
public Exception ReportedError {
get { return this.reportedError; }
}
/// <summary>Value that has been assigned from the background thread</summary>
public int AssignedValue {
get { return this.assignedValue; }
}
/// <summary>Called when an error occurs in the background thread</summary>
/// <param name="exception">Exception that was thrown in the background thread</param>
protected override void ReportError(Exception exception) {
this.reportedError = exception;
this.finishedGate.Set();
}
/// <summary>Last error that was reported by the threaded view model</summary>
private volatile Exception reportedError;
/// <summary>Triggered when the </summary>
private ManualResetEvent finishedGate;
/// <summary>Value that is assigned through the background thread</summary>
private volatile int assignedValue;
}
#endregion // class TestViewModel
/// <summary>Verifies that the threaded view model has a default constructor</summary>
[Test, Explicit]
public void HasDefaultConstructor() {
using(var mainForm = new System.Windows.Forms.Form()) {
mainForm.Show();
try {
mainForm.Visible = false;
using(new TestViewModel()) { }
}
finally {
mainForm.Close();
}
}
}
/// <summary>
/// Verifies that the threaded view model can be constructed with a custom UI context
/// </summary>
[Test]
public void HasCustomSychronizationContextConstructor() {
using(new TestViewModel(new DummyContext())) { }
}
/// <summary>Checks that a new view model starts out idle and not busy</summary>
[Test]
public void NewInstanceIsNotBusy() {
using(var viewModel = new TestViewModel(new DummyContext())) {
Assert.IsFalse(viewModel.IsBusy);
}
}
/// <summary>
/// Verifies that errors happening in the background processing threads are
/// reported to the main thread
/// </summary>
[Test]
public void ErrorsInBackgroundThreadAreReported() {
using(var viewModel = new TestViewModel(new DummyContext())) {
var testError = new ArgumentException("Mooh");
viewModel.CauseErrorInBackgroundThread(testError);
viewModel.WaitUntilFinished();
Assert.AreSame(testError, viewModel.ReportedError);
}
}
/// <summary>
/// Verifies that the background thread actually executes and can do work
/// </summary>
[Test]
public void BackgroundThreadExecutesTasks() {
using(var viewModel = new TestViewModel(new DummyContext())) {
viewModel.AssignValueInBackgroundThread(10042);
viewModel.WaitUntilFinished();
Assert.AreEqual(10042, viewModel.AssignedValue);
}
}
}
} // namespace Nuclex.Windows.Forms.ViewModels
#endif // UNITTEST

View file

@ -1,40 +0,0 @@
#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
using System;
using NUnit.Framework;
namespace Nuclex.Windows.Forms {
/// <summary>Unit test for the window manager</summary>
[TestFixture]
public class WindowManagerTest {
/// <summary>Verifies that the window manager provides a default constructor</summary>
[Test]
public void HasDefaultConstructor() {
Assert.DoesNotThrow(
() => new WindowManager()
);
}
}
} // namespace Nuclex.Windows.Forms