Skip to content

Commit 58444f7

Browse files
committed
Add tests for REST Controller and Error classes
1 parent 36ee5e1 commit 58444f7

8 files changed

Lines changed: 714 additions & 7 deletions

File tree

.distignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Git
22
.git
33
.gitignore
4+
.gitattributes
5+
.distignore
46
.editorconfig
57

68
# GitHub

.wp-env.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"core": null,
44
"phpVersion": "8.2",
55
"port": 8686,
6+
"testsPort": 8687,
67
"plugins": [
78
".",
89
"https://downloads.wordpress.org/plugin/indieauth.latest-stable.zip"

includes/class-adapter.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ public function get_name() {
146146
* @return bool True if this adapter can handle the URL.
147147
*/
148148
public function can_handle_url( $url ) {
149-
return true; // Default: can handle any URL.
149+
return true;
150+
// Default: can handle any URL.
150151
}
151152

152153
/**
@@ -159,7 +160,8 @@ public function can_handle_url( $url ) {
159160
* @return bool True if this adapter owns the feed.
160161
*/
161162
public function owns_feed( $url ) {
162-
return false; // Default: doesn't own any feeds.
163+
return false;
164+
// Default: doesn't own any feeds.
163165
}
164166

165167
// =========================================================================

includes/class-rest-controller.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ public function get_items( $request ) {
205205
$action
206206
)
207207
);
208-
}
208+
}//end switch
209209
}
210210

211211
/**
@@ -256,7 +256,7 @@ public function create_item( $request ) {
256256
$action
257257
)
258258
);
259-
}
259+
}//end switch
260260
}
261261

262262
/**
@@ -383,7 +383,7 @@ protected function handle_channels_post( $request, $user_id ) {
383383
* @param int $user_id The user ID.
384384
* @return \WP_REST_Response The response.
385385
*/
386-
protected function get_timeline( $request, $user_id ) {
386+
protected function get_timeline( $request, $user_id ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
387387
$channel = $request->get_param( 'channel' );
388388

389389
if ( empty( $channel ) ) {

phpcs.xml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,12 @@
2626
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
2727
<exclude-pattern>*/tests/*</exclude-pattern>
2828
</rule>
29-
<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter">
29+
<!-- Base adapter class defines interface signatures; default implementations don't use params -->
30+
<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed">
31+
<exclude-pattern>*/includes/class-adapter.php</exclude-pattern>
32+
</rule>
33+
<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter.Found">
3034
<exclude-pattern>*/includes/class-adapter.php</exclude-pattern>
31-
<exclude-pattern>*/includes/adapters/*</exclude-pattern>
3235
</rule>
3336
<rule ref="Generic.Formatting.MultipleStatementAlignment">
3437
<exclude-pattern>*/tests/*</exclude-pattern>

tests/phpunit/includes/class-test-adapter.php

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,102 @@ public function test_adapter_getters() {
142142
$this->assertEquals( 'test-adapter', $this->adapter->get_id() );
143143
$this->assertEquals( 'Test Adapter', $this->adapter->get_name() );
144144
}
145+
146+
/**
147+
* Test get_following filter.
148+
*/
149+
public function test_get_following_filter() {
150+
$this->adapter->register();
151+
152+
$result = apply_filters( 'microsub_get_following', array(), 'default', 1 );
153+
154+
$this->assertIsArray( $result );
155+
$this->assertCount( 1, $result );
156+
$this->assertEquals( 'feed', $result[0]['type'] );
157+
}
158+
159+
/**
160+
* Test unfollow filter.
161+
*/
162+
public function test_unfollow_filter() {
163+
$this->adapter->register();
164+
165+
$result = apply_filters( 'microsub_unfollow', null, 'default', 'https://example.com', 1 );
166+
167+
$this->assertTrue( $result );
168+
}
169+
170+
/**
171+
* Test multiple adapters are aggregated.
172+
*/
173+
public function test_multiple_adapters() {
174+
$this->adapter->register();
175+
176+
$second_adapter = new Test_Second_Adapter();
177+
$second_adapter->register();
178+
179+
$adapters = apply_filters( 'microsub_adapters', array() );
180+
181+
$this->assertCount( 2, $adapters );
182+
$this->assertArrayHasKey( 'test-adapter', $adapters );
183+
$this->assertArrayHasKey( 'second-adapter', $adapters );
184+
}
185+
186+
/**
187+
* Test channels are aggregated from multiple adapters.
188+
*/
189+
public function test_channels_aggregation() {
190+
$this->adapter->register();
191+
192+
$second_adapter = new Test_Second_Adapter();
193+
$second_adapter->register();
194+
195+
$channels = apply_filters( 'microsub_get_channels', array(), 1 );
196+
197+
$this->assertCount( 3, $channels );
198+
}
199+
200+
/**
201+
* Test can_handle_url default implementation.
202+
*/
203+
public function test_can_handle_url_default() {
204+
$this->assertFalse( $this->adapter->can_handle_url( 'https://example.com' ) );
205+
}
206+
207+
/**
208+
* Test owns_feed default implementation.
209+
*/
210+
public function test_owns_feed_default() {
211+
$this->assertFalse( $this->adapter->owns_feed( 'https://example.com/feed' ) );
212+
}
213+
}
214+
215+
class Test_Second_Adapter extends \Microsub\Adapter {
216+
217+
protected $id = 'second-adapter';
218+
protected $name = 'Second Adapter';
219+
220+
public function get_channels( $channels, $user_id ) {
221+
$channels[] = array(
222+
'uid' => 'second-channel',
223+
'name' => 'Second Channel',
224+
);
225+
return $channels;
226+
}
227+
228+
public function get_timeline( $result, $channel, $args ) {
229+
return $result;
230+
}
231+
232+
public function get_following( $result, $channel, $user_id ) {
233+
return $result;
234+
}
235+
236+
public function follow( $result, $channel, $url, $user_id ) {
237+
return $result;
238+
}
239+
240+
public function unfollow( $result, $channel, $url, $user_id ) {
241+
return $result;
242+
}
145243
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<?php
2+
/**
3+
* Test Error class.
4+
*
5+
* @package Microsub
6+
*/
7+
8+
namespace Microsub\Tests;
9+
10+
use WP_UnitTestCase;
11+
use Microsub\Error;
12+
13+
/**
14+
* Test Error class.
15+
*
16+
* @coversDefaultClass \Microsub\Error
17+
*/
18+
class Test_Error extends WP_UnitTestCase {
19+
20+
/**
21+
* Test invalid_request returns 400 with message.
22+
*
23+
* @covers ::invalid_request
24+
* @covers ::response
25+
*/
26+
public function test_invalid_request_error() {
27+
$response = Error::invalid_request( 'Test error message' );
28+
29+
$this->assertInstanceOf( '\WP_REST_Response', $response );
30+
$this->assertEquals( 400, $response->get_status() );
31+
32+
$data = $response->get_data();
33+
$this->assertEquals( 'invalid_request', $data['error'] );
34+
$this->assertEquals( 'Test error message', $data['error_description'] );
35+
}
36+
37+
/**
38+
* Test unauthorized returns 401.
39+
*
40+
* @covers ::unauthorized
41+
*/
42+
public function test_unauthorized_error() {
43+
$response = Error::unauthorized();
44+
45+
$this->assertEquals( 401, $response->get_status() );
46+
47+
$data = $response->get_data();
48+
$this->assertEquals( 'unauthorized', $data['error'] );
49+
}
50+
51+
/**
52+
* Test forbidden returns 403.
53+
*
54+
* @covers ::forbidden
55+
*/
56+
public function test_forbidden_error() {
57+
$response = Error::forbidden();
58+
59+
$this->assertEquals( 403, $response->get_status() );
60+
61+
$data = $response->get_data();
62+
$this->assertEquals( 'forbidden', $data['error'] );
63+
}
64+
65+
/**
66+
* Test insufficient_scope returns 403 with message.
67+
*
68+
* @covers ::insufficient_scope
69+
*/
70+
public function test_insufficient_scope_error() {
71+
$response = Error::insufficient_scope( 'Requires read scope' );
72+
73+
$this->assertEquals( 403, $response->get_status() );
74+
75+
$data = $response->get_data();
76+
$this->assertEquals( 'insufficient_scope', $data['error'] );
77+
$this->assertEquals( 'Requires read scope', $data['error_description'] );
78+
}
79+
80+
/**
81+
* Test not_found returns 404.
82+
*
83+
* @covers ::not_found
84+
*/
85+
public function test_not_found_error() {
86+
$response = Error::not_found();
87+
88+
$this->assertEquals( 404, $response->get_status() );
89+
90+
$data = $response->get_data();
91+
$this->assertEquals( 'not_found', $data['error'] );
92+
}
93+
94+
/**
95+
* Test not_implemented returns 501.
96+
*
97+
* @covers ::not_implemented
98+
*/
99+
public function test_not_implemented_error() {
100+
$response = Error::not_implemented( 'Feature not available' );
101+
102+
$this->assertEquals( 501, $response->get_status() );
103+
104+
$data = $response->get_data();
105+
$this->assertEquals( 'not_implemented', $data['error'] );
106+
$this->assertEquals( 'Feature not available', $data['error_description'] );
107+
}
108+
109+
/**
110+
* Test server_error returns 500.
111+
*
112+
* @covers ::server_error
113+
*/
114+
public function test_server_error() {
115+
$response = Error::server_error();
116+
117+
$this->assertEquals( 500, $response->get_status() );
118+
119+
$data = $response->get_data();
120+
$this->assertEquals( 'server_error', $data['error'] );
121+
}
122+
123+
/**
124+
* Test generic response with custom error.
125+
*
126+
* @covers ::response
127+
*/
128+
public function test_generic_response() {
129+
$response = Error::response( 'custom_error', 'Custom description' );
130+
131+
$this->assertEquals( 400, $response->get_status() );
132+
133+
$data = $response->get_data();
134+
$this->assertEquals( 'custom_error', $data['error'] );
135+
$this->assertEquals( 'Custom description', $data['error_description'] );
136+
}
137+
138+
/**
139+
* Test response without description omits field.
140+
*
141+
* @covers ::response
142+
*/
143+
public function test_response_without_description() {
144+
$response = Error::response( 'invalid_request' );
145+
146+
$data = $response->get_data();
147+
$this->assertEquals( 'invalid_request', $data['error'] );
148+
$this->assertArrayNotHasKey( 'error_description', $data );
149+
}
150+
}

0 commit comments

Comments
 (0)