microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
samples/migration-bot

Branches

Tags

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

Clone

HTTPS

Download ZIP

core/test/Microsoft.Teams.Bot.Apps.UnitTests/CitationEntityTests.cs

381lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using Microsoft.Teams.Bot.Apps.Schema;
5using Microsoft.Teams.Bot.Apps.Schema.Entities;
6using Microsoft.Teams.Bot.Core.Schema;
7
8namespace Microsoft.Teams.Bot.Apps.UnitTests;
9
10public class CitationEntityTests
11{
12 [Fact]
13 public void AddCitation_CreatesEntityWithClaim()
14 {
15 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
16
17 var citation = activity.AddCitation(1, new CitationAppearance
18 {
19 Name = "Test Document",
20 Abstract = "Test abstract content"
21 });
22
23 Assert.NotNull(activity.Entities);
24 Assert.Single(activity.Entities);
25 Assert.IsType<CitationEntity>(activity.Entities[0]);
26 Assert.NotNull(citation.Citation);
27 Assert.Single(citation.Citation);
28 Assert.Equal(1, citation.Citation[0].Position);
29 Assert.Equal("Test Document", citation.Citation[0].Appearance.Name);
30 Assert.Equal("Test abstract content", citation.Citation[0].Appearance.Abstract);
31 }
32
33 [Fact]
34 public void AddCitation_MultipleCitations_AccumulateOnSameEntity()
35 {
36 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
37
38 activity.AddCitation(1, new CitationAppearance
39 {
40 Name = "Document One",
41 Abstract = "First abstract"
42 });
43
44 var citation = activity.AddCitation(2, new CitationAppearance
45 {
46 Name = "Document Two",
47 Abstract = "Second abstract"
48 });
49
50 Assert.NotNull(activity.Entities);
51 Assert.Single(activity.Entities);
52 Assert.NotNull(citation.Citation);
53 Assert.Equal(2, citation.Citation.Count);
54 Assert.Equal(1, citation.Citation[0].Position);
55 Assert.Equal(2, citation.Citation[1].Position);
56 Assert.Equal("Document One", citation.Citation[0].Appearance.Name);
57 Assert.Equal("Document Two", citation.Citation[1].Appearance.Name);
58 }
59
60 [Fact]
61 public void AddAIGenerated_SetsAdditionalType()
62 {
63 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
64
65 var messageEntity = activity.AddAIGenerated();
66
67 Assert.NotNull(activity.Entities);
68 Assert.Single(activity.Entities);
69 Assert.IsType<OMessageEntity>(activity.Entities[0]);
70 Assert.NotNull(messageEntity.AdditionalType);
71 Assert.Contains("AIGeneratedContent", messageEntity.AdditionalType);
72 }
73
74 [Fact]
75 public void AddAIGenerated_CalledTwice_DoesNotDuplicate()
76 {
77 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
78
79 activity.AddAIGenerated();
80 activity.AddAIGenerated();
81
82 Assert.NotNull(activity.Entities);
83 Assert.Single(activity.Entities);
84 var messageEntity = activity.Entities[0] as OMessageEntity;
85 Assert.NotNull(messageEntity?.AdditionalType);
86 Assert.Single(messageEntity.AdditionalType);
87 }
88
89 [Fact]
90 public void AddAIGenerated_ThenAddCitation_PreservesAILabel()
91 {
92 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
93
94 activity.AddAIGenerated();
95 var citation = activity.AddCitation(1, new CitationAppearance
96 {
97 Name = "Test Doc",
98 Abstract = "Test abstract"
99 });
100
101 Assert.NotNull(activity.Entities);
102 Assert.Single(activity.Entities);
103 Assert.IsType<CitationEntity>(activity.Entities[0]);
104 Assert.NotNull(citation.AdditionalType);
105 Assert.Contains("AIGeneratedContent", citation.AdditionalType);
106 Assert.NotNull(citation.Citation);
107 Assert.Single(citation.Citation);
108 }
109
110 [Fact]
111 public void AddFeedback_SetsFeedbackLoopEnabled()
112 {
113 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
114
115 activity.AddFeedback();
116
117 Assert.NotNull(activity.ChannelData);
118 Assert.True(activity.ChannelData.FeedbackLoopEnabled);
119 }
120
121 [Fact]
122 public void AddCitation_WithAllAppearanceFields_SetsCorrectly()
123 {
124 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
125
126 var citation = activity.AddCitation(1, new CitationAppearance
127 {
128 Name = "Full Document",
129 Abstract = "Full abstract",
130 Text = "{\"type\":\"AdaptiveCard\"}",
131 Url = new Uri("https://example.com/doc"),
132 EncodingFormat = EncodingFormats.AdaptiveCard,
133 Icon = CitationIcon.MicrosoftWord,
134 Keywords = ["keyword1", "keyword2"],
135 UsageInfo = new SensitiveUsageEntity { Name = "Confidential" }
136 });
137
138 Assert.NotNull(citation.Citation);
139 var appearance = citation.Citation[0].Appearance;
140 Assert.Equal("Full Document", appearance.Name);
141 Assert.Equal("Full abstract", appearance.Abstract);
142 Assert.Equal("{\"type\":\"AdaptiveCard\"}", appearance.Text);
143 Assert.Equal(new Uri("https://example.com/doc"), appearance.Url);
144 Assert.Equal(EncodingFormats.AdaptiveCard, appearance.EncodingFormat);
145 Assert.NotNull(appearance.Image);
146 Assert.Equal(CitationIcon.MicrosoftWord, appearance.Image.Name);
147 Assert.NotNull(appearance.Keywords);
148 Assert.Equal(2, appearance.Keywords.Count);
149 Assert.NotNull(appearance.UsageInfo);
150 Assert.Equal("Confidential", appearance.UsageInfo.Name);
151 }
152
153 [Fact]
154 public void CitationEntity_RoundTrip_Serialization()
155 {
156 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
157
158 activity.AddAIGenerated();
159 activity.AddCitation(1, new CitationAppearance
160 {
161 Name = "Test Document",
162 Abstract = "Test abstract content",
163 Url = new Uri("https://example.com"),
164 Icon = CitationIcon.Pdf,
165 Keywords = ["test", "citation"]
166 });
167 activity.AddFeedback();
168
169 string json = activity.ToJson();
170
171 Assert.Contains("\"citation\"", json);
172 Assert.Contains("Test Document", json);
173 Assert.Contains("Test abstract content", json);
174 Assert.Contains("https://example.com", json);
175 Assert.Contains("AIGeneratedContent", json);
176 Assert.Contains("Claim", json);
177 Assert.Contains("DigitalDocument", json);
178 Assert.Contains("PDF", json);
179 Assert.Contains("feedbackLoopEnabled", json);
180 }
181
182 [Fact]
183 public void CitationEntity_Rebase_SurvivesRoundTrip()
184 {
185 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
186
187 activity.AddAIGenerated();
188 activity.AddCitation(1, new CitationAppearance
189 {
190 Name = "Rebase Test Doc",
191 Abstract = "Rebase test abstract",
192 Icon = CitationIcon.MicrosoftExcel
193 });
194
195 // Verify base CoreActivity.Entities (JsonArray) contains the citation data
196 CoreActivity coreActivity = activity;
197 Assert.NotNull(coreActivity.Entities);
198 Assert.Single(coreActivity.Entities);
199
200 string? entityJson = coreActivity.Entities[0]?.ToJsonString();
201 Assert.NotNull(entityJson);
202 Assert.Contains("citation", entityJson);
203 Assert.Contains("Rebase Test Doc", entityJson);
204 Assert.Contains("Rebase test abstract", entityJson);
205 Assert.Contains("AIGeneratedContent", entityJson);
206 Assert.Contains("Microsoft Excel", entityJson);
207 }
208
209 [Fact]
210 public void Fixture_AdaptiveCardActivity_DeserializesAIGeneratedEntity()
211 {
212 string json = """
213 {
214 "type": "message",
215 "channelId": "msteams",
216 "entities": [
217 {
218 "type": "https://schema.org/Message",
219 "@context": "https://schema.org",
220 "@type": "Message",
221 "additionalType": [
222 "AIGeneratedContent"
223 ]
224 }
225 ]
226 }
227 """;
228
229 CoreActivity coreActivity = CoreActivity.FromJsonString(json);
230 TeamsActivity activity = TeamsActivity.FromActivity(coreActivity);
231
232 Assert.NotNull(activity.Entities);
233 Assert.Single(activity.Entities);
234
235 var entity = activity.Entities[0];
236 Assert.Equal("https://schema.org/Message", entity.Type);
237 Assert.Equal("Message", entity.OType);
238
239 // Should deserialize as CitationEntity (since @type is "Message")
240 var citationEntity = entity as CitationEntity;
241 Assert.NotNull(citationEntity);
242 Assert.NotNull(citationEntity.AdditionalType);
243 Assert.Contains("AIGeneratedContent", citationEntity.AdditionalType);
244 }
245
246 [Fact]
247 public void Fixture_SensitiveUsageEntity_DeserializesByOType()
248 {
249 string json = """
250 {
251 "type": "message",
252 "entities": [
253 {
254 "type": "https://schema.org/Message",
255 "@context": "https://schema.org",
256 "@type": "CreativeWork",
257 "name": "Confidential",
258 "description": "This is sensitive content"
259 }
260 ]
261 }
262 """;
263
264 CoreActivity coreActivity = CoreActivity.FromJsonString(json);
265 TeamsActivity activity = TeamsActivity.FromActivity(coreActivity);
266
267 Assert.NotNull(activity.Entities);
268 Assert.Single(activity.Entities);
269
270 var entity = activity.Entities[0] as SensitiveUsageEntity;
271 Assert.NotNull(entity);
272 Assert.Equal("Confidential", entity.Name);
273 Assert.Equal("This is sensitive content", entity.Description);
274 }
275
276 [Fact]
277 public void OMessageEntity_WithUnknownOType_DeserializesAsOMessageEntity()
278 {
279 string json = """
280 {
281 "type": "message",
282 "entities": [
283 {
284 "type": "https://schema.org/Message",
285 "@context": "https://schema.org",
286 "@type": "UnknownType"
287 }
288 ]
289 }
290 """;
291
292 CoreActivity coreActivity = CoreActivity.FromJsonString(json);
293 TeamsActivity activity = TeamsActivity.FromActivity(coreActivity);
294
295 Assert.NotNull(activity.Entities);
296 Assert.Single(activity.Entities);
297
298 var entity = activity.Entities[0];
299 Assert.IsType<OMessageEntity>(entity);
300 Assert.Equal("UnknownType", entity.OType);
301 }
302
303 [Fact]
304 public void Fixture_CitationEntity_DeserializesWithClaims()
305 {
306 string json = """
307 {
308 "type": "message",
309 "entities": [
310 {
311 "type": "https://schema.org/Message",
312 "@context": "https://schema.org",
313 "@type": "Message",
314 "additionalType": ["AIGeneratedContent"],
315 "citation": [
316 {
317 "@type": "Claim",
318 "position": 1,
319 "appearance": {
320 "@type": "DigitalDocument",
321 "name": "Test Document",
322 "abstract": "Test abstract",
323 "url": "https://example.com/doc",
324 "encodingFormat": "application/vnd.microsoft.card.adaptive"
325 }
326 }
327 ]
328 }
329 ]
330 }
331 """;
332
333 CoreActivity coreActivity = CoreActivity.FromJsonString(json);
334 TeamsActivity activity = TeamsActivity.FromActivity(coreActivity);
335
336 Assert.NotNull(activity.Entities);
337 Assert.Single(activity.Entities);
338
339 var citationEntity = activity.Entities[0] as CitationEntity;
340 Assert.NotNull(citationEntity);
341 Assert.NotNull(citationEntity.AdditionalType);
342 Assert.Contains("AIGeneratedContent", citationEntity.AdditionalType);
343 Assert.NotNull(citationEntity.Citation);
344 Assert.Single(citationEntity.Citation);
345 Assert.Equal(1, citationEntity.Citation[0].Position);
346 Assert.Equal("Test Document", citationEntity.Citation[0].Appearance.Name);
347 Assert.Equal("Test abstract", citationEntity.Citation[0].Appearance.Abstract);
348 Assert.Equal(EncodingFormats.AdaptiveCard, citationEntity.Citation[0].Appearance.EncodingFormat);
349 }
350
351 [Fact]
352 public void CitationEntity_CopyConstructor_PreservesData()
353 {
354 var original = new CitationEntity();
355 original.AdditionalType = ["AIGeneratedContent"];
356 original.Citation = [
357 new CitationClaim
358 {
359 Position = 1,
360 Appearance = new CitationAppearanceDocument
361 {
362 Name = "Doc",
363 Abstract = "Abstract"
364 }
365 }
366 ];
367
368 var copy = new CitationEntity(original);
369
370 Assert.NotNull(copy.AdditionalType);
371 Assert.Contains("AIGeneratedContent", copy.AdditionalType);
372 Assert.NotNull(copy.Citation);
373 Assert.Single(copy.Citation);
374 Assert.Equal(1, copy.Citation[0].Position);
375 Assert.Equal("Doc", copy.Citation[0].Appearance.Name);
376
377 // Ensure it's a deep copy (modifying copy doesn't affect original)
378 copy.AdditionalType.Add("NewType");
379 Assert.Single(original.AdditionalType);
380 }
381}
382