getDriverName() !== 'mysql') { test()->markTestSkipped('Needs MySQL: SQLite compares byte-exactly and cannot show a collation fault.'); } }); test('the database really does fold the accent', function () { // Asserted rather than assumed, because everything below is only // meaningful if this is true of the connection actually in use. An // installation on utf8mb4_bin has never had the bug. $folds = DB::selectOne("SELECT _utf8mb4'a@example.com' COLLATE utf8mb4_unicode_ci = _utf8mb4'a@éxample.com' COLLATE utf8mb4_unicode_ci AS c")->c; expect((int) $folds)->toBe(1); }); test('the raw query matches an address it should not', function () { // The defect itself, shown rather than described: this is exactly what // SocialAuthenticator used to run. User::factory()->create(['email' => 'administrator@example.com']); $found = User::query()->where('email', 'administrator@éxample.com')->first(); expect($found)->not->toBeNull('the collation no longer folds — the rest of this file is moot'); }); test('the lookup refuses the address the collation would have accepted', function () { // The fix. Same database, same collation, same row present. User::factory()->create(['email' => 'administrator@example.com']); expect(app(AccountLookup::class)->byEmail('administrator@éxample.com'))->toBeNull(); }); test('and still finds the real one', function () { $user = User::factory()->create(['email' => 'administrator@example.com']); expect(app(AccountLookup::class)->byEmail('administrator@example.com')?->id)->toBe($user->id) ->and(app(AccountLookup::class)->byEmail('ADMINISTRATOR@Example.com')?->id)->toBe($user->id); });