UserRepositoryTest.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Tests\Repositories;
  4. use App\Repositories\UserRepository;
  5. use App\Tests\TestCase;
  6. /**
  7. * Covers the first-user-is-admin bootstrap rule from spec §4.
  8. */
  9. final class UserRepositoryTest extends TestCase
  10. {
  11. public function testFirstUserBecomesAdminWhenPromoted(): void
  12. {
  13. $pdo = $this->makeDb();
  14. $users = new UserRepository($pdo);
  15. $this->assertSame(0, $users->count());
  16. $r = $users->upsertFromOidc(
  17. oid: 'oid-alice',
  18. email: 'alice@example.com',
  19. name: 'Alice',
  20. promoteToAdmin: true, // caller's decision — normally based on count === 0
  21. );
  22. $this->assertTrue($r['user']->isAdmin);
  23. $this->assertNull($r['before']);
  24. }
  25. public function testSecondUserDoesNotBecomeAdmin(): void
  26. {
  27. $pdo = $this->makeDb();
  28. $users = new UserRepository($pdo);
  29. $users->upsertFromOidc('oid-alice', 'alice@x', 'Alice', true);
  30. $secondPromote = $users->count() === 0; // false
  31. $r2 = $users->upsertFromOidc('oid-bob', 'bob@x', 'Bob', $secondPromote);
  32. $this->assertFalse($r2['user']->isAdmin);
  33. }
  34. public function testReLoginDoesNotRegressAdminStatus(): void
  35. {
  36. $pdo = $this->makeDb();
  37. $users = new UserRepository($pdo);
  38. $users->upsertFromOidc('oid-alice', 'alice@x', 'Alice', true);
  39. // simulate a later login: count > 0 so promoteToAdmin=false
  40. $r = $users->upsertFromOidc('oid-alice', 'alice@x', 'Alice', false);
  41. $this->assertTrue($r['user']->isAdmin, 're-login must not demote admin');
  42. $this->assertNotNull($r['before']);
  43. }
  44. public function testForceAdminPromotesEvenOnUpdate(): void
  45. {
  46. // Local-admin login path sets forceAdmin=true so a demoted user gets
  47. // promoted back on next sign-in.
  48. $pdo = $this->makeDb();
  49. $users = new UserRepository($pdo);
  50. $r1 = $users->upsertFromOidc('local:admin@x', 'admin@x', 'Admin', true, true);
  51. $this->assertTrue($r1['user']->isAdmin);
  52. // Manually demote.
  53. $pdo->exec('UPDATE users SET is_admin = 0 WHERE id = ' . $r1['user']->id);
  54. $r2 = $users->upsertFromOidc('local:admin@x', 'admin@x', 'Admin', false, true);
  55. $this->assertTrue($r2['user']->isAdmin, 'forceAdmin must re-promote on update');
  56. }
  57. public function testUpsertUpdatesEmailAndName(): void
  58. {
  59. $pdo = $this->makeDb();
  60. $users = new UserRepository($pdo);
  61. $users->upsertFromOidc('oid-alice', 'old@x', 'Old Name', true);
  62. $r = $users->upsertFromOidc('oid-alice', 'new@x', 'New Name', false);
  63. $this->assertSame('new@x', $r['user']->email);
  64. $this->assertSame('New Name', $r['user']->displayName);
  65. }
  66. public function testCountReflectsInsertedUsers(): void
  67. {
  68. $pdo = $this->makeDb();
  69. $users = new UserRepository($pdo);
  70. $this->assertSame(0, $users->count());
  71. $users->upsertFromOidc('oid-1', 'a@x', 'A', true);
  72. $this->assertSame(1, $users->count());
  73. $users->upsertFromOidc('oid-2', 'b@x', 'B', false);
  74. $this->assertSame(2, $users->count());
  75. // Re-upsert existing user shouldn't add a row.
  76. $users->upsertFromOidc('oid-1', 'a@x', 'A', false);
  77. $this->assertSame(2, $users->count());
  78. }
  79. // ------------------------------------------------------------------
  80. // Phase 9: users management page helpers
  81. // ------------------------------------------------------------------
  82. public function testAllReturnsEveryUserOrderedByEmail(): void
  83. {
  84. $pdo = $this->makeDb();
  85. $users = new UserRepository($pdo);
  86. $users->upsertFromOidc('oid-c', 'carol@x', 'Carol', true);
  87. $users->upsertFromOidc('oid-a', 'alice@x', 'Alice', false);
  88. $users->upsertFromOidc('oid-b', 'BOB@x', 'Bob', false);
  89. $all = $users->all();
  90. $this->assertCount(3, $all);
  91. $this->assertSame(['alice@x', 'BOB@x', 'carol@x'], array_map(fn($u) => $u->email, $all));
  92. }
  93. public function testCountAdmins(): void
  94. {
  95. $pdo = $this->makeDb();
  96. $users = new UserRepository($pdo);
  97. $this->assertSame(0, $users->countAdmins());
  98. $users->upsertFromOidc('oid-a', 'a@x', 'A', true);
  99. $this->assertSame(1, $users->countAdmins());
  100. $users->upsertFromOidc('oid-b', 'b@x', 'B', false);
  101. $this->assertSame(1, $users->countAdmins());
  102. $users->upsertFromOidc('oid-c', 'c@x', 'C', false, true); // forceAdmin
  103. $this->assertSame(2, $users->countAdmins());
  104. }
  105. public function testSetAdminTogglesAndReportsDiff(): void
  106. {
  107. $pdo = $this->makeDb();
  108. $users = new UserRepository($pdo);
  109. $users->upsertFromOidc('oid-a', 'a@x', 'A', true);
  110. $users->upsertFromOidc('oid-b', 'b@x', 'B', false);
  111. $bob = $users->findByOid('oid-b');
  112. $r = $users->setAdmin($bob->id, true);
  113. $this->assertFalse($r['before']->isAdmin);
  114. $this->assertTrue ($r['after']->isAdmin);
  115. $this->assertSame(2, $users->countAdmins());
  116. $r = $users->setAdmin($bob->id, false);
  117. $this->assertTrue ($r['before']->isAdmin);
  118. $this->assertFalse($r['after']->isAdmin);
  119. $this->assertSame(1, $users->countAdmins());
  120. }
  121. }