11#nullable enable
22using Microsoft . Extensions . AI ;
3- using NSubstitute ;
4- using Sentry . Extensions . AI ;
53
64namespace Sentry . Extensions . AI . Tests ;
75
86public class SentryAIExtensionsTests
97{
10- [ Fact ]
11- public void WithSentry_ChatOptions_WithNullTools_ReturnsOriginalOptions ( )
12- {
13- // Arrange
14- var options = new ChatOptions ( ) ;
15-
16- // Act
17- var result = options . WithSentry ( ) ;
18-
19- // Assert
20- Assert . Same ( options , result ) ;
21- }
22-
23- [ Fact ]
24- public void WithSentry_ChatOptions_WithEmptyTools_ReturnsOriginalOptions ( )
25- {
26- // Arrange
27- var options = new ChatOptions
28- {
29- Tools = new List < AITool > ( )
30- } ;
31-
32- // Act
33- var result = options . WithSentry ( ) ;
34-
35- // Assert
36- Assert . Same ( options , result ) ;
37- }
38-
39- [ Fact ]
40- public void WithSentry_ChatOptions_WrapsAIFunctionsWithSentryInstrumentedFunction ( )
41- {
42- // Arrange
43- var mockFunction = Substitute . For < AIFunction > ( ) ;
44- mockFunction . Name . Returns ( "TestFunction" ) ;
45- mockFunction . Description . Returns ( "Test Description" ) ;
46-
47- var options = new ChatOptions
48- {
49- Tools = new List < AITool > { mockFunction }
50- } ;
51-
52- // Act
53- var result = options . WithSentry ( ) ;
54-
55- // Assert
56- Assert . Same ( options , result ) ;
57- Assert . Single ( options . Tools ) ;
58- Assert . IsType < SentryInstrumentedFunction > ( options . Tools [ 0 ] ) ;
59-
60- var instrumentedFunction = ( SentryInstrumentedFunction ) options . Tools [ 0 ] ;
61- Assert . Equal ( "TestFunction" , instrumentedFunction . Name ) ;
62- Assert . Equal ( "Test Description" , instrumentedFunction . Description ) ;
63- }
64-
65- [ Fact ]
66- public void WithSentry_ChatOptions_DoesNotDoubleWrapSentryInstrumentedFunction ( )
67- {
68- // Arrange
69- var mockFunction = Substitute . For < AIFunction > ( ) ;
70- var mockOption = Substitute . For < ChatOptions > ( ) ;
71- var alreadyInstrumentedFunction = new SentryInstrumentedFunction ( mockFunction , mockOption ) ;
72-
73- var options = new ChatOptions
74- {
75- Tools = new List < AITool > { alreadyInstrumentedFunction }
76- } ;
77-
78- // Act
79- var result = options . WithSentry ( ) ;
80-
81- // Assert
82- Assert . Same ( options , result ) ;
83- Assert . Single ( options . Tools ) ;
84- Assert . Same ( alreadyInstrumentedFunction , options . Tools [ 0 ] ) ;
85- }
86-
87- [ Fact ]
88- public void WithSentry_ChatOptions_HandlesMultipleFunctions ( )
89- {
90- // Arrange
91- var mockFunction1 = Substitute . For < AIFunction > ( ) ;
92- mockFunction1 . Name . Returns ( "Function1" ) ;
93-
94- var mockFunction2 = Substitute . For < AIFunction > ( ) ;
95- mockFunction2 . Name . Returns ( "Function2" ) ;
96-
97- var mockOption1 = Substitute . For < ChatOptions > ( ) ;
98- var alreadyInstrumentedFunction = new SentryInstrumentedFunction ( mockFunction1 , mockOption1 ) ;
99-
100- var options = new ChatOptions
101- {
102- Tools = new List < AITool >
103- {
104- mockFunction1 ,
105- mockFunction2 ,
106- alreadyInstrumentedFunction
107- }
108- } ;
109-
110- // Act
111- var result = options . WithSentry ( ) ;
112-
113- // Assert
114- Assert . Same ( options , result ) ;
115- Assert . Equal ( 3 , options . Tools . Count ) ;
116-
117- // First function should be wrapped
118- Assert . IsType < SentryInstrumentedFunction > ( options . Tools [ 0 ] ) ;
119- Assert . Equal ( "Function1" , options . Tools [ 0 ] . Name ) ;
120-
121- // Second function should be wrapped
122- Assert . IsType < SentryInstrumentedFunction > ( options . Tools [ 1 ] ) ;
123- Assert . Equal ( "Function2" , options . Tools [ 1 ] . Name ) ;
124-
125- // Third function was already instrumented, should remain unchanged
126- Assert . Same ( alreadyInstrumentedFunction , options . Tools [ 2 ] ) ;
127- }
128-
129- [ Fact ]
130- public void WithSentry_ChatOptions_IgnoresNonAIFunctionTools ( )
131- {
132- // Arrange
133- var mockFunction = Substitute . For < AIFunction > ( ) ;
134- mockFunction . Name . Returns ( "TestFunction" ) ;
135-
136- var mockNonFunction = Substitute . For < AITool > ( ) ;
137- mockNonFunction . Name . Returns ( "NonFunction" ) ;
138-
139- var options = new ChatOptions
140- {
141- Tools = new List < AITool > { mockFunction , mockNonFunction }
142- } ;
143-
144- // Act
145- var result = options . WithSentry ( ) ;
146-
147- // Assert
148- Assert . Same ( options , result ) ;
149- Assert . Equal ( 2 , options . Tools . Count ) ;
150-
151- // AIFunction should be wrapped
152- Assert . IsType < SentryInstrumentedFunction > ( options . Tools [ 0 ] ) ;
153- Assert . Equal ( "TestFunction" , options . Tools [ 0 ] . Name ) ;
154-
155- // Non-AIFunction should remain unchanged
156- Assert . Same ( mockNonFunction , options . Tools [ 1 ] ) ;
157- }
158-
1598 [ Fact ]
1609 public void WithSentry_IChatClient_ReturnsWrappedClient ( )
16110 {
@@ -177,19 +26,17 @@ public void WithSentry_IChatClient_WithConfiguration_PassesConfigurationToWrappe
17726 var configureWasCalled = false ;
17827
17928 // Act
180- var result = mockClient . WithSentry ( Configure ) ;
29+ var result = mockClient . WithSentry ( options =>
30+ {
31+ configureWasCalled = true ;
32+ options . IncludeAIRequestMessages = false ;
33+ options . IncludeAIResponseContent = false ;
34+ }
35+ ) ;
18136
18237 // Assert
18338 Assert . IsType < SentryChatClient > ( result ) ;
18439 Assert . True ( configureWasCalled ) ;
185- return ;
186-
187- void Configure ( SentryAIOptions options )
188- {
189- configureWasCalled = true ;
190- options . IncludeAIRequestMessages = false ;
191- options . IncludeAIResponseContent = false ;
192- }
19340 }
19441
19542 [ Fact ]
0 commit comments