getProperty('instance'); $property->setAccessible(true); $this->assertEquals('lemmy.world', $property->getValue($service)); } public function test_login_with_https_success(): void { Http::fake([ 'https://lemmy.world/api/v3/user/login' => Http::response(['jwt' => 'test-token'], 200), ]); $service = new LemmyApiService('lemmy.world'); $token = $service->login('user', 'pass'); $this->assertEquals('test-token', $token); Http::assertSent(function ($request) { return $request->url() === 'https://lemmy.world/api/v3/user/login' && $request['username_or_email'] === 'user' && $request['password'] === 'pass'; }); } public function test_login_falls_back_to_http_on_https_failure(): void { Http::fake([ 'https://lemmy.world/api/v3/user/login' => Http::response('', 500), 'http://lemmy.world/api/v3/user/login' => Http::response(['jwt' => 'http-token'], 200), ]); $service = new LemmyApiService('lemmy.world'); $token = $service->login('user', 'pass'); $this->assertEquals('http-token', $token); Http::assertSentCount(2); } public function test_login_with_explicit_http_scheme(): void { Http::fake([ 'http://localhost/api/v3/user/login' => Http::response(['jwt' => 'local-token'], 200), ]); $service = new LemmyApiService('http://localhost'); $token = $service->login('user', 'pass'); $this->assertEquals('local-token', $token); Http::assertSent(function ($request) { return $request->url() === 'http://localhost/api/v3/user/login'; }); } public function test_login_with_explicit_https_scheme(): void { Http::fake([ 'https://secure.lemmy/api/v3/user/login' => Http::response(['jwt' => 'secure-token'], 200), ]); $service = new LemmyApiService('https://secure.lemmy'); $token = $service->login('user', 'pass'); $this->assertEquals('secure-token', $token); Http::assertSent(function ($request) { return $request->url() === 'https://secure.lemmy/api/v3/user/login'; }); } public function test_login_returns_null_on_unsuccessful_response(): void { Http::fake([ '*' => Http::response(['error' => 'Invalid credentials'], 401), ]); $service = new LemmyApiService('lemmy.world'); $token = $service->login('user', 'wrong'); $this->assertNull($token); } public function test_login_handles_rate_limit_error(): void { Http::fake([ '*' => Http::response('{"error":"rate_limit_error"}', 429), ]); $service = new LemmyApiService('lemmy.world'); $this->expectException(Exception::class); $this->expectExceptionMessage('Rate limited'); $service->login('user', 'pass'); } public function test_login_returns_null_when_jwt_missing_from_response(): void { Http::fake([ '*' => Http::response(['success' => true], 200), ]); $service = new LemmyApiService('lemmy.world'); $token = $service->login('user', 'pass'); $this->assertNull($token); } public function test_login_handles_exception_and_throws(): void { Http::fake(function () { throw new Exception('Network error'); }); $service = new LemmyApiService('lemmy.world'); $this->expectException(Exception::class); $this->expectExceptionMessage('Connection failed'); $service->login('user', 'pass'); } public function test_get_community_id_success(): void { Http::fake([ '*' => Http::response([ 'community_view' => [ 'community' => ['id' => 123], ], ], 200), ]); $service = new LemmyApiService('lemmy.world'); $id = $service->getCommunityId('test-community', 'token'); $this->assertEquals(123, $id); Http::assertSent(function ($request) { return str_contains($request->url(), '/api/v3/community') && str_contains($request->url(), 'name=test-community') && $request->header('Authorization')[0] === 'Bearer token'; }); } public function test_get_community_id_throws_on_unsuccessful_response(): void { Http::fake([ '*' => Http::response('Not found', 404), ]); $service = new LemmyApiService('lemmy.world'); $this->expectException(Exception::class); $this->expectExceptionMessage('Failed to fetch community: 404'); $service->getCommunityId('missing', 'token'); } public function test_get_community_id_throws_when_community_not_in_response(): void { Http::fake([ '*' => Http::response(['success' => true], 200), ]); $service = new LemmyApiService('lemmy.world'); $this->expectException(Exception::class); $this->expectExceptionMessage('Community not found'); $service->getCommunityId('test', 'token'); } public function test_sync_channel_posts_success(): void { Http::fake([ '*' => Http::response([ 'posts' => [ [ 'post' => [ 'id' => 1, 'url' => 'https://example.com/1', 'name' => 'Post 1', 'published' => '2024-01-01T00:00:00Z', ], ], [ 'post' => [ 'id' => 2, 'url' => 'https://example.com/2', 'name' => 'Post 2', 'published' => '2024-01-02T00:00:00Z', ], ], ], ], 200), ]); $service = new LemmyApiService('lemmy.world'); $service->syncChannelPosts('token', 42, 'test-community'); Http::assertSent(function ($request) { return str_contains($request->url(), '/api/v3/post/list') && str_contains($request->url(), 'community_id=42') && str_contains($request->url(), 'limit=50') && str_contains($request->url(), 'sort=New'); }); // Verify posts were stored in the database $this->assertDatabaseHas('platform_channel_posts', [ 'platform' => PlatformEnum::LEMMY->value, 'channel_id' => '42', 'channel_name' => 'test-community', 'post_id' => '1', 'url' => 'https://example.com/1', 'title' => 'Post 1', ]); $this->assertDatabaseHas('platform_channel_posts', [ 'platform' => PlatformEnum::LEMMY->value, 'channel_id' => '42', 'channel_name' => 'test-community', 'post_id' => '2', 'url' => 'https://example.com/2', 'title' => 'Post 2', ]); } public function test_sync_channel_posts_handles_unsuccessful_response(): void { Http::fake([ '*' => Http::response('Error', 500), ]); $service = new LemmyApiService('lemmy.world'); $service->syncChannelPosts('token', 42, 'test-community'); Http::assertSentCount(1); $this->assertDatabaseCount('platform_channel_posts', 0); } public function test_sync_channel_posts_handles_exception(): void { Http::fake(function () { throw new Exception('Network error'); }); $service = new LemmyApiService('lemmy.world'); $service->syncChannelPosts('token', 42, 'test-community'); // Assert that the method completes without throwing $this->assertTrue(true); } public function test_create_post_with_all_parameters(): void { Http::fake([ '*' => Http::response(['post_view' => ['post' => ['id' => 999]]], 200), ]); $service = new LemmyApiService('lemmy.world'); $result = $service->createPost( 'token', 'Test Title', 'Test Body', 42, 'https://example.com', 'https://example.com/thumb.jpg', 5 ); $this->assertEquals(['post_view' => ['post' => ['id' => 999]]], $result); Http::assertSent(function ($request) { $data = $request->data(); return $request->url() === 'https://lemmy.world/api/v3/post' && $data['name'] === 'Test Title' && $data['body'] === 'Test Body' && $data['community_id'] === 42 && $data['url'] === 'https://example.com' && $data['custom_thumbnail'] === 'https://example.com/thumb.jpg' && $data['language_id'] === 5; }); } public function test_create_post_with_minimal_parameters(): void { Http::fake([ '*' => Http::response(['post_view' => ['post' => ['id' => 888]]], 200), ]); $service = new LemmyApiService('lemmy.world'); $result = $service->createPost( 'token', 'Title Only', 'Body Only', 42 ); $this->assertEquals(['post_view' => ['post' => ['id' => 888]]], $result); Http::assertSent(function ($request) { $data = $request->data(); return $request->url() === 'https://lemmy.world/api/v3/post' && $data['name'] === 'Title Only' && $data['body'] === 'Body Only' && $data['community_id'] === 42 && ! isset($data['url']) && ! isset($data['custom_thumbnail']) && ! isset($data['language_id']); }); } public function test_create_post_throws_on_unsuccessful_response(): void { Http::fake([ '*' => Http::response('Forbidden', 403), ]); $service = new LemmyApiService('lemmy.world'); $this->expectException(Exception::class); $this->expectExceptionMessage('Failed to create post: 403'); $service->createPost('token', 'Title', 'Body', 42); } public function test_get_languages_success(): void { Http::fake([ '*' => Http::response([ 'all_languages' => [ ['id' => 1, 'code' => 'en', 'name' => 'English'], ['id' => 2, 'code' => 'fr', 'name' => 'French'], ], ], 200), ]); $service = new LemmyApiService('lemmy.world'); $languages = $service->getLanguages(); $this->assertCount(2, $languages); $this->assertEquals('en', $languages[0]['code']); $this->assertEquals('fr', $languages[1]['code']); Http::assertSent(function ($request) { return str_contains($request->url(), '/api/v3/site'); }); } public function test_get_languages_returns_empty_array_on_failure(): void { Http::fake([ '*' => Http::response('Error', 500), ]); $service = new LemmyApiService('lemmy.world'); $languages = $service->getLanguages(); $this->assertEquals([], $languages); } public function test_get_languages_handles_exception(): void { Http::fake(function () { throw new Exception('Network error'); }); $service = new LemmyApiService('lemmy.world'); $languages = $service->getLanguages(); $this->assertEquals([], $languages); } public function test_get_languages_returns_empty_when_all_languages_missing(): void { Http::fake([ '*' => Http::response(['site_view' => []], 200), ]); $service = new LemmyApiService('lemmy.world'); $languages = $service->getLanguages(); $this->assertEquals([], $languages); } }