the browser-facing portion of osu!
at master 12 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6declare(strict_types=1); 7 8namespace Tests\Models\Chat; 9 10use App\Events\ChatChannelEvent; 11use App\Jobs\Notifications\ChannelAnnouncement; 12use App\Libraries\User\AvatarHelper; 13use App\Models\Chat\Channel; 14use App\Models\User; 15use App\Models\UserRelation; 16use Event; 17use Illuminate\Filesystem\Filesystem; 18use Queue; 19use SplFileInfo; 20use Storage; 21use Tests\TestCase; 22 23class ChannelTest extends TestCase 24{ 25 public function testAnnouncementSendMessage() 26 { 27 Queue::fake(); 28 29 $user = User::factory()->withGroup('announce')->create(); 30 $otherUser = User::factory()->create(); 31 $channel = Channel::factory()->type('announce', [$user, $otherUser])->create(); 32 33 $channel->receiveMessage($user, 'test'); 34 35 Queue::assertPushed(ChannelAnnouncement::class); 36 } 37 38 public function testAnnouncementSendToRestrictedUsers() 39 { 40 Queue::fake(); 41 42 $sender = User::factory()->withGroup('announce')->create(); 43 $user = User::factory()->create(); 44 $channel = Channel::factory()->type('announce', [$sender, $user])->create(); 45 46 $user->update(['user_warnings' => 1]); 47 $channel = $channel->fresh(); 48 49 // ChatMessageEvent uses activeUserIds to broadcast. 50 $this->assertContains($user->getKey(), $channel->activeUserIds()); 51 52 $channel->receiveMessage($sender, 'message'); 53 54 Queue::assertPushed( 55 ChannelAnnouncement::class, 56 fn (ChannelAnnouncement $job) => in_array($user->getKey(), $job->getReceiverIds(), true) 57 ); 58 } 59 60 public function testCreatePM() 61 { 62 $user1 = User::factory()->create(); 63 $user2 = User::factory()->create(); 64 65 $channel = Channel::createPM($user1, $user2); 66 $channel->refresh(); 67 68 $users = $channel->users(); 69 $this->assertContains($user1, $users); 70 $this->assertContains($user2, $users); 71 $this->assertCount(2, $users); 72 } 73 74 /** 75 * For testing the factory creates the channel in the expected form. 76 */ 77 public function testCreatePMWithFactory() 78 { 79 $channel1 = Channel::factory()->type('pm')->create(); 80 $users = $channel1->users(); 81 82 // multiple PM channels can be created; existing channel check is handled by sendPrivateMessage; 83 // createPM is typically not called directly. 84 $channel2 = Channel::createPM(...$users); 85 86 $this->assertCount(2, $users); 87 $this->assertSame($channel2->name, $channel1->name); 88 $this->assertEquals($channel2->users(), $users); 89 } 90 91 /** 92 * @dataProvider channelWithBlockedUserVisibilityDataProvider 93 */ 94 public function testChannelWithBlockedUserVisibility(?string $otherUserGroup, bool $expectVisible) 95 { 96 $user = User::factory()->create(); 97 $otherUser = User::factory()->withGroup($otherUserGroup)->create(); 98 $channel = Channel::factory()->type('pm', [$user, $otherUser])->create(); 99 100 UserRelation::create([ 101 'user_id' => $user->getKey(), 102 'zebra_id' => $otherUser->getKey(), 103 'foe' => true, 104 ]); 105 106 $this->assertSame($expectVisible, $channel->isVisibleFor($user)); 107 } 108 109 /** 110 * @dataProvider channelCanMessageModeratedChannelDataProvider 111 */ 112 public function testChannelCanMessageModeratedPmChannel(?string $group, bool $canMessage) 113 { 114 $user = User::factory()->withGroup($group)->create(); 115 $otherUser = User::factory()->create(); 116 $channel = Channel::factory()->type('pm', [$user, $otherUser])->moderated()->create(); 117 118 $this->assertSame($canMessage, $channel->checkCanMessage($user)->can()); 119 } 120 121 /** 122 * @dataProvider channelCanMessageModeratedChannelDataProvider 123 */ 124 public function testChannelCanMessageModeratedPublicChannel(?string $group, bool $canMessage) 125 { 126 $user = User::factory()->withGroup($group)->create(); 127 $channel = Channel::factory()->type('public', [$user])->moderated()->create(); 128 129 $this->assertSame($canMessage, $channel->checkCanMessage($user)->can()); 130 } 131 132 /** 133 * @dataProvider channelCanMessageWhenBlockedDataProvider 134 */ 135 public function testChannelCanMessagePmChannelWhenBlocked(?string $group, bool $canMessage) 136 { 137 $user = User::factory()->withGroup($group)->create(); 138 $otherUser = User::factory()->create(); 139 $channel = Channel::factory()->type('pm', [$user, $otherUser])->create(); 140 141 UserRelation::create([ 142 'user_id' => $user->getKey(), 143 'zebra_id' => $otherUser->getKey(), 144 'foe' => true, 145 ]); 146 147 // reset caches from previous steps. 148 $user->refresh(); 149 $otherUser->refresh(); 150 app('OsuAuthorize')->resetCache(); 151 152 // this assertion to make sure the correct block direction is being tested. 153 $this->assertTrue($user->hasBlocked($otherUser)); 154 $this->assertSame($canMessage, $channel->checkCanMessage($user)->can()); 155 } 156 157 /** 158 * @dataProvider channelCanMessageWhenBlockedDataProvider 159 */ 160 public function testChannelCanMessagePmChannelWhenBlocking(?string $group, bool $canMessage) 161 { 162 $user = User::factory()->withGroup($group)->create(); 163 $otherUser = User::factory()->create(); 164 $channel = Channel::factory()->type('pm', [$user, $otherUser])->create(); 165 166 UserRelation::create([ 167 'user_id' => $otherUser->getKey(), 168 'zebra_id' => $user->getKey(), 169 'foe' => true, 170 ]); 171 172 // reset caches from previous steps. 173 $user->refresh(); 174 $otherUser->refresh(); 175 app('OsuAuthorize')->resetCache(); 176 177 // this assertion to make sure the correct block direction is being tested. 178 $this->assertTrue($otherUser->hasBlocked($user)); 179 $this->assertSame($canMessage, $channel->checkCanMessage($user)->can()); 180 } 181 182 /** 183 * @dataProvider channelCanMessageWhenBlockedDataProvider 184 */ 185 public function testChannelCanMessagePmChannelWhenFriendsOnly(?string $group, bool $canMessage) 186 { 187 $user = User::factory()->withGroup($group)->create(); 188 $otherUser = User::factory()->create(['pm_friends_only' => true]); 189 $channel = Channel::factory()->type('pm', [$user, $otherUser])->create(); 190 191 app('OsuAuthorize')->resetCache(); 192 193 $this->assertSame($canMessage, $channel->checkCanMessage($user)->can()); 194 } 195 196 public function testCreateAnnouncement() 197 { 198 Event::fake(ChatChannelEvent::class); 199 200 $users = User::factory()->count(2)->create(); 201 202 $channel = Channel::createAnnouncement($users, ['description' => 'channel', 'name' => 'the best']); 203 204 $channel = $channel->fresh(); 205 206 $this->assertEmpty($users->diff($channel->users()), 'created channel has too many users.'); 207 $this->assertEmpty($channel->users()->diff($users), 'created channel is missing users.'); 208 $this->assertSame(Channel::TYPES['announce'], $channel->type); 209 210 Event::assertDispatched(fn (ChatChannelEvent $event) => $event->action === 'join', 2); 211 Event::assertNotDispatched(fn (ChatChannelEvent $event) => $event->action !== 'join'); 212 } 213 214 public function testGetPMChannelName() 215 { 216 $user1 = User::factory()->create(); 217 $user2 = User::factory()->create(); 218 219 $this->assertSame( 220 Channel::getPMChannelName($user1, $user2), 221 Channel::getPMChannelName($user2, $user1) 222 ); 223 } 224 225 /** 226 * @dataProvider leaveChannelDataProvider 227 */ 228 public function testLeaveChannel(string $type, bool $inChannel) 229 { 230 $users = User::factory()->count(2)->create(); 231 $user = $users[0]; 232 $channel = Channel::factory()->type($type, [...$users])->create(); 233 $channel->refresh(); 234 235 $channel->removeUser($user); 236 $channel->refresh(); 237 238 if ($inChannel) { 239 $this->assertContains($user->getKey(), $channel->userIds()); 240 $this->assertTrue($channel->hasUser($user)); 241 } else { 242 $this->assertNotContains($user->getKey(), $channel->userIds()); 243 $this->assertFalse($channel->hasUser($user)); 244 } 245 } 246 247 public function testPmChannelIcon() 248 { 249 Storage::fake('local-avatar'); 250 $this->beforeApplicationDestroyed(function () { 251 (new Filesystem())->deleteDirectory(storage_path('framework/testing/disks/local-avatar')); 252 }); 253 254 $user = User::factory()->create(); 255 $otherUser = User::factory()->create(); 256 257 $testFile = new SplFileInfo(public_path('images/layout/avatar-guest.png')); 258 AvatarHelper::set($user, $testFile); 259 AvatarHelper::set($otherUser, $testFile); 260 261 $channel = Channel::factory()->type('pm', [$user, $otherUser])->create(); 262 $this->assertSame($otherUser->user_avatar, $channel->displayIconFor($user)); 263 $this->assertSame($user->user_avatar, $channel->displayIconFor($otherUser)); 264 } 265 266 public function testPmChannelName() 267 { 268 $user = User::factory()->create(); 269 $otherUser = User::factory()->create(); 270 271 $channel = Channel::factory()->type('pm', [$user, $otherUser])->create(); 272 $this->assertSame($otherUser->username, $channel->displayNameFor($user)); 273 $this->assertSame($user->username, $channel->displayNameFor($otherUser)); 274 } 275 276 public function testPublicChannelDoesNotShowUsers() 277 { 278 $user = User::factory()->create(); 279 $channel = Channel::factory()->type('public', [$user])->create(); 280 281 $this->assertSame(1, $channel->users()->count()); 282 $this->assertEmpty($channel->visibleUsers()); 283 } 284 285 // test add/removeUser resets any memoized values 286 public function testResetMemoized() 287 { 288 $user = User::factory()->create(); 289 $channel = Channel::factory()->create(); 290 291 $channel->addUser($user); // removeUser doesn't trigger resetMemoized if the user isn't in the channel. 292 $memoized = $this->invokeProperty($channel, 'memoized'); 293 $this->assertEmpty($memoized); // addUser calls resetMemoized at the end so it should be empty. 294 295 $this->invokeMethod($channel, 'userChannelFor', [$user]); 296 $memoized = $this->invokeProperty($channel, 'memoized'); 297 $this->assertNotEmpty($memoized); 298 299 $channel->removeUser($user); 300 $memoized = $this->invokeProperty($channel, 'memoized'); 301 $this->assertEmpty($memoized); 302 } 303 304 public static function channelCanMessageModeratedChannelDataProvider() 305 { 306 return [ 307 [null, false], 308 ['admin', true], 309 ['bng', false], 310 ['bot', false], 311 ['gmt', true], 312 ['nat', true], 313 ]; 314 } 315 316 public static function channelCanMessageWhenBlockedDataProvider() 317 { 318 return [ 319 [null, false], 320 ['admin', true], 321 ['bng', false], 322 ['bot', true], 323 ['gmt', true], 324 ['nat', true], 325 ]; 326 } 327 328 public static function channelWithBlockedUserVisibilityDataProvider() 329 { 330 return [ 331 [null, false], 332 ['admin', true], 333 ['bng', false], 334 ['bot', true], 335 ['gmt', true], 336 ['nat', true], 337 ]; 338 } 339 340 public static function leaveChannelDataProvider() 341 { 342 return [ 343 ['announce', true], 344 ['pm', true], 345 ['public', false], 346 ]; 347 } 348}