microsoft/teams.net

Public

mirrored fromhttps://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
docs/update-release-process

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

Tests/Microsoft.Teams.Api.Tests/Activities/Message/MessageActivityTests.cs

580lines · modecode

1using System.Text;
2using System.Text.Json;
3using System.Text.Json.Serialization;
4
5using Microsoft.Teams.Api.Activities;
6using Microsoft.Teams.Api.Entities;
7
8namespace Microsoft.Teams.Api.Tests.Activities;
9
10public class MessageActivityTests
11{
12 [Fact]
13 public void JsonSerialize()
14 {
15 var activity = new MessageActivity("testing123")
16 {
17 Id = "1",
18 From = new()
19 {
20 Id = "1",
21 Name = "test",
22 Role = Role.User
23 },
24 Conversation = new()
25 {
26 Id = "1",
27 Type = ConversationType.Personal
28 },
29 Recipient = new()
30 {
31 Id = "2",
32 Name = "test-bot",
33 Role = Role.Bot
34 }
35 };
36
37 var json = JsonSerializer.Serialize(activity, new JsonSerializerOptions()
38 {
39 WriteIndented = true,
40 IndentSize = 4,
41 DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
42 });
43
44 Assert.Equal(File.ReadAllText(
45 @"../../../Json/Activity/Message/MessageActivity.json"
46 ), json);
47 }
48
49 [Fact]
50 public void JsonSerialize_Derived()
51 {
52 MessageActivity activity = new MessageActivity("testing123")
53 {
54 Id = "1",
55 From = new()
56 {
57 Id = "1",
58 Name = "test",
59 Role = Role.User
60 },
61 Conversation = new()
62 {
63 Id = "1",
64 Type = ConversationType.Personal
65 },
66 Recipient = new()
67 {
68 Id = "2",
69 Name = "test-bot",
70 Role = Role.Bot
71 }
72 };
73
74 var json = JsonSerializer.Serialize(activity, new JsonSerializerOptions()
75 {
76 WriteIndented = true,
77 IndentSize = 4,
78 DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
79 });
80
81 Assert.Equal(File.ReadAllText(
82 @"../../../Json/Activity/Message/MessageActivity.json"
83 ), json);
84 }
85
86 [Fact]
87 public void JsonSerialize_Derived_Interface()
88 {
89 Activity activity = new MessageActivity("testing123")
90 {
91 Id = "1",
92 From = new()
93 {
94 Id = "1",
95 Name = "test",
96 Role = Role.User
97 },
98 Conversation = new()
99 {
100 Id = "1",
101 Type = ConversationType.Personal
102 },
103 Recipient = new()
104 {
105 Id = "2",
106 Name = "test-bot",
107 Role = Role.Bot
108 }
109 };
110
111 var json = JsonSerializer.Serialize(activity, new JsonSerializerOptions()
112 {
113 WriteIndented = true,
114 IndentSize = 4,
115 DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
116 });
117
118 Assert.Equal(File.ReadAllText(
119 @"../../../Json/Activity/Message/MessageActivity.json"
120 ), json);
121 }
122
123 [Fact]
124 public void JsonSerialize_Mention()
125 {
126 Account bot = new()
127 {
128 Id = "2",
129 Name = "test-bot",
130 Role = Role.Bot
131 };
132
133 Activity activity = new MessageActivity("testing123")
134 {
135 Id = "1",
136 From = new()
137 {
138 Id = "1",
139 Name = "test",
140 Role = Role.User
141 },
142 Conversation = new()
143 {
144 Id = "1",
145 Type = ConversationType.Personal
146 },
147 Recipient = bot
148 }.AddMention(bot);
149
150 var json = JsonSerializer.Serialize(activity, new JsonSerializerOptions()
151 {
152 WriteIndented = true,
153 IndentSize = 4,
154 DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
155 Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
156 });
157
158 var text = File.ReadAllText(
159 @"../../../Json/Activity/Message/MessageActivity_Mention.json",
160 Encoding.UTF8
161 );
162
163 Assert.Equal(text, json);
164 }
165
166 [Fact]
167 public void JsonDeserialize()
168 {
169 var json = File.ReadAllText(@"../../../Json/Activity/Message/MessageActivity.json");
170 var activity = JsonSerializer.Deserialize<MessageActivity>(json);
171 var expected = new MessageActivity("testing123")
172 {
173 Id = "1",
174 From = new()
175 {
176 Id = "1",
177 Name = "test",
178 Role = Role.User
179 },
180 Conversation = new()
181 {
182 Id = "1",
183 Type = ConversationType.Personal
184 },
185 Recipient = new()
186 {
187 Id = "2",
188 Name = "test-bot",
189 Role = Role.Bot
190 }
191 };
192
193 Assert.Equivalent(expected, activity);
194 }
195
196 [Fact]
197 public void JsonDeserialize_Derived()
198 {
199 var json = File.ReadAllText(@"../../../Json/Activity/Message/MessageActivity.json");
200 var activity = JsonSerializer.Deserialize<Activity>(json);
201 var expected = new MessageActivity("testing123")
202 {
203 Id = "1",
204 From = new()
205 {
206 Id = "1",
207 Name = "test",
208 Role = Role.User
209 },
210 Conversation = new()
211 {
212 Id = "1",
213 Type = ConversationType.Personal
214 },
215 Recipient = new()
216 {
217 Id = "2",
218 Name = "test-bot",
219 Role = Role.Bot
220 }
221 };
222
223 Assert.Equivalent(expected, activity);
224 }
225
226 [Fact]
227 public void JsonSerialize_WebChat_AllowsEmptyConversationType()
228 {
229 MessageActivity activity = new MessageActivity()
230 {
231 Id = "1",
232 ChannelId = new ChannelId("webchat"),
233 From = new Account()
234 {
235 Id = "1",
236 Name = "test",
237 Role = Role.User
238 },
239 Conversation = new Api.Conversation()
240 {
241 Id = "1"
242 },
243 Recipient = new Account
244 {
245 Id = "2",
246 Name = "test-bot",
247 Role = Role.Bot
248 }
249 };
250 string json = JsonSerializer.Serialize(activity, new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
251 string expected = File.ReadAllText(@"../../../Json/Activity/Message/MessageActivity_webChat.json");
252 Assert.Equal(expected, json);
253 }
254
255 [Fact]
256 public void JsonDeserialize_WebChat_AllowsEmptyConversationType()
257 {
258 var json = File.ReadAllText(@"../../../Json/Activity/Message/MessageActivity_webChat.json");
259 var activity = JsonSerializer.Deserialize<MessageActivity>(json);
260 Assert.NotNull(activity);
261 Assert.Equal("1", activity.Id);
262 Assert.Equal("webchat", activity.ChannelId);
263 Assert.NotNull(activity.From);
264 Assert.Equal("1", activity.From.Id);
265 Assert.Equal("test", activity.From.Name);
266 Assert.NotNull(activity.From.Role);
267 Assert.Equal(Role.User, activity.From.Role.Value);
268 Assert.NotNull(activity.Conversation);
269 Assert.Equal("1", activity.Conversation.Id);
270 Assert.Null(activity.Conversation.Type);
271 Assert.NotNull(activity.Recipient);
272 Assert.Equal("2", activity.Recipient.Id);
273 Assert.Equal("test-bot", activity.Recipient.Name);
274 Assert.NotNull(activity.Recipient.Role);
275 Assert.Equal(Role.Bot, activity.Recipient.Role.Value);
276 }
277
278 [Fact]
279 public void MultipleAddAIGenerated_DoesNotCreateDuplicateMessageEntities()
280 {
281 var activity = new MessageActivity("test");
282
283 activity.AddAIGenerated();
284 activity.AddAIGenerated();
285 activity.AddAIGenerated();
286
287 var messageEntities = activity.Entities?.Where(e =>
288 e.Type == "https://schema.org/Message" && e.OType == "Message"
289 ).ToList();
290
291 Assert.NotNull(messageEntities);
292 Assert.Single(messageEntities);
293 }
294
295 [Fact]
296 public void MultipleAddCitation_DoesNotCreateDuplicateMessageEntities()
297 {
298 var activity = new MessageActivity("test");
299
300 var appearance1 = new Microsoft.Teams.Api.Entities.CitationAppearance
301 {
302 Name = "Doc 1",
303 Abstract = "Abstract 1"
304 };
305
306 var appearance2 = new Microsoft.Teams.Api.Entities.CitationAppearance
307 {
308 Name = "Doc 2",
309 Abstract = "Abstract 2"
310 };
311
312 var appearance3 = new Microsoft.Teams.Api.Entities.CitationAppearance
313 {
314 Name = "Doc 3",
315 Abstract = "Abstract 3"
316 };
317
318 activity.AddCitation(1, appearance1);
319 activity.AddCitation(2, appearance2);
320 activity.AddCitation(3, appearance3);
321
322 var messageEntities = activity.Entities?.Where(e =>
323 e.Type == "https://schema.org/Message" && e.OType == "Message"
324 ).ToList();
325
326 Assert.NotNull(messageEntities);
327 Assert.Single(messageEntities);
328
329 // Verify all citations are in the single message entity
330 var citationEntity = messageEntities[0] as Microsoft.Teams.Api.Entities.CitationEntity;
331 Assert.NotNull(citationEntity);
332 Assert.NotNull(citationEntity.Citation);
333 Assert.Equal(3, citationEntity.Citation.Count);
334 }
335
336 [Fact]
337 public void MixedAddAIGeneratedAndAddCitation_DoesNotCreateDuplicateMessageEntities()
338 {
339 var activity = new MessageActivity("test");
340
341 activity.AddAIGenerated();
342
343 var appearance = new Microsoft.Teams.Api.Entities.CitationAppearance
344 {
345 Name = "Doc 1",
346 Abstract = "Abstract 1"
347 };
348
349 activity.AddCitation(1, appearance);
350 activity.AddAIGenerated();
351
352 var messageEntities = activity.Entities?.Where(e =>
353 e.Type == "https://schema.org/Message" && e.OType == "Message"
354 ).ToList();
355
356 Assert.NotNull(messageEntities);
357 Assert.Single(messageEntities);
358
359 // Verify it has both AI generated flag and citation
360 var entity = messageEntities[0] as Microsoft.Teams.Api.Entities.IMessageEntity;
361 Assert.NotNull(entity?.AdditionalType);
362 Assert.Contains("AIGeneratedContent", entity.AdditionalType);
363
364 var citationEntity = messageEntities[0] as Microsoft.Teams.Api.Entities.CitationEntity;
365 Assert.NotNull(citationEntity);
366 Assert.NotNull(citationEntity.Citation);
367 Assert.Single(citationEntity.Citation);
368 }
369
370 [Fact]
371 public void AddMention_WithAddTextFalse_DoesNotAddTextToActivity()
372 {
373 Account bot = new()
374 {
375 Id = "2",
376 Name = "test-bot",
377 Role = Role.Bot
378 };
379
380 var activity = new MessageActivity("testing123")
381 {
382 Id = "1",
383 From = new()
384 {
385 Id = "1",
386 Name = "test",
387 Role = Role.User
388 },
389 Conversation = new()
390 {
391 Id = "1",
392 Type = ConversationType.Personal
393 },
394 Recipient = bot
395 }.AddMention(bot, addText: false);
396
397 // Text should remain unchanged
398 Assert.Equal("testing123", activity.Text);
399
400 // But mention entity should still be added
401 var mention = activity.GetAccountMention("2");
402 Assert.NotNull(mention);
403 Assert.Equal("<at>test-bot</at>", mention.Text);
404 }
405
406 [Fact]
407 public void AddMention_WithCustomText_UsesCustomText()
408 {
409 Account bot = new()
410 {
411 Id = "2",
412 Name = "test-bot",
413 Role = Role.Bot
414 };
415
416 var activity = new MessageActivity("Hello ")
417 {
418 Id = "1",
419 From = new()
420 {
421 Id = "1",
422 Name = "test",
423 Role = Role.User
424 },
425 Conversation = new()
426 {
427 Id = "1",
428 Type = ConversationType.Personal
429 },
430 Recipient = bot
431 }.AddMention(bot, text: "Custom Name");
432
433 // Text should include custom mention text at the beginning
434 Assert.Equal("<at>Custom Name</at> Hello ", activity.Text);
435
436 // Mention entity should use custom text
437 var mention = activity.GetAccountMention("2");
438 Assert.NotNull(mention);
439 Assert.Equal("<at>Custom Name</at>", mention.Text);
440 }
441
442 [Fact]
443 public void AddMention_WithCustomTextAndAddTextFalse_DoesNotAddText()
444 {
445 Account bot = new()
446 {
447 Id = "2",
448 Name = "test-bot",
449 Role = Role.Bot
450 };
451
452 var activity = new MessageActivity("Hello")
453 {
454 Id = "1",
455 From = new()
456 {
457 Id = "1",
458 Name = "test",
459 Role = Role.User
460 },
461 Conversation = new()
462 {
463 Id = "1",
464 Type = ConversationType.Personal
465 },
466 Recipient = bot
467 }.AddMention(bot, text: "Custom Name", addText: false);
468
469 // Text should remain unchanged
470 Assert.Equal("Hello", activity.Text);
471
472 // But mention entity should use custom text
473 var mention = activity.GetAccountMention("2");
474 Assert.NotNull(mention);
475 Assert.Equal("<at>Custom Name</at>", mention.Text);
476 }
477
478 [Fact]
479 public void WithRecipient_DefaultsToNotTargeted()
480 {
481 var activity = new MessageActivity("hello").WithRecipient(new Account() { Id = "1" });
482
483 Assert.Null(activity.Recipient.IsTargeted);
484 Assert.NotNull(activity.Recipient);
485 }
486
487 [Fact]
488 public void WithRecipient_Bool_SetsIsTargeted()
489 {
490 var activity = new MessageActivity("hello").WithRecipient(new Account() { Id = "1" }, true);
491
492 Assert.True(activity.Recipient.IsTargeted);
493 Assert.NotNull(activity.Recipient);
494 }
495
496 [Fact]
497 public void WithRecipient_SetsIsTargetedAndRecipient()
498 {
499 var activity = new MessageActivity("hello").WithRecipient(new Account() { Id = "user-123", Name = "user", Role = Role.User }, true);
500
501 Assert.True(activity.Recipient.IsTargeted);
502 Assert.NotNull(activity.Recipient);
503 Assert.Equal("user-123", activity.Recipient.Id);
504 Assert.Equal("user", activity.Recipient.Name);
505 Assert.Equal(Role.User, activity.Recipient.Role);
506 }
507
508 [Fact]
509 public void WithRecipient_MaintainsFluentChaining()
510 {
511 // This test ensures that WithRecipient(account) returns MessageActivity, not Activity
512 // If it returned Activity, the call to AddText would not compile
513 var activity = new MessageActivity("hello")
514 .WithRecipient(new Account() { Id = "user-123" })
515 .AddText(" world");
516
517 Assert.Equal("hello world", activity.Text);
518 Assert.NotNull(activity.Recipient);
519 Assert.Equal("user-123", activity.Recipient.Id);
520 Assert.Null(activity.Recipient.IsTargeted);
521 }
522
523 [Fact]
524 public void JsonSerialize_WithIsTargeted()
525 {
526 var activity = new MessageActivity("targeted message").WithRecipient(new Account() { Id = "user-123" }, true);
527 activity.Id = "1";
528 activity.From = new() { Id = "1", Name = "test", Role = Role.User };
529 activity.Conversation = new() { Id = "1", Type = ConversationType.Personal };
530
531 var json = JsonSerializer.Serialize(activity, new JsonSerializerOptions()
532 {
533 WriteIndented = true,
534 IndentSize = 4,
535 DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
536 });
537
538 // IsTargeted is serialized in the recipient object
539 Assert.Contains("\"isTargeted\": true", json);
540 Assert.Contains("\"text\": \"targeted message\"", json);
541 // Verify the property is still set on the object
542 Assert.True(activity.Recipient.IsTargeted);
543 }
544
545 [Fact]
546 public void Validate_FluentAPI()
547 {
548 var msg = new MessageActivity("Hello")
549 .WithDeliveryMode(DeliveryMode.Notification)
550 .WithRecipient(new Account() { Id = "user-123", Name = "Test User", Role = Role.User }, true)
551 .WithImportance(Importance.High);
552
553 Assert.Equal("Hello", msg.Text);
554 Assert.True(msg.Recipient.IsTargeted);
555 Assert.NotNull(msg.Recipient);
556 Assert.Equal("user-123", msg.Recipient.Id);
557 Assert.Equal("Test User", msg.Recipient.Name);
558 Assert.Equal(Role.User, msg.Recipient.Role);
559 }
560
561 [Fact]
562 public void AddStreamFinal_OverridesExistingStreamType()
563 {
564 var activity = new MessageActivity("done")
565 {
566 Id = "stream-1",
567 ChannelData = new ChannelData { StreamType = StreamType.Informative }
568 };
569
570 activity.AddStreamFinal();
571
572 Assert.Equal(StreamType.Final, activity.ChannelData.StreamType);
573 Assert.Equal("stream-1", activity.ChannelData.StreamId);
574
575 var streamInfo = activity.Entities?.OfType<Microsoft.Teams.Api.Entities.StreamInfoEntity>().Single();
576 Assert.NotNull(streamInfo);
577 Assert.Equal(StreamType.Final, streamInfo.StreamType);
578 Assert.Equal("stream-1", streamInfo.StreamId);
579 }
580}