Skip to content

Commit bc20859

Browse files
committedFeb 19, 2021
Add some tests
1 parent 2b798ea commit bc20859

File tree

9 files changed

+531
-37
lines changed

9 files changed

+531
-37
lines changed
 

‎ThirdPartyNotices.txt

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
2+
-------------------------------------------------------------------
3+
4+
-------------------------------------------------------------------
5+
16
Newtonsoft.Json 9.0.1
27

38
Copyright (c) 2007 James Newton-King
@@ -20,4 +25,29 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2025
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2126
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2227
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29+
30+
-------------------------------------------------------------------
31+
32+
-------------------------------------------------------------------
33+
34+
Moq 4.16 - BSD-3-Clause
35+
36+
37+
(c) 2008 VeriSign, Inc.
38+
39+
Copyright (c) <year> <owner> . All rights reserved.
40+
41+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
42+
43+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
44+
45+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
46+
47+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
48+
49+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50+
51+
-------------------------------------------------------------------
52+
53+
-------------------------------------------------------------------

‎dotnet/DinoBot/DinoBot.sln

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1414
Settings.StyleCop = Settings.StyleCop
1515
EndProjectSection
1616
EndProject
17+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DinoTests", "DinoTests\DinoTests.csproj", "{20D97E53-3E9A-4E68-88E2-AD3A6DAF2FDA}"
18+
EndProject
1719
Global
1820
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1921
Debug|Any CPU = Debug|Any CPU
@@ -32,6 +34,10 @@ Global
3234
{1914515D-F3A7-4A5A-B1D3-891470021979}.Debug|Any CPU.Build.0 = Debug|Any CPU
3335
{1914515D-F3A7-4A5A-B1D3-891470021979}.Release|Any CPU.ActiveCfg = Release|Any CPU
3436
{1914515D-F3A7-4A5A-B1D3-891470021979}.Release|Any CPU.Build.0 = Release|Any CPU
37+
{20D97E53-3E9A-4E68-88E2-AD3A6DAF2FDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38+
{20D97E53-3E9A-4E68-88E2-AD3A6DAF2FDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
39+
{20D97E53-3E9A-4E68-88E2-AD3A6DAF2FDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
40+
{20D97E53-3E9A-4E68-88E2-AD3A6DAF2FDA}.Release|Any CPU.Build.0 = Release|Any CPU
3541
EndGlobalSection
3642
GlobalSection(SolutionProperties) = preSolution
3743
HideSolutionNode = FALSE

‎dotnet/DinoBot/DinoBot/DinoBot.cs

+49-35
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,23 @@ public class Dinobot
4040
private IBotPoster _botPoster;
4141
private TraceWriter _log;
4242
private string _botId;
43-
private MessageItem _message;
4443

45-
internal Dinobot(TraceWriter log, string botId, IBotPoster botPoster)
44+
/// <summary>
45+
/// Initializes a new instance of the <see cref="Dinobot"/> class
46+
/// </summary>
47+
/// <param name="botId">ID of the bot to use to post messages</param>
48+
/// <param name="botPoster">IBotPoster to use to post bot messages</param>
49+
public Dinobot(string botId, IBotPoster botPoster) : this(botId, botPoster, null)
50+
{
51+
}
52+
53+
/// <summary>
54+
/// Initializes a new instance of the <see cref="Dinobot"/> class
55+
/// </summary>
56+
/// <param name="botId">ID of the bot to use to post messages</param>
57+
/// <param name="botPoster">IBotPoster to use to post bot messages</param>
58+
/// <param name="log">Logger to use. Optional.</param>
59+
public Dinobot(string botId, IBotPoster botPoster, TraceWriter log)
4660
{
4761
if (botPoster == null)
4862
{
@@ -58,6 +72,11 @@ internal Dinobot(TraceWriter log, string botId, IBotPoster botPoster)
5872
_botPoster = botPoster;
5973
}
6074

75+
/// <summary>
76+
/// Gets or sets the message to parse
77+
/// </summary>
78+
public MessageItem Message { get; set; }
79+
6180
/// <summary>
6281
/// Message called when the Azure function is invoked
6382
///
@@ -86,7 +105,7 @@ public static async Task<HttpResponseMessage> Run([HttpTrigger(Route = "DinoCall
86105
}
87106

88107
var botPoster = new BotPoster(BotPostUrl);
89-
var bot = new Dinobot(log, botId, botPoster);
108+
var bot = new Dinobot(botId, botPoster, log);
90109
bool parsedMessage = await bot.ParseIncomingRequestAsync(req);
91110
if (parsedMessage)
92111
{
@@ -106,39 +125,39 @@ public static async Task<HttpResponseMessage> Run([HttpTrigger(Route = "DinoCall
106125
/// </summary>
107126
/// <param name="request">Incoming request</param>
108127
/// <returns>True if a message was properly parsed from the request</returns>
109-
internal async Task<bool> ParseIncomingRequestAsync(HttpRequestMessage request)
128+
public async Task<bool> ParseIncomingRequestAsync(HttpRequestMessage request)
110129
{
111130
if (request == null)
112131
{
113132
return false;
114133
}
115134

116135
string content = await request.Content.ReadAsStringAsync();
117-
_message = JsonSerializer.DeserializeJson<MessageItem>(content);
118-
return _message?.Text != null;
136+
Message = JsonSerializer.DeserializeJson<MessageItem>(content);
137+
return Message?.Text != null;
119138
}
120139

121140
/// <summary>
122141
/// Processes a message and sends dinos if necessary
123142
/// </summary>
124143
/// <returns>True if a bot message was sent, false if message was processed with no action</returns>
125-
internal async Task<bool> ProcessMessageAsync()
144+
public async Task<bool> ProcessMessageAsync()
126145
{
127-
if (_message == null)
146+
if (Message == null)
128147
{
129148
return false;
130149
}
131150

132-
_log?.Info("Parsed message for " + _message.GroupId);
133-
if (string.IsNullOrEmpty(_message.GroupId))
151+
_log?.Info("Parsed message for " + Message.GroupId);
152+
if (string.IsNullOrEmpty(Message.GroupId))
134153
{
135154
_log?.Info("Not a group message, ignoring");
136155
return false;
137156
}
138157
else
139158
{
140159
UpdateEnvironmentVariables();
141-
return await HandleIncomingMessageAsync(_log, _message, _botId);
160+
return await HandleIncomingMessageAsync(Message, _botId);
142161
}
143162
}
144163

@@ -177,38 +196,37 @@ private void UpdateEnvironmentVariableForContainer(string key, ICollection<strin
177196
/// <summary>
178197
/// Handles an incoming message and sends a bot message if appropriate
179198
/// </summary>
180-
/// <param name="log">Logger for the operation</param>
181199
/// <param name="message">Message to process</param>
182200
/// <param name="botId">ID of the bot to use to send messages</param>
183201
/// <returns>True if a bot message was sent</returns>
184-
private async Task<bool> HandleIncomingMessageAsync(TraceWriter log, MessageItem message, string botId)
202+
private async Task<bool> HandleIncomingMessageAsync(MessageItem message, string botId)
185203
{
186204
// Checks for the type of messages Dinobot will respond to, in decreasing priority order
187205
// TODO: It would be cool if these were some sort of class-based trigger system you added to a collection rather than this if/else block
188206
string text = message.Text?.ToLower();
189-
if (await CheckDinoRequest(log, text, message, botId))
207+
if (await CheckDinoRequest(text, message, botId))
190208
{
191-
log?.Info("Posted Dino");
209+
_log?.Info("Posted Dino");
192210
return true;
193211
}
194-
else if (await CheckDinoAddressed(log, text, message, botId))
212+
else if (await CheckDinoAddressed(text, message, botId))
195213
{
196-
log?.Info("Dino responded");
214+
_log?.Info("Dino responded");
197215
return true;
198216
}
199-
else if (await CheckRandy(log, text, botId))
217+
else if (await CheckRandy(text, botId))
200218
{
201-
log?.Info("Posted Randy");
219+
_log?.Info("Posted Randy");
202220
return true;
203221
}
204-
else if (await CheckDinoQuestion(log, text, message, botId))
222+
else if (await CheckDinoQuestion(text, message, botId))
205223
{
206-
log?.Info("Posted DinoQ");
224+
_log?.Info("Posted DinoQ");
207225
return true;
208226
}
209227
else
210228
{
211-
log?.Info("No dino message");
229+
_log?.Info("No dino message");
212230
}
213231

214232
return false;
@@ -219,20 +237,19 @@ private async Task<bool> HandleIncomingMessageAsync(TraceWriter log, MessageItem
219237
///
220238
/// For example, a message contains the text "3 dinos" will result in 3 dino emojis sent by the bot.
221239
/// </summary>
222-
/// <param name="log">Logger for the operation</param>
223240
/// <param name="messageText">Pre-processed text for the message</param>
224241
/// <param name="message">Message being processed</param>
225242
/// <param name="botId">ID of the bot to send the message</param>
226243
/// <returns>True if a message was sent by the bot, otherwise false</returns>
227-
private async Task<bool> CheckDinoRequest(TraceWriter log, string messageText, MessageItem message, string botId)
244+
private async Task<bool> CheckDinoRequest(string messageText, MessageItem message, string botId)
228245
{
229246
Match match = DinoRegex.Match(messageText);
230247
if (match.Success && match.Groups.Count == 4)
231248
{
232-
log?.Info("Found dino");
249+
_log?.Info("Found dino");
233250
string num = match.Groups[2].Value;
234251
int dinos = Math.Min(int.Parse(num), MaxDinos);
235-
log?.Info("Dinos:" + dinos.ToString());
252+
_log?.Info("Dinos:" + dinos.ToString());
236253

237254
if (dinos > 0)
238255
{
@@ -250,16 +267,15 @@ private async Task<bool> CheckDinoRequest(TraceWriter log, string messageText, M
250267
/// For example, a message containing the test "Hey DinoBot" will result in a dinosaur emoji being sent.
251268
/// The trigger text and users who can use this trigger are configurable via AppSettings
252269
/// </summary>
253-
/// <param name="log">Logger for the operation</param>
254270
/// <param name="messageText">Pre-processed text for the message</param>
255271
/// <param name="message">Message being processed</param>
256272
/// <param name="botId">ID of the bot to send the message</param>
257273
/// <returns>True if a message was sent by the bot, otherwise false</returns>
258-
private async Task<bool> CheckDinoAddressed(TraceWriter log, string messageText, MessageItem message, string botId)
274+
private async Task<bool> CheckDinoAddressed(string messageText, MessageItem message, string botId)
259275
{
260276
if ((_canAddressDino.Count == 0 || _canAddressDino.Contains(message.UserId)) && _dinoAddressTrigger.Any(t => messageText.Contains(t)))
261277
{
262-
log?.Info("Dino addressed");
278+
_log?.Info("Dino addressed");
263279
Attachment existingReply = message.GetExistingReply();
264280
HttpStatusCode response = await _botPoster.PostEmojiAsync(DinoPack, DinoEmoji, 1, botId, EmojiPostDelayMs, existingReply?.ReplyId ?? null, existingReply?.BaseReplyId ?? null);
265281
return response == HttpStatusCode.Accepted;
@@ -270,18 +286,17 @@ private async Task<bool> CheckDinoAddressed(TraceWriter log, string messageText,
270286
/// <summary>
271287
/// Checks if the user requests the Randy emoji
272288
/// </summary>
273-
/// <param name="log">Logger for the operation</param>
274289
/// <param name="messageText">Pre-processed text for the message</param>
275290
/// <param name="botId">ID of the bot to send the message</param>
276291
/// <returns>True if a message was sent by the bot, otherwise false</returns>
277-
private async Task<bool> CheckRandy(TraceWriter log, string messageText, string botId)
292+
private async Task<bool> CheckRandy(string messageText, string botId)
278293
{
279294
if (messageText.Contains("(randy pooping)"))
280295
{
281296
HttpStatusCode response = await _botPoster.PostEmojiAsync(RandyPack, RandyEmoji, 1, botId, EmojiPostDelayMs);
282297
if (response == HttpStatusCode.Accepted)
283298
{
284-
log?.Info("Posted Randy:" + response.ToString());
299+
_log?.Info("Posted Randy:" + response.ToString());
285300
return true;
286301
}
287302
}
@@ -291,20 +306,19 @@ private async Task<bool> CheckRandy(TraceWriter log, string messageText, string
291306
/// <summary>
292307
/// Checks if the user asked a question and uses the most sophisticated AI to determine if Dinobot should respond
293308
/// </summary>
294-
/// <param name="log">Logger for the operation</param>
295309
/// <param name="messageText">Pre-processed text for the message</param>
296310
/// <param name="message">The message being processed</param>
297311
/// <param name="botId">ID of the bot to send the message</param>
298312
/// <returns>True if a message was sent by the bot, otherwise false</returns>
299-
private async Task<bool> CheckDinoQuestion(TraceWriter log, string messageText, MessageItem message, string botId)
313+
private async Task<bool> CheckDinoQuestion(string messageText, MessageItem message, string botId)
300314
{
301315
if (messageText.Contains("?"))
302316
{
303317
Random rand = new Random();
304318
double val = rand.NextDouble();
305319
if (val <= ResponseWeight)
306320
{
307-
log?.Info("Posting response");
321+
_log?.Info("Posting response");
308322
Attachment existingReply = message.GetExistingReply();
309323
HttpStatusCode response = await _botPoster.PostEmojiAsync(DinoPack, DinoEmoji, 1, botId, EmojiPostDelayMs, message.MessageId, existingReply?.BaseReplyId ?? null);
310324
return response == HttpStatusCode.Accepted;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using GroupMeShared.Model;
5+
using Microsoft.VisualStudio.TestTools.UnitTesting;
6+
7+
namespace DinoTests
8+
{
9+
/// <summary>
10+
/// Tests message attachments
11+
/// </summary>
12+
[TestClass]
13+
public class AttachmentTests
14+
{
15+
[TestMethod]
16+
public void TestAttachmentHasReply()
17+
{
18+
var message = new MessageItem
19+
{
20+
Attachments = new Attachment[] {
21+
new Attachment
22+
{
23+
Type = Attachment.ImageType
24+
},
25+
new Attachment
26+
{
27+
Type = Attachment.ReplyType
28+
},
29+
new Attachment
30+
{
31+
Type = Attachment.Emoji
32+
}
33+
}
34+
};
35+
36+
Attachment reply = message.GetExistingReply();
37+
Assert.IsNotNull(reply);
38+
Assert.AreEqual(Attachment.ReplyType, reply.Type);
39+
}
40+
41+
[TestMethod]
42+
public void TestAttachmentNoReply()
43+
{
44+
var message = new MessageItem
45+
{
46+
Attachments = new Attachment[] {
47+
new Attachment
48+
{
49+
Type = Attachment.ImageType
50+
},
51+
new Attachment
52+
{
53+
Type = Attachment.Emoji
54+
}
55+
}
56+
};
57+
58+
Attachment reply = message.GetExistingReply();
59+
Assert.IsNull(reply);
60+
}
61+
62+
[TestMethod]
63+
public void TestAttachmentNoReplies()
64+
{
65+
var message = new MessageItem();
66+
67+
Attachment reply = message.GetExistingReply();
68+
Assert.IsNull(reply);
69+
}
70+
}
71+
}
+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props')" />
4+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
5+
<PropertyGroup>
6+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
7+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
8+
<ProjectGuid>{20D97E53-3E9A-4E68-88E2-AD3A6DAF2FDA}</ProjectGuid>
9+
<OutputType>Library</OutputType>
10+
<AppDesignerFolder>Properties</AppDesignerFolder>
11+
<RootNamespace>DinoTests</RootNamespace>
12+
<AssemblyName>DinoTests</AssemblyName>
13+
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
14+
<FileAlignment>512</FileAlignment>
15+
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
16+
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
17+
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
18+
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
19+
<IsCodedUITest>False</IsCodedUITest>
20+
<TestProjectType>UnitTest</TestProjectType>
21+
<NuGetPackageImportStamp>
22+
</NuGetPackageImportStamp>
23+
</PropertyGroup>
24+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
25+
<DebugSymbols>true</DebugSymbols>
26+
<DebugType>full</DebugType>
27+
<Optimize>false</Optimize>
28+
<OutputPath>bin\Debug\</OutputPath>
29+
<DefineConstants>DEBUG;TRACE</DefineConstants>
30+
<ErrorReport>prompt</ErrorReport>
31+
<WarningLevel>4</WarningLevel>
32+
</PropertyGroup>
33+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
34+
<DebugType>pdbonly</DebugType>
35+
<Optimize>true</Optimize>
36+
<OutputPath>bin\Release\</OutputPath>
37+
<DefineConstants>TRACE</DefineConstants>
38+
<ErrorReport>prompt</ErrorReport>
39+
<WarningLevel>4</WarningLevel>
40+
</PropertyGroup>
41+
<ItemGroup>
42+
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
43+
<HintPath>..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll</HintPath>
44+
</Reference>
45+
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
46+
<HintPath>..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
47+
</Reference>
48+
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
49+
<HintPath>..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
50+
</Reference>
51+
<Reference Include="Moq, Version=4.16.0.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
52+
<HintPath>..\packages\Moq.4.16.0\lib\net45\Moq.dll</HintPath>
53+
</Reference>
54+
<Reference Include="System" />
55+
<Reference Include="System.Configuration" />
56+
<Reference Include="System.Core" />
57+
<Reference Include="System.Net.Http" />
58+
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
59+
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
60+
</Reference>
61+
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
62+
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
63+
</Reference>
64+
</ItemGroup>
65+
<ItemGroup>
66+
<Compile Include="AttachmentTests.cs" />
67+
<Compile Include="DinobotTests.cs" />
68+
<Compile Include="Properties\AssemblyInfo.cs" />
69+
</ItemGroup>
70+
<ItemGroup>
71+
<None Include="packages.config" />
72+
</ItemGroup>
73+
<ItemGroup>
74+
<ProjectReference Include="..\DinoBot\DinoBot.csproj">
75+
<Project>{78C1A8E2-9C41-4DD9-A272-6D75A7968704}</Project>
76+
<Name>DinoBot</Name>
77+
</ProjectReference>
78+
<ProjectReference Include="..\GroupMeBots\GroupMeBots.csproj">
79+
<Project>{1914515D-F3A7-4A5A-B1D3-891470021979}</Project>
80+
<Name>GroupMeBots</Name>
81+
</ProjectReference>
82+
<ProjectReference Include="..\GroupMeShared\GroupMeShared.csproj">
83+
<Project>{6AEE518E-62E1-4AA2-A7A4-9308966115F9}</Project>
84+
<Name>GroupMeShared</Name>
85+
</ProjectReference>
86+
</ItemGroup>
87+
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
88+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
89+
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
90+
<PropertyGroup>
91+
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
92+
</PropertyGroup>
93+
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props'))" />
94+
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets'))" />
95+
</Target>
96+
<Import Project="..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets')" />
97+
</Project>
+246
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Net.Http;
6+
using System.Threading.Tasks;
7+
using DinoBot;
8+
using GroupMeBots.Service;
9+
using GroupMeShared.Model;
10+
using Microsoft.VisualStudio.TestTools.UnitTesting;
11+
using Moq;
12+
13+
namespace DinoTests
14+
{
15+
[TestClass]
16+
public class DinobotTests
17+
{
18+
private const string TestBotId = "123";
19+
private const string TestMessageWithDinos =
20+
"{" +
21+
" 'group_id': '1', " +
22+
" 'text': '3 dinos' " +
23+
"}";
24+
25+
26+
[TestMethod]
27+
[ExpectedException(typeof(ArgumentNullException))]
28+
public void TestMissingBotId()
29+
{
30+
var botPoster = new Mock<IBotPoster>().Object;
31+
var bot = new Dinobot(null, botPoster);
32+
}
33+
34+
[TestMethod]
35+
[ExpectedException(typeof(ArgumentNullException))]
36+
public void TestMissingBotPoster()
37+
{
38+
var bot = new Dinobot(TestBotId, null);
39+
}
40+
41+
[TestMethod]
42+
public async Task TestParsingNoMessage()
43+
{
44+
var botPoster = new Mock<IBotPoster>().Object;
45+
var bot = new Dinobot(TestBotId, botPoster);
46+
47+
bool parsed = await bot.ParseIncomingRequestAsync(null);
48+
Assert.IsFalse(parsed);
49+
Assert.IsNull(bot.Message);
50+
}
51+
52+
[TestMethod]
53+
public async Task TestParsingMessage()
54+
{
55+
var botPoster = new Mock<IBotPoster>().Object;
56+
var bot = new Dinobot(TestBotId, botPoster);
57+
58+
var message = new HttpRequestMessage
59+
{
60+
Content = new StringContent(TestMessageWithDinos)
61+
};
62+
63+
bool parsed = await bot.ParseIncomingRequestAsync(message);
64+
Assert.IsTrue(parsed);
65+
Assert.IsNotNull(bot.Message);
66+
Assert.AreEqual("1", bot.Message.GroupId);
67+
Assert.AreEqual("3 dinos", bot.Message.Text);
68+
}
69+
70+
[TestMethod]
71+
public async Task TestMessageNoMessage()
72+
{
73+
var botPoster = new Mock<IBotPoster>().Object;
74+
var bot = new Dinobot(TestBotId, botPoster);
75+
76+
bool parsed = await bot.ProcessMessageAsync();
77+
Assert.IsFalse(parsed);
78+
}
79+
80+
[TestMethod]
81+
public async Task TestMessageIsDm()
82+
{
83+
var botPoster = new Mock<IBotPoster>().Object;
84+
var bot = new Dinobot(TestBotId, botPoster);
85+
86+
var message = new MessageItem
87+
{
88+
MessageId = "1",
89+
ChatId = "1+2",
90+
RecipientId = "2",
91+
Text = "3 dinos"
92+
};
93+
bot.Message = message;
94+
95+
bool parsed = await bot.ProcessMessageAsync();
96+
Assert.IsFalse(parsed);
97+
}
98+
99+
[TestMethod]
100+
public async Task TestMessageHasDinosServerFail()
101+
{
102+
var botPoster = new Mock<IBotPoster>();
103+
botPoster
104+
.Setup(b => b.PostEmojiAsync(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>()))
105+
.Returns(Task.FromResult(System.Net.HttpStatusCode.BadRequest));
106+
var bot = new Dinobot(TestBotId, botPoster.Object);
107+
108+
var message = new MessageItem
109+
{
110+
MessageId = "1",
111+
GroupId = "1",
112+
Text = "3 dinos"
113+
};
114+
bot.Message = message;
115+
116+
bool sent = await bot.ProcessMessageAsync();
117+
Assert.IsFalse(sent);
118+
}
119+
120+
[TestMethod]
121+
public async Task TestMessageHasDinos()
122+
{
123+
var botPoster = new Mock<IBotPoster>();
124+
botPoster
125+
.Setup(b => b.PostEmojiAsync(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>()))
126+
.Returns(Task.FromResult(System.Net.HttpStatusCode.Accepted));
127+
var bot = new Dinobot(TestBotId, botPoster.Object);
128+
129+
var message = new MessageItem
130+
{
131+
MessageId = "1",
132+
GroupId = "1",
133+
Text = "3 dinos"
134+
};
135+
bot.Message = message;
136+
137+
bool sent = await bot.ProcessMessageAsync();
138+
Assert.IsTrue(sent);
139+
}
140+
141+
[TestMethod]
142+
public async Task TestMessageHasDinosMiddle()
143+
{
144+
var botPoster = new Mock<IBotPoster>();
145+
botPoster
146+
.Setup(b => b.PostEmojiAsync(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>()))
147+
.Returns(Task.FromResult(System.Net.HttpStatusCode.Accepted));
148+
var bot = new Dinobot(TestBotId, botPoster.Object);
149+
150+
var message = new MessageItem
151+
{
152+
MessageId = "1",
153+
GroupId = "1",
154+
Text = "so cool 3 dinos yay"
155+
};
156+
bot.Message = message;
157+
158+
bool sent = await bot.ProcessMessageAsync();
159+
Assert.IsTrue(sent);
160+
}
161+
162+
[TestMethod]
163+
public async Task TestMessageHasAddressCaps()
164+
{
165+
var botPoster = new Mock<IBotPoster>();
166+
botPoster
167+
.Setup(b => b.PostEmojiAsync(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>()))
168+
.Returns(Task.FromResult(System.Net.HttpStatusCode.Accepted));
169+
var bot = new Dinobot(TestBotId, botPoster.Object);
170+
171+
var message = new MessageItem
172+
{
173+
MessageId = "1",
174+
GroupId = "1",
175+
Text = "HEY DINOBOT"
176+
};
177+
bot.Message = message;
178+
179+
bool sent = await bot.ProcessMessageAsync();
180+
Assert.IsTrue(sent);
181+
}
182+
183+
[TestMethod]
184+
public async Task TestMessageHasAddressMiddle()
185+
{
186+
var botPoster = new Mock<IBotPoster>();
187+
botPoster
188+
.Setup(b => b.PostEmojiAsync(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>()))
189+
.Returns(Task.FromResult(System.Net.HttpStatusCode.Accepted));
190+
var bot = new Dinobot(TestBotId, botPoster.Object);
191+
192+
var message = new MessageItem
193+
{
194+
MessageId = "1",
195+
GroupId = "1",
196+
Text = "Oh hey dinobot what's up?"
197+
};
198+
bot.Message = message;
199+
200+
bool sent = await bot.ProcessMessageAsync();
201+
Assert.IsTrue(sent);
202+
}
203+
204+
[TestMethod]
205+
public async Task TestMessageHasAddressServerFail()
206+
{
207+
var botPoster = new Mock<IBotPoster>();
208+
botPoster
209+
.Setup(b => b.PostEmojiAsync(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>()))
210+
.Returns(Task.FromResult(System.Net.HttpStatusCode.BadRequest));
211+
var bot = new Dinobot(TestBotId, botPoster.Object);
212+
213+
var message = new MessageItem
214+
{
215+
MessageId = "1",
216+
GroupId = "1",
217+
Text = "hey dinobot"
218+
};
219+
bot.Message = message;
220+
221+
bool sent = await bot.ProcessMessageAsync();
222+
Assert.IsFalse(sent);
223+
}
224+
225+
[TestMethod]
226+
public async Task TestMessageNoDinos()
227+
{
228+
var botPoster = new Mock<IBotPoster>();
229+
botPoster
230+
.Setup(b => b.PostEmojiAsync(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>()))
231+
.Returns(Task.FromResult(System.Net.HttpStatusCode.Accepted));
232+
var bot = new Dinobot(TestBotId, botPoster.Object);
233+
234+
var message = new MessageItem
235+
{
236+
MessageId = "1",
237+
GroupId = "1",
238+
Text = "None here"
239+
};
240+
bot.Message = message;
241+
242+
bool sent = await bot.ProcessMessageAsync();
243+
Assert.IsFalse(sent);
244+
}
245+
}
246+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
[assembly: AssemblyTitle("DinoTests")]
6+
[assembly: AssemblyDescription("")]
7+
[assembly: AssemblyConfiguration("")]
8+
[assembly: AssemblyCompany("")]
9+
[assembly: AssemblyProduct("DinoTests")]
10+
[assembly: AssemblyCopyright("Copyright © 2021")]
11+
[assembly: AssemblyTrademark("")]
12+
[assembly: AssemblyCulture("")]
13+
14+
[assembly: ComVisible(false)]
15+
16+
[assembly: Guid("20d97e53-3e9a-4e68-88e2-ad3a6daf2fda")]
17+
18+
// [assembly: AssemblyVersion("1.0.*")]
19+
[assembly: AssemblyVersion("1.0.0.0")]
20+
[assembly: AssemblyFileVersion("1.0.0.0")]
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Castle.Core" version="4.4.0" targetFramework="net461" />
4+
<package id="Moq" version="4.16.0" targetFramework="net461" />
5+
<package id="MSTest.TestAdapter" version="2.1.1" targetFramework="net461" />
6+
<package id="MSTest.TestFramework" version="2.1.1" targetFramework="net461" />
7+
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net461" />
8+
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net461" />
9+
</packages>

‎dotnet/DinoBot/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,5 @@ These settings can be tested locally by creating a `local.settings` file in the
5050
- Upgrade to Azure Functions 3
5151
- Move shared code to a re-usable nuget package
5252
- Make Dinobot do math, e.g. "10-3 dinos"
53-
- Make more things configurable, like the maximum number of dinos
53+
- Make more things configurable, like the maximum number of dinos
54+
- More detailed tests

0 commit comments

Comments
 (0)
Please sign in to comment.