Skip to content

Commit 5e75e2a

Browse files
committed
Added Channel Unit Tests
- Added xunit as a dependency for the new test project. - Added moq as a dependency for the new test project. - Added unit tests for the Channel class.
1 parent daf0c2d commit 5e75e2a

File tree

21 files changed

+19895
-0
lines changed

21 files changed

+19895
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading;
6+
7+
using Xunit;
8+
9+
using Moq;
10+
11+
using MyoSharp.Communication;
12+
using MyoSharp.Device;
13+
14+
namespace MyoSharp.Tests.Unit.Communication
15+
{
16+
public class ChannelTests
17+
{
18+
#region Constants
19+
private const string APPLICATION_IDENTIFIER = "com.myosharp.tests";
20+
#endregion
21+
22+
#region Methods
23+
[Fact]
24+
public void Create_NullChannelDriver_ThrowsNullArgumentException()
25+
{
26+
// Setup
27+
28+
// Execute
29+
Assert.ThrowsDelegate method = () => Channel.Create(null);
30+
31+
// Assert
32+
var exception = Assert.Throws<ArgumentNullException>(method);
33+
Assert.Equal("channelDriver", exception.ParamName);
34+
}
35+
36+
[Fact]
37+
public void Create_NullApplicationIdentifier_ThrowsNullArgumentException()
38+
{
39+
// Setup
40+
var driver = new Mock<IChannelDriver>();
41+
42+
// Execute
43+
Assert.ThrowsDelegate method = () => Channel.Create(driver.Object, null);
44+
45+
// Assert
46+
var exception = Assert.Throws<ArgumentNullException>(method);
47+
Assert.Equal("applicationIdentifier", exception.ParamName);
48+
49+
driver.Verify(x => x.InitializeMyoHub(It.IsAny<string>()), Times.Never);
50+
}
51+
52+
[Fact]
53+
public void Create_LongApplicationIdentifier_ThrowsArgumentException()
54+
{
55+
// Setup
56+
var driver = new Mock<IChannelDriver>();
57+
58+
// Execute
59+
Assert.ThrowsDelegate method = () => Channel.Create(driver.Object, new string('x', 256));
60+
61+
// Assert
62+
var exception = Assert.Throws<ArgumentException>(method);
63+
Assert.Equal("applicationIdentifier", exception.ParamName);
64+
65+
driver.Verify(x => x.InitializeMyoHub(It.IsAny<string>()), Times.Never);
66+
}
67+
68+
[Fact]
69+
public void Create_HubInitializationError_ThrowsInvalidOperationException()
70+
{
71+
// Setup
72+
var driver = new Mock<IChannelDriver>();
73+
driver
74+
.Setup(x => x.InitializeMyoHub(APPLICATION_IDENTIFIER))
75+
.Returns(IntPtr.Zero);
76+
77+
// Execute
78+
Assert.ThrowsDelegate method = () => Channel.Create(driver.Object, APPLICATION_IDENTIFIER);
79+
80+
// Assert
81+
Assert.Throws<InvalidOperationException>(method);
82+
83+
driver.Verify(x => x.InitializeMyoHub(APPLICATION_IDENTIFIER), Times.Once);
84+
}
85+
86+
[Fact]
87+
public void Create_ValidParameters_NewInstance()
88+
{
89+
// Setup
90+
var driver = new Mock<IChannelDriver>();
91+
var myoHandle = new IntPtr(12345);
92+
driver
93+
.Setup(x => x.InitializeMyoHub(APPLICATION_IDENTIFIER))
94+
.Returns(myoHandle);
95+
96+
// Execute
97+
var result = Channel.Create(driver.Object, APPLICATION_IDENTIFIER);
98+
99+
// Assert
100+
Assert.NotNull(result);
101+
102+
driver.Verify(x => x.InitializeMyoHub(APPLICATION_IDENTIFIER), Times.Once);
103+
}
104+
105+
[Fact]
106+
public void Dispose_CalledDirectly_ShutsDownMyoHub()
107+
{
108+
// Setup
109+
var driver = new Mock<IChannelDriver>();
110+
111+
var myoHandle = new IntPtr(12345);
112+
driver
113+
.Setup(x => x.InitializeMyoHub(APPLICATION_IDENTIFIER))
114+
.Returns(myoHandle);
115+
116+
var channel = Channel.Create(driver.Object, APPLICATION_IDENTIFIER);
117+
118+
// Execute
119+
channel.Dispose();
120+
121+
// Assert
122+
driver.Verify(x => x.InitializeMyoHub(APPLICATION_IDENTIFIER), Times.Once);
123+
driver.Verify(x => x.ShutdownMyoHub(myoHandle), Times.Once);
124+
}
125+
126+
[Fact]
127+
public void ListenerThread_HandleMyoEvent_TriggersEventReceivedEvent()
128+
{
129+
// Setup
130+
var driver = new Mock<IChannelDriver>();
131+
132+
var timestamp = DateTime.UtcNow;
133+
var eventHandle = new IntPtr(123);
134+
var myoHandle = new IntPtr(12345);
135+
driver
136+
.Setup(x => x.InitializeMyoHub(APPLICATION_IDENTIFIER))
137+
.Returns(myoHandle);
138+
driver
139+
.Setup(x => x.Run(myoHandle, It.IsAny<MyoRunHandler>(), It.IsAny<IntPtr>()))
140+
.Callback<IntPtr, MyoRunHandler, IntPtr>((handle, runHandler, userData) =>
141+
{
142+
runHandler(userData, eventHandle);
143+
});
144+
driver
145+
.Setup(x => x.GetEventType(eventHandle))
146+
.Returns(MyoEventType.Emg);
147+
driver
148+
.Setup(x => x.GetMyoForEvent(eventHandle))
149+
.Returns(myoHandle);
150+
driver
151+
.Setup(x => x.GetEventTimestamp(eventHandle))
152+
.Returns(timestamp);
153+
154+
var channel = Channel.Create(driver.Object, APPLICATION_IDENTIFIER);
155+
156+
var trigger = new ManualResetEventSlim();
157+
object actualSender = null;
158+
RouteMyoEventArgs actualEventArgs = null;
159+
channel.EventReceived += (sender, args) =>
160+
{
161+
actualSender = sender;
162+
actualEventArgs = args;
163+
trigger.Set();
164+
};
165+
166+
// Execute
167+
channel.StartListening();
168+
169+
// Assert
170+
try
171+
{
172+
Assert.True(
173+
trigger.Wait(5000),
174+
"The asycnhronous operation did not finish within a reasonable amount of time.");
175+
176+
Assert.Equal(channel, actualSender);
177+
Assert.NotNull(actualEventArgs);
178+
Assert.Equal(myoHandle, actualEventArgs.MyoHandle);
179+
Assert.Equal(eventHandle, actualEventArgs.Event);
180+
Assert.Equal(MyoEventType.Emg, actualEventArgs.EventType);
181+
Assert.Equal(timestamp, actualEventArgs.Timestamp);
182+
183+
driver.Verify(x => x.InitializeMyoHub(APPLICATION_IDENTIFIER), Times.Once);
184+
driver.Verify(x => x.Run(myoHandle, It.IsAny<MyoRunHandler>(), It.IsAny<IntPtr>()), Times.AtLeastOnce());
185+
driver.Verify(x => x.GetEventType(eventHandle), Times.AtLeastOnce());
186+
driver.Verify(x => x.GetMyoForEvent(eventHandle), Times.AtLeastOnce());
187+
driver.Verify(x => x.GetEventTimestamp(eventHandle), Times.AtLeastOnce());
188+
}
189+
finally
190+
{
191+
channel.Dispose();
192+
}
193+
}
194+
#endregion
195+
}
196+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{1BAD8167-FEB9-4088-9DDD-D1946C464489}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>MyoSharp.Tests.Unit</RootNamespace>
11+
<AssemblyName>MyoSharp.Tests.Unit</AssemblyName>
12+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
</PropertyGroup>
15+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16+
<DebugSymbols>true</DebugSymbols>
17+
<DebugType>full</DebugType>
18+
<Optimize>false</Optimize>
19+
<OutputPath>bin\Debug\</OutputPath>
20+
<DefineConstants>DEBUG;TRACE</DefineConstants>
21+
<ErrorReport>prompt</ErrorReport>
22+
<WarningLevel>4</WarningLevel>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25+
<DebugType>pdbonly</DebugType>
26+
<Optimize>true</Optimize>
27+
<OutputPath>bin\Release\</OutputPath>
28+
<DefineConstants>TRACE</DefineConstants>
29+
<ErrorReport>prompt</ErrorReport>
30+
<WarningLevel>4</WarningLevel>
31+
</PropertyGroup>
32+
<ItemGroup>
33+
<Reference Include="Moq">
34+
<HintPath>..\packages\Moq.4.2.1409.1722\lib\net40\Moq.dll</HintPath>
35+
</Reference>
36+
<Reference Include="System" />
37+
<Reference Include="System.Core" />
38+
<Reference Include="System.Xml.Linq" />
39+
<Reference Include="System.Data.DataSetExtensions" />
40+
<Reference Include="Microsoft.CSharp" />
41+
<Reference Include="System.Data" />
42+
<Reference Include="System.Xml" />
43+
<Reference Include="xunit">
44+
<HintPath>..\packages\xunit.1.9.2\lib\net20\xunit.dll</HintPath>
45+
</Reference>
46+
</ItemGroup>
47+
<ItemGroup>
48+
<Compile Include="Communication\ChannelTests.cs" />
49+
<Compile Include="Discovery\DeviceListenerTests.cs" />
50+
<Compile Include="Properties\AssemblyInfo.cs" />
51+
</ItemGroup>
52+
<ItemGroup>
53+
<None Include="packages.config" />
54+
</ItemGroup>
55+
<ItemGroup>
56+
<ProjectReference Include="..\MyoSharp\MyoSharp.csproj">
57+
<Project>{b075c7e9-fe48-4508-b44c-1a259bcc8b22}</Project>
58+
<Name>MyoSharp</Name>
59+
</ProjectReference>
60+
</ItemGroup>
61+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
62+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
63+
Other similar extension points exist, see Microsoft.Common.targets.
64+
<Target Name="BeforeBuild">
65+
</Target>
66+
<Target Name="AfterBuild">
67+
</Target>
68+
-->
69+
</Project>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("MyoSharp.Tests.Unit")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("Microsoft")]
12+
[assembly: AssemblyProduct("MyoSharp.Tests.Unit")]
13+
[assembly: AssemblyCopyright("Copyright © Microsoft 2014")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("4f9d0d0a-dcd3-41b9-9e96-26e631ba5655")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Build and Revision Numbers
33+
// by using the '*' as shown below:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]

MyoSharp.Tests.Unit/packages.config

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Moq" version="4.2.1409.1722" targetFramework="net45" />
4+
<package id="xunit" version="1.9.2" targetFramework="net45" />
5+
</packages>

MyoSharp.sln

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyoSharp", "MyoSharp\MyoSha
55
EndProject
66
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyoSharp.ConsoleSample", "MyoSharp.ConsoleSample\MyoSharp.ConsoleSample.csproj", "{27DA6BB8-8526-437E-9293-A877FC175653}"
77
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyoSharp.Tests.Unit", "MyoSharp.Tests.Unit\MyoSharp.Tests.Unit.csproj", "{1BAD8167-FEB9-4088-9DDD-D1946C464489}"
9+
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1012
Debug|Any CPU = Debug|Any CPU
@@ -29,6 +31,12 @@ Global
2931
{27DA6BB8-8526-437E-9293-A877FC175653}.Release|Any CPU.ActiveCfg = Release|Any CPU
3032
{27DA6BB8-8526-437E-9293-A877FC175653}.Release|Any CPU.Build.0 = Release|Any CPU
3133
{27DA6BB8-8526-437E-9293-A877FC175653}.Release|x86.ActiveCfg = Release|Any CPU
34+
{1BAD8167-FEB9-4088-9DDD-D1946C464489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35+
{1BAD8167-FEB9-4088-9DDD-D1946C464489}.Debug|Any CPU.Build.0 = Debug|Any CPU
36+
{1BAD8167-FEB9-4088-9DDD-D1946C464489}.Debug|x86.ActiveCfg = Debug|Any CPU
37+
{1BAD8167-FEB9-4088-9DDD-D1946C464489}.Release|Any CPU.ActiveCfg = Release|Any CPU
38+
{1BAD8167-FEB9-4088-9DDD-D1946C464489}.Release|Any CPU.Build.0 = Release|Any CPU
39+
{1BAD8167-FEB9-4088-9DDD-D1946C464489}.Release|x86.ActiveCfg = Release|Any CPU
3240
EndGlobalSection
3341
GlobalSection(SolutionProperties) = preSolution
3442
HideSolutionNode = FALSE

MyoSharp/Communication/Channel.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ private Channel(IChannelDriver channelDriver, string applicationIdentifier, bool
4646
throw new ArgumentNullException("channelDriver", "The channel driver cannot be null.");
4747
}
4848

49+
// TODO: replace with code contracts
50+
AssertApplicationIdentifier(applicationIdentifier);
51+
4952
_channelDriver = channelDriver;
5053

5154
_handle = channelDriver.InitializeMyoHub(applicationIdentifier);
@@ -126,6 +129,9 @@ public static IChannel Create(IChannelDriver channelDriver, string applicationId
126129
throw new ArgumentNullException("channelDriver", "The channel driver cannot be null.");
127130
}
128131

132+
// TODO: replace with code contracts
133+
// AssertApplicationIdentifier(applicationIdentifier);
134+
129135
return Create(channelDriver, applicationIdentifier, false);
130136
}
131137

@@ -158,6 +164,9 @@ public static IChannel Create(IChannelDriver channelDriver, string applicationId
158164
throw new ArgumentNullException("channelDriver", "The channel driver cannot be null.");
159165
}
160166

167+
// TODO: replace with code contracts
168+
// AssertApplicationIdentifier(applicationIdentifier);
169+
161170
return new Channel(channelDriver, applicationIdentifier, autostart);
162171
}
163172

@@ -202,6 +211,26 @@ public void Dispose()
202211
GC.SuppressFinalize(this);
203212
}
204213

214+
private static void AssertApplicationIdentifier(string applicationIdentifier)
215+
{
216+
if (applicationIdentifier == string.Empty)
217+
{
218+
return;
219+
}
220+
221+
if (applicationIdentifier == null)
222+
{
223+
throw new ArgumentNullException("applicationIdentifier", "The application identifier cannot be null.");
224+
}
225+
226+
if (applicationIdentifier.Length > 255)
227+
{
228+
throw new ArgumentException("The application identifier cannot be longer than 255 characters.", "applicationIdentifier");
229+
}
230+
231+
// TODO: add a regex for validating before the Myo has to deal with it
232+
}
233+
205234
/// <summary>
206235
/// Releases unmanaged and - optionally - managed resources.
207236
/// </summary>
Binary file not shown.
662 KB
Binary file not shown.

0 commit comments

Comments
 (0)