make(); $this->assertSame( 'gitea', $p->get_id() ); $this->assertSame( 'Gitea', $p->get_label() ); } public function test_repo_data_normalizes_gitea_fields(): void { \Brain\Monkey\Functions\expect( 'wp_remote_get' ) ->once() ->with( 'https://codeberg.org/api/v1/repos/owner/repo', \Brain\Monkey\Actions\anyArgs() ) ->andReturn( [ 'response' => [ 'code' => 200 ], 'headers' => [], 'body' => json_encode( [ 'owner' => [ 'avatar_url' => 'https://codeberg.org/avatars/owner', 'login' => 'owner', 'html_url' => 'https://codeberg.org/owner', ], 'updated_at' => '2026-02-03T04:05:06Z', 'language' => 'PHP', 'license' => [ 'name' => 'MIT' ], 'stars_count' => 100, 'forks_count' => 10, 'open_issues_count' => 5, ] ), ] ); $data = $this->make()->get_repo_data(); $this->assertSame( 100, $data['stargazers_count'] ); $this->assertSame( 10, $data['forks_count'] ); $this->assertSame( 5, $data['open_issues_count'] ); $this->assertSame( 'MIT', $data['license']['name'] ); $this->assertSame( 'owner', $data['owner']['login'] ); } public function test_repo_data_handles_string_license(): void { \Brain\Monkey\Functions\expect( 'wp_remote_get' ) ->once() ->andReturn( [ 'response' => [ 'code' => 200 ], 'headers' => [], 'body' => json_encode( [ 'owner' => [], 'stars_count' => 0, 'forks_count' => 0, 'open_issues_count' => 0, 'license' => 'Apache-2.0', ] ), ] ); $data = $this->make()->get_repo_data(); $this->assertSame( 'Apache-2.0', $data['license']['name'] ); } public function test_repo_data_handles_null_license(): void { \Brain\Monkey\Functions\expect( 'wp_remote_get' ) ->once() ->andReturn( [ 'response' => [ 'code' => 200 ], 'headers' => [], 'body' => json_encode( [ 'owner' => [], 'stars_count' => 0, 'forks_count' => 0, 'open_issues_count' => 0, 'license' => null, ] ), ] ); $data = $this->make()->get_repo_data(); $this->assertSame( 'None', $data['license']['name'] ); } public function test_release_url_picks_zip_asset_from_first_release(): void { $body = json_encode( [ [ 'tag_name' => 'v2.0.0', 'assets' => [ [ 'name' => 'source.tar.gz', 'browser_download_url' => 'https://example/x.tar.gz' ], [ 'name' => 'release.zip', 'browser_download_url' => 'https://example/release.zip' ], ], ], ] ); \Brain\Monkey\Functions\expect( 'wp_remote_get' ) ->twice() ->andReturn( [ 'response' => [ 'code' => 200 ], 'headers' => [], 'body' => $body, ] ); $this->assertSame( 'https://example/release.zip', $this->make()->get_release_url() ); $this->assertSame( 'v2.0.0', $this->make()->get_latest_version() ); } public function test_release_url_falls_back_to_archive_url(): void { $body = json_encode( [ [ 'tag_name' => 'v0.1.0', 'assets' => [] ], ] ); \Brain\Monkey\Functions\expect( 'wp_remote_get' ) ->once() ->andReturn( [ 'response' => [ 'code' => 200 ], 'headers' => [], 'body' => $body, ] ); $this->assertSame( 'https://codeberg.org/owner/repo/archive/refs/tags/v0.1.0.zip', $this->make()->get_release_url() ); } public function test_release_object_shape_picks_first_tag_from_object(): void { // Gitea's /releases/latest returns a single release OBJECT (associative array), // not a list. The implementation must accept either shape. $body = json_encode( [ 'tag_name' => 'v2.1.0', 'name' => 'v2.1.0', 'assets' => [ [ 'name' => 'release.zip', 'browser_download_url' => 'https://example/release.zip' ], ], ] ); \Brain\Monkey\Functions\expect( 'wp_remote_get' ) ->twice() // get_release_url and get_latest_version both fetch ->andReturn( [ 'response' => [ 'code' => 200 ], 'headers' => [], 'body' => $body, ] ); $provider = $this->make(); $this->assertSame( 'https://example/release.zip', $provider->get_release_url() ); $this->assertSame( 'v2.1.0', $provider->get_latest_version() ); } public function test_release_url_empty_array_returns_null(): void { \Brain\Monkey\Functions\expect( 'wp_remote_get' ) ->once() ->andReturn( [ 'response' => [ 'code' => 200 ], 'headers' => [], 'body' => '[]', ] ); $this->assertNull( $this->make()->get_release_url() ); } public function test_repo_browse_url_is_built_from_base(): void { $this->assertSame( 'https://codeberg.org/owner/repo', $this->make()->get_repo_browse_url() ); } public function test_http_failure_returns_null(): void { \Brain\Monkey\Functions\expect( 'wp_remote_get' ) ->once() ->andReturn( new \WP_Error( 'http_error', 'boom' ) ); $this->assertNull( $this->make()->get_repo_data() ); } public function test_self_hosted_base_url_is_used(): void { $provider = new Gitea_Provider( 'https://git.example.org/owner/repo', 'https://git.example.org', '' ); $this->assertSame( 'https://git.example.org/owner/repo', $provider->get_repo_browse_url() ); } }