1
+ <?php
2
+
3
+ namespace Tests \Feature ;
4
+
5
+ use LucianoTonet \GroqLaravel \Facades \Groq ;
6
+ use LucianoTonet \GroqLaravel \GroqServiceProvider ;
7
+ use LucianoTonet \GroqPHP \Completions ;
8
+ use LucianoTonet \GroqPHP \Stream ;
9
+ use LucianoTonet \GroqPHP \Groq as GroqPHP ;
10
+ use LucianoTonet \GroqPHP \Chat ;
11
+ use Orchestra \Testbench \TestCase ;
12
+
13
+ class CompletionsTest extends TestCase
14
+ {
15
+ protected function getPackageProviders ($ app )
16
+ {
17
+ return [GroqServiceProvider::class];
18
+ }
19
+
20
+ protected function getEnvironmentSetUp ($ app )
21
+ {
22
+ $ app ['config ' ]->set ('groq.api_key ' , 'test-key ' );
23
+ $ app ['config ' ]->set ('groq.model ' , 'llama-3.1-8b-instant ' );
24
+ }
25
+
26
+ /** @test */
27
+ public function it_can_get_completions_instance ()
28
+ {
29
+ $ this ->assertInstanceOf (Completions::class, Groq::completions ());
30
+ }
31
+
32
+ /** @test */
33
+ public function it_can_create_completion_with_basic_options ()
34
+ {
35
+ // Create a mock response
36
+ $ expectedResponse = [
37
+ 'choices ' => [
38
+ [
39
+ 'message ' => [
40
+ 'content ' => 'Test response '
41
+ ]
42
+ ]
43
+ ]
44
+ ];
45
+
46
+ // Mock the Completions class
47
+ $ mockCompletions = $ this ->createMock (Completions::class);
48
+ $ mockCompletions ->expects ($ this ->once ())
49
+ ->method ('create ' )
50
+ ->with ($ this ->callback (function ($ params ) {
51
+ return isset ($ params ['model ' ]) &&
52
+ isset ($ params ['messages ' ]) &&
53
+ isset ($ params ['temperature ' ]);
54
+ }))
55
+ ->willReturn ($ expectedResponse );
56
+
57
+ // Mock the Chat class that will return our mock Completions
58
+ $ mockChat = $ this ->getMockBuilder (Chat::class)
59
+ ->disableOriginalConstructor ()
60
+ ->getMock ();
61
+
62
+ $ mockChat ->expects ($ this ->once ())
63
+ ->method ('completions ' )
64
+ ->willReturn ($ mockCompletions );
65
+
66
+ // Mock the Groq class
67
+ $ mockGroq = $ this ->getMockBuilder (GroqPHP::class)
68
+ ->disableOriginalConstructor ()
69
+ ->getMock ();
70
+
71
+ $ mockGroq ->expects ($ this ->once ())
72
+ ->method ('chat ' )
73
+ ->willReturn ($ mockChat );
74
+
75
+ // Replace the bound instance
76
+ $ this ->app ->instance (GroqPHP::class, $ mockGroq );
77
+
78
+ // Test the facade (which now uses our mock)
79
+ $ result = Groq::completions ()->create ([
80
+ 'model ' => 'llama-3.1-8b-instant ' ,
81
+ 'messages ' => [
82
+ ['role ' => 'user ' , 'content ' => 'Hello, world! ' ]
83
+ ],
84
+ 'temperature ' => 0.7
85
+ ]);
86
+
87
+ $ this ->assertIsArray ($ result );
88
+ $ this ->assertArrayHasKey ('choices ' , $ result );
89
+ $ this ->assertEquals ('Test response ' , $ result ['choices ' ][0 ]['message ' ]['content ' ]);
90
+ }
91
+
92
+ /** @test */
93
+ public function it_can_handle_image_content ()
94
+ {
95
+ // Create a mock response
96
+ $ expectedResponse = [
97
+ 'choices ' => [
98
+ [
99
+ 'message ' => [
100
+ 'content ' => 'Image description '
101
+ ]
102
+ ]
103
+ ]
104
+ ];
105
+
106
+ // Mock the Completions class
107
+ $ mockCompletions = $ this ->createMock (Completions::class);
108
+ $ mockCompletions ->expects ($ this ->once ())
109
+ ->method ('create ' )
110
+ ->with ($ this ->callback (function ($ params ) {
111
+ return isset ($ params ['messages ' ][0 ]['content ' ]) &&
112
+ is_array ($ params ['messages ' ][0 ]['content ' ]) &&
113
+ isset ($ params ['messages ' ][0 ]['content ' ][1 ]['type ' ]) &&
114
+ $ params ['messages ' ][0 ]['content ' ][1 ]['type ' ] === 'image_url ' ;
115
+ }))
116
+ ->willReturn ($ expectedResponse );
117
+
118
+ // Mock the Chat class that will return our mock Completions
119
+ $ mockChat = $ this ->getMockBuilder (Chat::class)
120
+ ->disableOriginalConstructor ()
121
+ ->getMock ();
122
+
123
+ $ mockChat ->expects ($ this ->once ())
124
+ ->method ('completions ' )
125
+ ->willReturn ($ mockCompletions );
126
+
127
+ // Mock the Groq class
128
+ $ mockGroq = $ this ->getMockBuilder (GroqPHP::class)
129
+ ->disableOriginalConstructor ()
130
+ ->getMock ();
131
+
132
+ $ mockGroq ->expects ($ this ->once ())
133
+ ->method ('chat ' )
134
+ ->willReturn ($ mockChat );
135
+
136
+ // Replace the bound instance
137
+ $ this ->app ->instance (GroqPHP::class, $ mockGroq );
138
+
139
+ // Test the facade (which now uses our mock)
140
+ $ result = Groq::completions ()->create ([
141
+ 'model ' => 'llama-3.1-8b-instant ' ,
142
+ 'messages ' => [
143
+ [
144
+ 'role ' => 'user ' ,
145
+ 'content ' => [
146
+ ['type ' => 'text ' , 'text ' => 'What is in this image? ' ],
147
+ [
148
+ 'type ' => 'image_url ' ,
149
+ 'image_url ' => [
150
+ 'url ' => 'https://example.com/image.jpg '
151
+ ]
152
+ ]
153
+ ]
154
+ ]
155
+ ]
156
+ ]);
157
+
158
+ $ this ->assertIsArray ($ result );
159
+ $ this ->assertArrayHasKey ('choices ' , $ result );
160
+ $ this ->assertEquals ('Image description ' , $ result ['choices ' ][0 ]['message ' ]['content ' ]);
161
+ }
162
+
163
+ /** @test */
164
+ public function it_can_stream_completions ()
165
+ {
166
+ // Create a mock Stream object
167
+ $ mockStream = $ this ->getMockBuilder (Stream::class)
168
+ ->disableOriginalConstructor ()
169
+ ->getMock ();
170
+
171
+ // Set up the mock to implement the chunks generator
172
+ $ mockStream ->expects ($ this ->once ())
173
+ ->method ('chunks ' )
174
+ ->willReturn ((function () {
175
+ yield ['choices ' => [['delta ' => ['content ' => 'Hello ' ]]]];
176
+ yield ['choices ' => [['delta ' => ['content ' => ' world! ' ]]]];
177
+ })());
178
+
179
+ // Mock the Completions class
180
+ $ mockCompletions = $ this ->createMock (Completions::class);
181
+ $ mockCompletions ->expects ($ this ->once ())
182
+ ->method ('create ' )
183
+ ->with ($ this ->callback (function ($ params ) {
184
+ return isset ($ params ['stream ' ]) && $ params ['stream ' ] === true ;
185
+ }))
186
+ ->willReturn ($ mockStream );
187
+
188
+ // Mock the Chat class that will return our mock Completions
189
+ $ mockChat = $ this ->getMockBuilder (Chat::class)
190
+ ->disableOriginalConstructor ()
191
+ ->getMock ();
192
+
193
+ $ mockChat ->expects ($ this ->once ())
194
+ ->method ('completions ' )
195
+ ->willReturn ($ mockCompletions );
196
+
197
+ // Mock the Groq class
198
+ $ mockGroq = $ this ->getMockBuilder (GroqPHP::class)
199
+ ->disableOriginalConstructor ()
200
+ ->getMock ();
201
+
202
+ $ mockGroq ->expects ($ this ->once ())
203
+ ->method ('chat ' )
204
+ ->willReturn ($ mockChat );
205
+
206
+ // Replace the bound instance
207
+ $ this ->app ->instance (GroqPHP::class, $ mockGroq );
208
+
209
+ // Test the streaming functionality
210
+ $ stream = Groq::completions ()->create ([
211
+ 'model ' => 'llama-3.1-8b-instant ' ,
212
+ 'messages ' => [
213
+ ['role ' => 'user ' , 'content ' => 'Hello, world! ' ]
214
+ ],
215
+ 'stream ' => true
216
+ ]);
217
+
218
+ $ this ->assertInstanceOf (Stream::class, $ stream );
219
+
220
+ // Test iterating over the stream using chunks()
221
+ $ result = '' ;
222
+ foreach ($ stream ->chunks () as $ response ) {
223
+ $ result .= $ response ['choices ' ][0 ]['delta ' ]['content ' ] ?? '' ;
224
+ }
225
+
226
+ $ this ->assertEquals ('Hello world! ' , $ result );
227
+ }
228
+ }
0 commit comments