瀏覽代碼

API improvements + test fixes (#5925)

* migrate PHPUnit configuration

* replace @test annotations with #[Test] attributes, and add it where it was missing

* remove test prefix from test method names

* add PHPUnit cache to .gitignore

* Update ApiV1Controller, fix notifications favourited/reblogged/bookmarked state. Fixes #5901

* Update ApiV1Controller, fix relationship fields. Fixes #5900

* Update instance config, return proper matrix limits. Fixes #4780

* Update SearchApiV2Service, fix offset bug. Fixes #5875

* Update ApiV1Controller, add better direct error message. Fixes #4789

* Update changelog

---------

Co-authored-by: Daniel Simon <daniel.simon.dev@proton.me>
daniel 3 月之前
父節點
當前提交
0158941fb6

+ 2 - 0
.gitignore

@@ -10,6 +10,8 @@
 /.gitconfig
 #/.gitignore
 /.idea
+/.phpunit.cache
+/.phpunit.result.cache
 /.vagrant
 /bootstrap/cache
 /docker-compose-state/

+ 5 - 0
CHANGELOG.md

@@ -10,6 +10,11 @@
 - Update Profile.vue, fix pagination ([2ea107805](https://github.com/pixelfed/pixelfed/commit/2ea107805))
 - Update ProfileMigrationController, fix race condition by chaining batched jobs ([3001365025](https://github.com/pixelfed/pixelfed/commit/3001365025))
 - Update Instance total post, add optional estimation for huge status tables ([5a5821fe8](https://github.com/pixelfed/pixelfed/commit/5a5821fe8))
+- Update ApiV1Controller, fix notifications favourited/reblogged/bookmarked state. Fixes #5901 ([8a86808a0](https://github.com/pixelfed/pixelfed/commit/8a86808a0))
+- Update ApiV1Controller, fix relationship fields. Fixes #5900 ([245ab3bc4](https://github.com/pixelfed/pixelfed/commit/245ab3bc4))
+- Update instance config, return proper matrix limits. Fixes #4780 ([473201908](https://github.com/pixelfed/pixelfed/commit/473201908))
+- Update SearchApiV2Service, fix offset bug. Fixes #5875 ([0a98b7ad2](https://github.com/pixelfed/pixelfed/commit/0a98b7ad2))
+- Update ApiV1Controller, add better direct error message. Fixes #4789 ([658fe6898](https://github.com/pixelfed/pixelfed/commit/658fe6898))
 -  ([](https://github.com/pixelfed/pixelfed/commit/))
 
 ## [v0.12.5 (2025-03-23)](https://github.com/pixelfed/pixelfed/compare/v0.12.5...dev)

+ 18 - 3
app/Http/Controllers/Api/ApiV1Controller.php

@@ -1734,11 +1734,11 @@ class ApiV1Controller extends Controller
                 'mobile_registration' => (bool) config_cache('pixelfed.open_registration') && config('auth.in_app_registration'),
                 'configuration' => [
                     'media_attachments' => [
-                        'image_matrix_limit' => 16777216,
+                        'image_matrix_limit' => 2073600,
                         'image_size_limit' => config_cache('pixelfed.max_photo_size') * 1024,
                         'supported_mime_types' => explode(',', config_cache('pixelfed.media_types')),
                         'video_frame_rate_limit' => 120,
-                        'video_matrix_limit' => 2304000,
+                        'video_matrix_limit' => 2073600,
                         'video_size_limit' => config_cache('pixelfed.max_photo_size') * 1024,
                     ],
                     'polls' => [
@@ -2441,6 +2441,15 @@ class ApiV1Controller extends Controller
 
                 return true;
             })
+            ->map(function ($n) use ($pid) {
+                if (isset($n['status'])) {
+                    $n['status']['favourited'] = (bool) LikeService::liked($pid, $n['status']['id']);
+                    $n['status']['reblogged'] = (bool) ReblogService::get($pid, $n['status']['id']);
+                    $n['status']['bookmarked'] = (bool) BookmarkService::get($pid, $n['status']['id']);
+                }
+
+                return $n;
+            })
             ->filter(function ($n) use ($types) {
                 if (! $types) {
                     return true;
@@ -3516,13 +3525,19 @@ class ApiV1Controller extends Controller
             'in_reply_to_id' => 'nullable',
             'media_ids' => 'sometimes|array|max:'.(int) config_cache('pixelfed.max_album_length'),
             'sensitive' => 'nullable',
-            'visibility' => 'string|in:private,unlisted,public',
+            'visibility' => 'string|in:private,unlisted,public,direct',
             'spoiler_text' => 'sometimes|max:140',
             'place_id' => 'sometimes|integer|min:1|max:128769',
             'collection_ids' => 'sometimes|array|max:3',
             'comments_disabled' => 'sometimes|boolean',
         ]);
 
+        if ($request->filled('visibility') && $request->input('visibility') === 'direct') {
+            return $this->json([
+                'error' => 'Direct visibility is not available.',
+            ], 400);
+        }
+
         if ($request->hasHeader('idempotency-key')) {
             $key = 'pf:api:v1:status:idempotency-key:'.$request->user()->id.':'.hash('sha1', $request->header('idempotency-key'));
             $exists = Cache::has($key);

+ 7 - 7
app/Http/Controllers/Api/ApiV2Controller.php

@@ -101,10 +101,10 @@ class ApiV2Controller extends Controller
                     'media_attachments' => [
                         'supported_mime_types' => explode(',', config_cache('pixelfed.media_types')),
                         'image_size_limit' => config_cache('pixelfed.max_photo_size') * 1024,
-                        'image_matrix_limit' => 3686400,
+                        'image_matrix_limit' => 2073600,
                         'video_size_limit' => config_cache('pixelfed.max_photo_size') * 1024,
-                        'video_frame_rate_limit' => 240,
-                        'video_matrix_limit' => 3686400,
+                        'video_frame_rate_limit' => 120,
+                        'video_matrix_limit' => 2073600,
                     ],
                     'polls' => [
                         'max_options' => 0,
@@ -292,7 +292,7 @@ class ApiV2Controller extends Controller
             }
         }
 
-        $media = new Media();
+        $media = new Media;
         $media->status_id = null;
         $media->profile_id = $profile->id;
         $media->user_id = $user->id;
@@ -326,9 +326,9 @@ class ApiV2Controller extends Controller
         $user->save();
 
         Cache::forget($limitKey);
-        $fractal = new Fractal\Manager();
-        $fractal->setSerializer(new ArraySerializer());
-        $resource = new Fractal\Resource\Item($media, new MediaTransformer());
+        $fractal = new Fractal\Manager;
+        $fractal->setSerializer(new ArraySerializer);
+        $resource = new Fractal\Resource\Item($media, new MediaTransformer);
         $res = $fractal->createData($resource)->toArray();
         $res['preview_url'] = $media->url().'?v='.time();
         $res['url'] = null;

+ 103 - 99
app/Services/RelationshipService.php

@@ -2,116 +2,120 @@
 
 namespace App\Services;
 
-use Illuminate\Support\Facades\Cache;
 use App\Follower;
 use App\FollowRequest;
-use App\Profile;
 use App\UserFilter;
+use Illuminate\Support\Facades\Cache;
 
 class RelationshipService
 {
-	const CACHE_KEY = 'pf:services:urel:';
-
-	public static function get($aid, $tid)
-	{
-		$actor = AccountService::get($aid, true);
-		$target = AccountService::get($tid, true);
-		if(!$actor || !$target) {
-			return self::defaultRelation($tid);
-		}
-
-		if($actor['id'] === $target['id']) {
-			return self::defaultRelation($tid);
-		}
-
-		return Cache::remember(self::key("a_{$aid}:t_{$tid}"), 1209600, function() use($aid, $tid) {
-			return [
-				'id' => (string) $tid,
-				'following' => Follower::whereProfileId($aid)->whereFollowingId($tid)->exists(),
-				'followed_by' => Follower::whereProfileId($tid)->whereFollowingId($aid)->exists(),
-				'blocking' => UserFilter::whereUserId($aid)
-					->whereFilterableType('App\Profile')
-					->whereFilterableId($tid)
-					->whereFilterType('block')
-					->exists(),
-				'muting' => UserFilter::whereUserId($aid)
-					->whereFilterableType('App\Profile')
-					->whereFilterableId($tid)
-					->whereFilterType('mute')
-					->exists(),
-				'muting_notifications' => null,
-				'requested' => FollowRequest::whereFollowerId($aid)
-					->whereFollowingId($tid)
-					->exists(),
-				'domain_blocking' => null,
-				'showing_reblogs' => null,
-				'endorsed' => false
-			];
-		});
-	}
-
-	public static function delete($aid, $tid)
-	{
-		Cache::forget(self::key("wd:a_{$aid}:t_{$tid}"));
-		return Cache::forget(self::key("a_{$aid}:t_{$tid}"));
-	}
-
-	public static function refresh($aid, $tid)
-	{
-		Cache::forget('pf:services:follower:audience:' . $aid);
-		Cache::forget('pf:services:follower:audience:' . $tid);
-		self::delete($tid, $aid);
-		self::delete($aid, $tid);
-		self::get($tid, $aid);
-		return self::get($aid, $tid);
-	}
-
-	public static function forget($aid, $tid)
-	{
-		Cache::forget('pf:services:follower:audience:' . $aid);
-		Cache::forget('pf:services:follower:audience:' . $tid);
-		self::delete($tid, $aid);
-		self::delete($aid, $tid);
-	}
-
-	public static function defaultRelation($tid)
-	{
-		return [
+    const CACHE_KEY = 'pf:services:urel:';
+
+    public static function get($aid, $tid)
+    {
+        $actor = AccountService::get($aid, true);
+        $target = AccountService::get($tid, true);
+        if (! $actor || ! $target) {
+            return self::defaultRelation($tid);
+        }
+
+        if ($actor['id'] === $target['id']) {
+            return self::defaultRelation($tid);
+        }
+
+        return Cache::remember(self::key("a_{$aid}:t_{$tid}"), 1209600, function () use ($aid, $tid) {
+            return [
+                'id' => (string) $tid,
+                'following' => Follower::whereProfileId($aid)->whereFollowingId($tid)->exists(),
+                'followed_by' => Follower::whereProfileId($tid)->whereFollowingId($aid)->exists(),
+                'blocking' => UserFilter::whereUserId($aid)
+                    ->whereFilterableType('App\Profile')
+                    ->whereFilterableId($tid)
+                    ->whereFilterType('block')
+                    ->exists(),
+                'muting' => UserFilter::whereUserId($aid)
+                    ->whereFilterableType('App\Profile')
+                    ->whereFilterableId($tid)
+                    ->whereFilterType('mute')
+                    ->exists(),
+                'muting_notifications' => false,
+                'requested' => FollowRequest::whereFollowerId($aid)
+                    ->whereFollowingId($tid)
+                    ->exists(),
+                'domain_blocking' => false,
+                'showing_reblogs' => false,
+                'endorsed' => false,
+            ];
+        });
+    }
+
+    public static function delete($aid, $tid)
+    {
+        Cache::forget(self::key("wd:a_{$aid}:t_{$tid}"));
+
+        return Cache::forget(self::key("a_{$aid}:t_{$tid}"));
+    }
+
+    public static function refresh($aid, $tid)
+    {
+        Cache::forget('pf:services:follower:audience:'.$aid);
+        Cache::forget('pf:services:follower:audience:'.$tid);
+        self::delete($tid, $aid);
+        self::delete($aid, $tid);
+        self::get($tid, $aid);
+
+        return self::get($aid, $tid);
+    }
+
+    public static function forget($aid, $tid)
+    {
+        Cache::forget('pf:services:follower:audience:'.$aid);
+        Cache::forget('pf:services:follower:audience:'.$tid);
+        self::delete($tid, $aid);
+        self::delete($aid, $tid);
+    }
+
+    public static function defaultRelation($tid)
+    {
+        return [
             'id' => (string) $tid,
             'following' => false,
             'followed_by' => false,
             'blocking' => false,
             'muting' => false,
-            'muting_notifications' => null,
+            'muting_notifications' => false,
             'requested' => false,
-            'domain_blocking' => null,
-            'showing_reblogs' => null,
-            'endorsed' => false
+            'domain_blocking' => false,
+            'showing_reblogs' => false,
+            'endorsed' => false,
         ];
-	}
-
-	protected static function key($suffix)
-	{
-		return self::CACHE_KEY . $suffix;
-	}
-
-	public static function getWithDate($aid, $tid)
-	{
-		$res = self::get($aid, $tid);
-
-		if(!$res || !$res['following']) {
-			$res['following_since'] = null;
-			return $res;
-		}
-
-		return Cache::remember(self::key("wd:a_{$aid}:t_{$tid}"), 1209600, function() use($aid, $tid, $res) {
-			$tmp = Follower::whereProfileId($aid)->whereFollowingId($tid)->first();
-			if(!$tmp) {
-				$res['following_since'] = null;
-				return $res;
-			}
-			$res['following_since'] = str_replace('+00:00', 'Z', $tmp->created_at->format(DATE_RFC3339_EXTENDED));
-			return $res;
-		});
-	}
+    }
+
+    protected static function key($suffix)
+    {
+        return self::CACHE_KEY.$suffix;
+    }
+
+    public static function getWithDate($aid, $tid)
+    {
+        $res = self::get($aid, $tid);
+
+        if (! $res || ! $res['following']) {
+            $res['following_since'] = null;
+
+            return $res;
+        }
+
+        return Cache::remember(self::key("wd:a_{$aid}:t_{$tid}"), 1209600, function () use ($aid, $tid, $res) {
+            $tmp = Follower::whereProfileId($aid)->whereFollowingId($tid)->first();
+            if (! $tmp) {
+                $res['following_since'] = null;
+
+                return $res;
+            }
+            $res['following_since'] = str_replace('+00:00', 'Z', $tmp->created_at->format(DATE_RFC3339_EXTENDED));
+
+            return $res;
+        });
+    }
 }

+ 15 - 3
app/Services/SearchApiV2Service.php

@@ -132,7 +132,6 @@ class SearchApiV2Service
         $q = $this->query->input('q');
         $limit = $this->query->input('limit') ?? 20;
         $offset = $this->query->input('offset') ?? 0;
-
         $query = Str::startsWith($q, '#') ? substr($q, 1) : $q;
         $query = $query.'%';
 
@@ -214,6 +213,9 @@ class SearchApiV2Service
         $user = request()->user();
         $mastodonMode = self::$mastodonMode;
         $query = urldecode($this->query->input('q'));
+        $limit = $this->query->input('limit') ?? 20;
+        $offset = $this->query->input('offset') ?? 0;
+
         $banned = InstanceService::getBannedDomains();
         $domainBlocks = UserFilterService::domainBlocks($user->profile_id);
         if ($domainBlocks && count($domainBlocks)) {
@@ -252,7 +254,12 @@ class SearchApiV2Service
                     if (in_array($domain, $banned)) {
                         return $default;
                     }
-                    $default['accounts'][] = $res;
+                    $paginated = collect($res)->take($limit)->skip($offset)->toArray();
+                    if (! empty($paginated)) {
+                        $default['accounts'][] = $paginated;
+                    } else {
+                        $default['accounts'] = [];
+                    }
 
                     return $default;
                 } else {
@@ -271,7 +278,12 @@ class SearchApiV2Service
                     if (in_array($domain, $banned)) {
                         return $default;
                     }
-                    $default['accounts'][] = $res;
+                    $paginated = collect($res)->take($limit)->skip($offset)->toArray();
+                    if (! empty($paginated)) {
+                        $default['accounts'][] = $paginated;
+                    } else {
+                        $default['accounts'] = [];
+                    }
 
                     return $default;
                 } else {

+ 17 - 10
app/Transformer/Api/RelationshipTransformer.php

@@ -2,11 +2,10 @@
 
 namespace App\Transformer\Api;
 
+use App\FollowRequest;
+use App\Models\UserDomainBlock;
+use App\Profile;
 use Auth;
-use App\{
-    FollowRequest,
-    Profile
-};
 use League\Fractal;
 
 class RelationshipTransformer extends Fractal\TransformerAbstract
@@ -14,27 +13,35 @@ class RelationshipTransformer extends Fractal\TransformerAbstract
     public function transform(Profile $profile)
     {
         $auth = Auth::check();
-        if(!$auth) {
+        if (! $auth) {
             return [];
         }
         $user = $auth ? Auth::user()->profile : false;
         $requested = false;
-        if($user) {
+        $domainBlocking = false;
+        if ($user) {
             $requested = FollowRequest::whereFollowerId($user->id)
                 ->whereFollowingId($profile->id)
                 ->exists();
+
+            if ($profile->domain) {
+                $domainBlocking = UserDomainBlock::whereProfileId($user->id)
+                    ->whereDomain($profile->domain)
+                    ->exists();
+            }
         }
+
         return [
             'id' => (string) $profile->id,
             'following' => $auth ? $user->follows($profile) : false,
             'followed_by' => $auth ? $user->followedBy($profile) : false,
             'blocking' => $auth ? $user->blockedIds()->contains($profile->id) : false,
             'muting' => $auth ? $user->mutedIds()->contains($profile->id) : false,
-            'muting_notifications' => null,
+            'muting_notifications' => false,
             'requested' => $requested,
-            'domain_blocking' => null,
-            'showing_reblogs' => null,
-            'endorsed' => false
+            'domain_blocking' => $domainBlocking,
+            'showing_reblogs' => false,
+            'endorsed' => false,
         ];
     }
 }

+ 11 - 13
phpunit.xml

@@ -1,20 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-    backupGlobals="false" 
-    backupStaticAttributes="false" 
-    bootstrap="vendor/autoload.php" 
-    colors="true" 
-    convertErrorsToExceptions="true" 
-    convertNoticesToExceptions="true" 
-    convertWarningsToExceptions="true" 
-    processIsolation="false" 
-    stopOnFailure="false" 
-    xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
-  <coverage processUncoveredFiles="true">
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    backupGlobals="false"
+    backupStaticProperties="false"
+    bootstrap="vendor/autoload.php"
+    colors="true"
+    processIsolation="false"
+    stopOnFailure="false"
+    cacheDirectory=".phpunit.cache"
+    xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.5/phpunit.xsd">
+  <source>
     <include>
       <directory suffix=".php">./app</directory>
     </include>
-  </coverage>
+  </source>
   <testsuites>
     <testsuite name="Feature">
       <directory suffix="Test.php">./tests/Feature</directory>

+ 2 - 1
tests/Feature/LoginTest.php

@@ -2,11 +2,12 @@
 
 namespace Tests\Feature;
 
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class LoginTest extends TestCase
 {
-    /** @test */
+    #[Test]
     public function view_login_page()
     {
         $response = $this->get('login');

+ 13 - 6
tests/Unit/APAnnounceStrategyTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit;
 
 use App\Util\ActivityPub\Helpers;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class APAnnounceStrategyTest extends TestCase
@@ -26,22 +27,26 @@ class APAnnounceStrategyTest extends TestCase
         $this->pleroma = json_decode('{"@context":"https://www.w3.org/ns/activitystreams","actor":"https://pleroma.site/users/pixeldev","cc":["https://www.w3.org/ns/activitystreams#Public"],"context":"tag:mastodon.social,2018-10-14:objectId=59146153:objectType=Conversation","context_id":12325955,"id":"https://pleroma.site/activities/db2273eb-d504-4e3a-8f74-c343d069755a","object":"https://mastodon.social/users/dansup/statuses/100891324792793720","published":"2018-10-14T01:22:18.554227Z","to":["https://pleroma.site/users/pixeldev/followers","https://mastodon.social/users/dansup"],"type":"Announce"}', true);
     }
 
-    public function testBasicValidation()
+    #[Test]
+    public function basicValidation()
     {
         $this->assertFalse(Helpers::validateObject($this->invalid));
     }
 
-    public function testMastodonValidation()
+    #[Test]
+    public function mastodonValidation()
     {
         $this->assertTrue(Helpers::validateObject($this->mastodon));
     }
 
-    public function testPleromaValidation()
+    #[Test]
+    public function pleromaValidation()
     {
         $this->assertTrue(Helpers::validateObject($this->pleroma));
     }
 
-    public function testMastodonAudienceScope()
+    #[Test]
+    public function mastodonAudienceScope()
     {
         $scope = Helpers::normalizeAudience($this->mastodon, false);
         $actual = [
@@ -56,7 +61,8 @@ class APAnnounceStrategyTest extends TestCase
         $this->assertEquals($scope, $actual);
     }
 
-    public function testPleromaAudienceScope()
+    #[Test]
+    public function pleromaAudienceScope()
     {
         $scope = Helpers::normalizeAudience($this->pleroma, false);
         $actual = [
@@ -71,7 +77,8 @@ class APAnnounceStrategyTest extends TestCase
         $this->assertEquals($scope, $actual);
     }
 
-    public function testInvalidAudienceScope()
+    #[Test]
+    public function invalidAudienceScope()
     {
         $scope = Helpers::normalizeAudience($this->invalid, false);
         $actual = [

+ 13 - 6
tests/Unit/ActivityPub/AudienceScopeTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit\ActivityPub;
 
 use App\Util\ActivityPub\Helpers;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class AudienceScopeTest extends TestCase
@@ -28,22 +29,26 @@ class AudienceScopeTest extends TestCase
         $this->pleroma = json_decode('{"@context":"https://www.w3.org/ns/activitystreams","actor":"https://pleroma.site/users/pixeldev","cc":["https://www.w3.org/ns/activitystreams#Public"],"context":"tag:mastodon.social,2018-10-14:objectId=59146153:objectType=Conversation","context_id":12325955,"id":"https://pleroma.site/activities/db2273eb-d504-4e3a-8f74-c343d069755a","object":"https://mastodon.social/users/dansup/statuses/100891324792793720","published":"2018-10-14T01:22:18.554227Z","to":["https://pleroma.site/users/pixeldev/followers","https://mastodon.social/users/dansup"],"type":"Announce"}', true);
     }
 
-    public function testBasicValidation()
+    #[Test]
+    public function basicValidation()
     {
         $this->assertFalse(Helpers::validateObject($this->invalid));
     }
 
-    public function testMastodonValidation()
+    #[Test]
+    public function mastodonValidation()
     {
         $this->assertTrue(Helpers::validateObject($this->mastodon));
     }
 
-    public function testPleromaValidation()
+    #[Test]
+    public function pleromaValidation()
     {
         $this->assertTrue(Helpers::validateObject($this->pleroma));
     }
 
-    public function testMastodonAudienceScope()
+    #[Test]
+    public function mastodonAudienceScope()
     {
         $scope = Helpers::normalizeAudience($this->mastodon, false);
         $actual = [
@@ -58,7 +63,8 @@ class AudienceScopeTest extends TestCase
         $this->assertEquals($scope, $actual);
     }
 
-    public function testPleromaAudienceScope()
+    #[Test]
+    public function pleromaAudienceScope()
     {
         $scope = Helpers::normalizeAudience($this->pleroma, false);
         $actual = [
@@ -73,7 +79,8 @@ class AudienceScopeTest extends TestCase
         $this->assertEquals($scope, $actual);
     }
 
-    public function testInvalidAudienceScope()
+    #[Test]
+    public function invalidAudienceScope()
     {
         $scope = Helpers::normalizeAudience($this->invalid, false);
         $actual = [

+ 9 - 4
tests/Unit/ActivityPub/NoteAttachmentTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit\ActivityPub;
 
 use App\Util\ActivityPub\Helpers;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class NoteAttachmentTest extends TestCase
@@ -28,25 +29,29 @@ class NoteAttachmentTest extends TestCase
         $this->invalidMime = json_decode('{"id":"https://mastodon.social/users/dansup/statuses/100889802384218791/activity","type":"Create","actor":"https://mastodon.social/users/dansup","published":"2018-10-13T18:43:33Z","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://mastodon.social/users/dansup/followers"],"object":{"id":"https://mastodon.social/users/dansup/statuses/100889802384218791","type":"Note","summary":null,"inReplyTo":null,"published":"2018-10-13T18:43:33Z","url":"https://mastodon.social/@dansup/100889802384218791","attributedTo":"https://mastodon.social/users/dansup","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://mastodon.social/users/dansup/followers"],"sensitive":false,"atomUri":"https://mastodon.social/users/dansup/statuses/100889802384218791","inReplyToAtomUri":null,"conversation":"tag:mastodon.social,2018-10-13:objectId=59103420:objectType=Conversation","content":"<p>Good Morning! <a href=\"https://mastodon.social/tags/coffee\" class=\"mention hashtag\" rel=\"tag\">#<span>coffee</span></a></p>","contentMap":{"en":"<p>Good Morning! <a href=\"https://mastodon.social/tags/coffee\" class=\"mention hashtag\" rel=\"tag\">#<span>coffee</span></a></p>"},"attachment":[{"type":"Document","mediaType":"image/webp","url":"https://files.mastodon.social/media_attachments/files/007/110/573/original/96a196885a77c9a4.jpg","name":null}],"tag":[{"type":"Hashtag","href":"https://mastodon.social/tags/coffee","name":"#coffee"}]}}', true, 9);
     }
 
-    public function testPixelfed()
+    #[Test]
+    public function pixelfed()
     {
         $valid = Helpers::verifyAttachments($this->pixelfed);
         $this->assertTrue($valid);
     }
 
-    public function testMastodon()
+    #[Test]
+    public function mastodon()
     {
         $valid = Helpers::verifyAttachments($this->mastodon);
         $this->assertTrue($valid);
     }
 
-    public function testInvalidAttachmentType()
+    #[Test]
+    public function invalidAttachmentType()
     {
         $valid = Helpers::verifyAttachments($this->invalidType);
         $this->assertFalse($valid);
     }
 
-    public function testInvalidMimeType()
+    #[Test]
+    public function invalidMimeType()
     {
         $valid = Helpers::verifyAttachments($this->invalidMime);
         $this->assertFalse($valid);

+ 2 - 1
tests/Unit/ActivityPub/RemoteFollowTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit\ActivityPub;
 
 use App\Util\ActivityPub\Helpers;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class RemoteFollowTest extends TestCase
@@ -17,7 +18,7 @@ class RemoteFollowTest extends TestCase
 
     }
 
-    /** @test */
+    #[Test]
     public function validateMastodonFollowObject()
     {
         $mastodon = json_decode($this->mastodon, true);

+ 9 - 8
tests/Unit/ActivityPub/StoryValidationTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit\ActivityPub;
 
 use App\Util\ActivityPub\Validator\StoryValidator;
+use PHPUnit\Framework\Attributes\Test;
 use PHPUnit\Framework\TestCase;
 
 class StoryValidationTest extends TestCase
@@ -16,13 +17,13 @@ class StoryValidationTest extends TestCase
         $this->activity = json_decode('{"@context":"https://www.w3.org/ns/activitystreams","id":"https://pixelfed.test/stories/dansup/338581222496276480","type":"Story","to":["https://pixelfed.test/users/dansup/followers"],"cc":[],"attributedTo":"https://pixelfed.test/users/dansup","published":"2021-09-01T07:20:53+00:00","expiresAt":"2021-09-02T07:21:04+00:00","duration":3,"can_reply":true,"can_react":true,"attachment":{"type":"Image","url":"https://pixelfed.test/storage/_esm.t3/xV9/R2LF1xwhAA/011oqKVPDySG3WCPW7yIs2wobvccoITMnG/yT_FZX04f2DCzTA3K8HD2OS7FptXTHPiE1c_ZkHASBQ8UlPKH4.jpg","mediaType":"image/jpeg"}}', true);
     }
 
-    /** @test */
+    #[Test]
     public function schemaTest()
     {
         $this->assertTrue(StoryValidator::validate($this->activity));
     }
 
-    /** @test */
+    #[Test]
     public function invalidContext()
     {
         $activity = $this->activity;
@@ -31,7 +32,7 @@ class StoryValidationTest extends TestCase
         $this->assertFalse(StoryValidator::validate($activity));
     }
 
-    /** @test */
+    #[Test]
     public function missingContext()
     {
         $activity = $this->activity;
@@ -39,7 +40,7 @@ class StoryValidationTest extends TestCase
         $this->assertFalse(StoryValidator::validate($activity));
     }
 
-    /** @test */
+    #[Test]
     public function missingId()
     {
         $activity = $this->activity;
@@ -47,7 +48,7 @@ class StoryValidationTest extends TestCase
         $this->assertFalse(StoryValidator::validate($activity));
     }
 
-    /** @test */
+    #[Test]
     public function missingType()
     {
         $activity = $this->activity;
@@ -55,7 +56,7 @@ class StoryValidationTest extends TestCase
         $this->assertFalse(StoryValidator::validate($activity));
     }
 
-    /** @test */
+    #[Test]
     public function invalidType()
     {
         $activity = $this->activity;
@@ -63,7 +64,7 @@ class StoryValidationTest extends TestCase
         $this->assertFalse(StoryValidator::validate($activity));
     }
 
-    /** @test */
+    #[Test]
     public function missingTo()
     {
         $activity = $this->activity;
@@ -71,7 +72,7 @@ class StoryValidationTest extends TestCase
         $this->assertFalse(StoryValidator::validate($activity));
     }
 
-    /** @test */
+    #[Test]
     public function missingTimestamps()
     {
         $activity = $this->activity;

File diff suppressed because it is too large
+ 1 - 0
tests/Unit/ActivityPub/UpdatePersonValidationTest.php


+ 4 - 3
tests/Unit/ActivityPub/Verb/AcceptVerbTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit\ActivityPub\Verb;
 
 use App\Util\ActivityPub\Validator\Accept;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class AcceptVerbTest extends TestCase
@@ -77,19 +78,19 @@ class AcceptVerbTest extends TestCase
         ];
     }
 
-    /** @test */
+    #[Test]
     public function basic_accept()
     {
         $this->assertTrue(Accept::validate($this->validAccept));
     }
 
-    /** @test */
+    #[Test]
     public function invalid_accept()
     {
         $this->assertFalse(Accept::validate($this->invalidAccept));
     }
 
-    /** @test */
+    #[Test]
     public function mastodon_accept()
     {
         $this->assertTrue(Accept::validate($this->mastodonAccept));

+ 6 - 5
tests/Unit/ActivityPub/Verb/AnnounceTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit\ActivityPub\Verb;
 
 use App\Util\ActivityPub\Validator\Announce;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class AnnounceTest extends TestCase
@@ -138,32 +139,32 @@ class AnnounceTest extends TestCase
         ];
     }
 
-    /** @test */
+    #[Test]
     public function basic_accept()
     {
         $this->assertTrue(Announce::validate($this->validAnnounce));
     }
 
-    /** @test */
+    #[Test]
     public function invalid_accept()
     {
         $this->assertFalse(Announce::validate($this->invalidAnnounce));
     }
 
-    /** @test */
+    #[Test]
     public function context_missing()
     {
         $this->assertFalse(Announce::validate($this->contextMissing));
     }
 
-    /** @test */
+    #[Test]
     public function invalid_actor()
     {
         $this->assertFalse(Announce::validate($this->invalidActor));
         $this->assertFalse(Announce::validate($this->invalidActor2));
     }
 
-    /** @test */
+    #[Test]
     public function mastodon_announce()
     {
         $this->assertTrue(Announce::validate($this->mastodonAnnounce));

+ 2 - 1
tests/Unit/ActivityPub/Verb/FollowTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit\ActivityPub\Verb;
 
 use App\Util\ActivityPub\Validator\Follow;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class FollowTest extends TestCase
@@ -44,7 +45,7 @@ class FollowTest extends TestCase
         ];
     }
 
-    /** @test */
+    #[Test]
     public function basic_follow()
     {
         $this->assertTrue(Follow::validate($this->basicFollow));

+ 2 - 1
tests/Unit/ActivityPub/Verb/LikeTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit\ActivityPub\Verb;
 
 use App\Util\ActivityPub\Validator\Like;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class LikeTest extends TestCase
@@ -44,7 +45,7 @@ class LikeTest extends TestCase
         ];
     }
 
-    /** @test */
+    #[Test]
     public function basic_like()
     {
         $this->assertTrue(Like::validate($this->basicLike));

+ 3 - 2
tests/Unit/ActivityPub/Verb/UndoFollowTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit\ActivityPub\Verb;
 
 use App\Util\ActivityPub\Validator\UndoFollow;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class UndoFollowTest extends TestCase
@@ -28,13 +29,13 @@ class UndoFollowTest extends TestCase
         ];
     }
 
-    /** @test */
+    #[Test]
     public function valid_undo_follow()
     {
         $this->assertTrue(UndoFollow::validate($this->validUndo));
     }
 
-    /** @test */
+    #[Test]
     public function invalid_undo_follow()
     {
         $this->assertFalse(UndoFollow::validate($this->invalidUndo));

+ 7 - 4
tests/Unit/ActivityPubTagObjectTest.php

@@ -2,6 +2,7 @@
 
 namespace Tests\Unit;
 
+use PHPUnit\Framework\Attributes\Test;
 use PHPUnit\Framework\TestCase;
 
 class ActivityPubTagObjectTest extends TestCase
@@ -9,7 +10,8 @@ class ActivityPubTagObjectTest extends TestCase
     /**
      * A basic unit test example.
      */
-    public function test_gotosocial(): void
+    #[Test]
+    public function gotosocial(): void
     {
         $res = [
             "tag" => [
@@ -33,7 +35,8 @@ class ActivityPubTagObjectTest extends TestCase
         $this->assertTrue($tags->count() === 1);
     }
 
-    public function test_pixelfed_hashtags(): void
+    #[Test]
+    public function pixelfed_hashtags(): void
     {
         $res = [
             "tag" => [
@@ -94,8 +97,8 @@ class ActivityPubTagObjectTest extends TestCase
         $this->assertTrue($tags->count() === 7);
     }
 
-
-    public function test_pixelfed_mentions(): void
+    #[Test]
+    public function pixelfed_mentions(): void
     {
         $res = [
             "tag" => [

+ 9 - 8
tests/Unit/BearcapTest.php

@@ -3,11 +3,12 @@
 namespace Tests\Unit;
 
 use App\Util\Lexer\Bearcap;
+use PHPUnit\Framework\Attributes\Test;
 use PHPUnit\Framework\TestCase;
 
 class BearcapTest extends TestCase
 {
-    /** @test */
+    #[Test]
     public function validTest()
     {
         $str = 'bear:?t=LpVypnEUdHhwwgXE9tTqEwrtPvmLjqYaPexqyXnVo1flSfJy5AYMCdRPiFRmqld2&u=https://pixelfed.test/stories/admin/337892163734081536';
@@ -19,7 +20,7 @@ class BearcapTest extends TestCase
         $this->assertEquals($expected, $actual);
     }
 
-    /** @test */
+    #[Test]
     public function invalidTokenParameterName()
     {
         $str = 'bear:?token=LpVypnEUdHhwwgXE9tTqEwrtPvmLjqYaPexqyXnVo1flSfJy5AYMCdRPiFRmqld2&u=https://pixelfed.test/stories/admin/337892163734081536';
@@ -27,7 +28,7 @@ class BearcapTest extends TestCase
         $this->assertFalse($actual);
     }
 
-    /** @test */
+    #[Test]
     public function invalidUrlParameterName()
     {
         $str = 'bear:?t=LpVypnEUdHhwwgXE9tTqEwrtPvmLjqYaPexqyXnVo1flSfJy5AYMCdRPiFRmqld2&url=https://pixelfed.test/stories/admin/337892163734081536';
@@ -35,7 +36,7 @@ class BearcapTest extends TestCase
         $this->assertFalse($actual);
     }
 
-    /** @test */
+    #[Test]
     public function invalidScheme()
     {
         $str = 'bearcap:?t=LpVypnEUdHhwwgXE9tTqEwrtPvmLjqYaPexqyXnVo1flSfJy5AYMCdRPiFRmqld2&url=https://pixelfed.test/stories/admin/337892163734081536';
@@ -43,7 +44,7 @@ class BearcapTest extends TestCase
         $this->assertFalse($actual);
     }
 
-    /** @test */
+    #[Test]
     public function missingToken()
     {
         $str = 'bear:?u=https://pixelfed.test/stories/admin/337892163734081536';
@@ -51,7 +52,7 @@ class BearcapTest extends TestCase
         $this->assertFalse($actual);
     }
 
-    /** @test */
+    #[Test]
     public function missingUrl()
     {
         $str = 'bear:?t=LpVypnEUdHhwwgXE9tTqEwrtPvmLjqYaPexqyXnVo1flSfJy5AYMCdRPiFRmqld2';
@@ -59,7 +60,7 @@ class BearcapTest extends TestCase
         $this->assertFalse($actual);
     }
 
-    /** @test */
+    #[Test]
     public function invalidHttpUrl()
     {
         $str = 'bear:?t=LpVypnEUdHhwwgXE9tTqEwrtPvmLjqYaPexqyXnVo1flSfJy5AYMCdRPiFRmqld2&u=http://pixelfed.test/stories/admin/337892163734081536';
@@ -67,7 +68,7 @@ class BearcapTest extends TestCase
         $this->assertFalse($actual);
     }
 
-    /** @test */
+    #[Test]
     public function invalidUrlSchema()
     {
         $str = 'bear:?t=LpVypnEUdHhwwgXE9tTqEwrtPvmLjqYaPexqyXnVo1flSfJy5AYMCdRPiFRmqld2&u=phar://pixelfed.test/stories/admin/337892163734081536';

+ 5 - 2
tests/Unit/CryptoTest.php

@@ -3,6 +3,7 @@
 namespace Tests\Unit;
 
 use phpseclib\Crypt\RSA;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class CryptoTest extends TestCase
@@ -12,12 +13,14 @@ class CryptoTest extends TestCase
      *
      * @return void
      */
-    public function testLibraryInstalled()
+    #[Test]
+    public function libraryInstalled()
     {
         $this->assertTrue(class_exists('\phpseclib\Crypt\RSA'));
     }
 
-    public function testRSASigning()
+    #[Test]
+    public function RSASigning()
     {
         $rsa = new RSA();
         extract($rsa->createKey());

+ 2 - 1
tests/Unit/Lexer/RestrictedNameTest.php

@@ -3,11 +3,12 @@
 namespace Tests\Unit\Lexer;
 
 use App\Util\Lexer\RestrictedNames;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class RestrictedNameTest extends TestCase
 {
-    /** @test */
+    #[Test]
     public function restrictedUsername()
     {
         $names = RestrictedNames::get();

+ 9 - 6
tests/Unit/Lexer/StatusLexerTest.php

@@ -5,6 +5,7 @@ namespace Tests\Unit\Lexer;
 use App\Status;
 use App\Util\Lexer\Autolink;
 use App\Util\Lexer\Extractor;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class StatusLexerTest extends TestCase
@@ -21,7 +22,8 @@ class StatusLexerTest extends TestCase
         $this->autolink = Autolink::create()->autolink($this->status);
     }
 
-    public function testLexerExtractor()
+    #[Test]
+    public function lexerExtractor()
     {
         $expected = [
             'hashtags' => [
@@ -56,13 +58,14 @@ class StatusLexerTest extends TestCase
         $this->assertEquals($this->entities, $expected);
     }
 
-    public function testAutolink()
+    #[Test]
+    public function autolink()
     {
         $expected = '<a class="u-url mention" href="https://pixelfed.dev/pixelfed" rel="external nofollow noopener" target="_blank">@pixelfed</a> hi, really like the website! <a href="https://pixelfed.dev/discover/tags/píxelfed?src=hash" title="#píxelfed" class="u-url hashtag" rel="external nofollow noopener">#píxelfed</a>';
         $this->assertEquals($this->autolink, $expected);
     }
 
-    /** @test * */
+    #[Test]
     public function remoteMention()
     {
         $expected = [
@@ -106,7 +109,7 @@ class StatusLexerTest extends TestCase
         $this->assertEquals($actual, $expected);
     }
 
-    /** @test * */
+    #[Test]
     public function mentionLimit()
     {
         $text = '@test1 @test @test2 @test3 @test4 @test5 @test6 @test7 @test8 @test9 @test10 @test11 @test12 @test13 @test14 @test15 @test16 @test17 @test18 @test19 test post';
@@ -116,7 +119,7 @@ class StatusLexerTest extends TestCase
         $this->assertEquals(Status::MAX_MENTIONS, $count);
     }
 
-    /** @test * */
+    #[Test]
     public function hashtagLimit()
     {
         $text = '#hashtag0 #hashtag1 #hashtag2 #hashtag3 #hashtag4 #hashtag5 #hashtag6 #hashtag7 #hashtag8 #hashtag9 #hashtag10 #hashtag11 #hashtag12 #hashtag13 #hashtag14 #hashtag15 #hashtag16 #hashtag17 #hashtag18 #hashtag19 #hashtag20 #hashtag21 #hashtag22 #hashtag23 #hashtag24 #hashtag25 #hashtag26 #hashtag27 #hashtag28 #hashtag29 #hashtag30 #hashtag31 #hashtag0 #hashtag1 #hashtag2 #hashtag3 #hashtag4 #hashtag5 #hashtag6 #hashtag7 #hashtag8 #hashtag9 #hashtag10 #hashtag11 #hashtag12 #hashtag13 #hashtag14 #hashtag15 #hashtag16 #hashtag17 #hashtag18 #hashtag19 #hashtag20 #hashtag21 #hashtag22 #hashtag23 #hashtag24 #hashtag25 #hashtag26 #hashtag27 #hashtag28 #hashtag29 #hashtag30 #hashtag31';
@@ -127,7 +130,7 @@ class StatusLexerTest extends TestCase
     }
 
 
-    /** @test * */
+    #[Test]
     public function linkLimit()
     {
         $text = 'https://example.org https://example.net https://example.com https://example.com https://example.net';

+ 9 - 8
tests/Unit/Lexer/UsernameTest.php

@@ -4,11 +4,12 @@ namespace Tests\Unit\Lexer;
 
 use App\Util\Lexer\Autolink;
 use App\Util\Lexer\Extractor;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class UsernameTest extends TestCase
 {
-    /** @test * */
+    #[Test]
     public function genericUsername()
     {
         $username = '@dansup';
@@ -38,7 +39,7 @@ class UsernameTest extends TestCase
         $this->assertEquals($expectedEntity, $entities);
     }
 
-    /** @test * */
+    #[Test]
     public function usernameWithPeriod()
     {
         $username = '@dansup.two';
@@ -68,7 +69,7 @@ class UsernameTest extends TestCase
         $this->assertEquals($expectedEntity, $entities);
     }
 
-    /** @test * */
+    #[Test]
     public function usernameWithDash()
     {
         $username = '@dansup-too';
@@ -98,7 +99,7 @@ class UsernameTest extends TestCase
         $this->assertEquals($expectedEntity, $entities);
     }
 
-    /** @test * */
+    #[Test]
     public function usernameWithUnderscore()
     {
         $username = '@dansup_too';
@@ -128,7 +129,7 @@ class UsernameTest extends TestCase
         $this->assertEquals($expectedEntity, $entities);
     }
 
-    /** @test * */
+    #[Test]
     public function multipleMentions()
     {
         $text = 'hello @dansup and @pixelfed.team from @username_underscore';
@@ -175,7 +176,7 @@ class UsernameTest extends TestCase
         $this->assertEquals($expectedEntity, $entities);
     }
 
-    /** @test * */
+    #[Test]
     public function germanUmlatsAutolink()
     {
         $mentions = "@März and @königin and @Glück";
@@ -185,7 +186,7 @@ class UsernameTest extends TestCase
         $this->assertEquals($expectedAutolink, $autolink);
     }
 
-    /** @test * */
+    #[Test]
     public function germanUmlatsExtractor()
     {
         $mentions = "@März and @königin and @Glück";
@@ -229,7 +230,7 @@ class UsernameTest extends TestCase
         $this->assertEquals($expectedEntity, $entities);
     }
 
-    /** @test * */
+    #[Test]
     public function germanUmlatsWebfingerAutolink()
     {
         $mentions = "hello @märz@example.org!";

+ 2 - 1
tests/Unit/PurifierTest.php

@@ -2,12 +2,13 @@
 
 namespace Tests\Unit;
 
+use PHPUnit\Framework\Attributes\Test;
 use Purify;
 use Tests\TestCase;
 
 class PurifierTest extends TestCase
 {
-    /** @test */
+    #[Test]
     public function puckTest()
     {
         $actual = Purify::clean("<span class=\"fa-spin fa\">catgirl spinning around in the interblag</span>");

+ 2 - 1
tests/Unit/WebfingerTest.php

@@ -3,11 +3,12 @@
 namespace Tests\Unit;
 
 use App\Util\Lexer\Nickname;
+use PHPUnit\Framework\Attributes\Test;
 use Tests\TestCase;
 
 class WebfingerTest extends TestCase
 {
-    /** @test */
+    #[Test]
     public function webfingerTest()
     {
         $expected = [

Some files were not shown because too many files changed in this diff