Maintain local ⭤ remote in sync with automatic AT Protocol parity for Laravel (alpha & unstable)
at main 191 lines 6.1 kB view raw
1<?php 2 3namespace SocialDept\AtpParity\Tests\Unit\Concerns; 4 5use SocialDept\AtpParity\MapperRegistry; 6use SocialDept\AtpParity\Tests\Fixtures\TestMapper; 7use SocialDept\AtpParity\Tests\Fixtures\TestModel; 8use SocialDept\AtpParity\Tests\Fixtures\TestRecord; 9use SocialDept\AtpParity\Tests\TestCase; 10 11class HasAtpRecordTest extends TestCase 12{ 13 public function test_get_atp_uri_returns_uri_from_column(): void 14 { 15 $model = new TestModel(['atp_uri' => 'at://did:plc:test/app.test.record/abc123']); 16 17 $this->assertSame('at://did:plc:test/app.test.record/abc123', $model->getAtpUri()); 18 } 19 20 public function test_get_atp_uri_returns_null_when_not_set(): void 21 { 22 $model = new TestModel(); 23 24 $this->assertNull($model->getAtpUri()); 25 } 26 27 public function test_get_atp_cid_returns_cid_from_column(): void 28 { 29 $model = new TestModel(['atp_cid' => 'bafyreiabc123']); 30 31 $this->assertSame('bafyreiabc123', $model->getAtpCid()); 32 } 33 34 public function test_get_atp_cid_returns_null_when_not_set(): void 35 { 36 $model = new TestModel(); 37 38 $this->assertNull($model->getAtpCid()); 39 } 40 41 public function test_get_atp_did_extracts_did_from_uri(): void 42 { 43 $model = new TestModel(['atp_uri' => 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/abc123']); 44 45 $this->assertSame('did:plc:z72i7hdynmk6r22z27h6tvur', $model->getAtpDid()); 46 } 47 48 public function test_get_atp_did_returns_null_when_no_uri(): void 49 { 50 $model = new TestModel(); 51 52 $this->assertNull($model->getAtpDid()); 53 } 54 55 public function test_get_atp_did_returns_null_for_malformed_uri(): void 56 { 57 $model = new TestModel(['atp_uri' => 'invalid-uri']); 58 59 $this->assertNull($model->getAtpDid()); 60 } 61 62 public function test_get_atp_collection_extracts_collection_from_uri(): void 63 { 64 $model = new TestModel(['atp_uri' => 'at://did:plc:test/app.bsky.feed.post/abc123']); 65 66 $this->assertSame('app.bsky.feed.post', $model->getAtpCollection()); 67 } 68 69 public function test_get_atp_collection_returns_null_when_no_uri(): void 70 { 71 $model = new TestModel(); 72 73 $this->assertNull($model->getAtpCollection()); 74 } 75 76 public function test_get_atp_rkey_extracts_rkey_from_uri(): void 77 { 78 $model = new TestModel(['atp_uri' => 'at://did:plc:test/app.bsky.feed.post/3kj2h4k5j']); 79 80 $this->assertSame('3kj2h4k5j', $model->getAtpRkey()); 81 } 82 83 public function test_get_atp_rkey_returns_null_when_no_uri(): void 84 { 85 $model = new TestModel(); 86 87 $this->assertNull($model->getAtpRkey()); 88 } 89 90 public function test_has_atp_record_returns_true_when_uri_set(): void 91 { 92 $model = new TestModel(['atp_uri' => 'at://did/col/rkey']); 93 94 $this->assertTrue($model->hasAtpRecord()); 95 } 96 97 public function test_has_atp_record_returns_false_when_no_uri(): void 98 { 99 $model = new TestModel(); 100 101 $this->assertFalse($model->hasAtpRecord()); 102 } 103 104 public function test_get_atp_mapper_returns_mapper_when_registered(): void 105 { 106 $registry = app(MapperRegistry::class); 107 $registry->register(new TestMapper()); 108 109 $model = new TestModel(); 110 $mapper = $model->getAtpMapper(); 111 112 $this->assertInstanceOf(TestMapper::class, $mapper); 113 } 114 115 public function test_get_atp_mapper_returns_null_when_not_registered(): void 116 { 117 // Fresh registry without any mappers 118 $this->app->forgetInstance(MapperRegistry::class); 119 $this->app->singleton(MapperRegistry::class); 120 121 $model = new TestModel(); 122 123 $this->assertNull($model->getAtpMapper()); 124 } 125 126 public function test_to_atp_record_converts_model_to_record(): void 127 { 128 $registry = app(MapperRegistry::class); 129 $registry->register(new TestMapper()); 130 131 $model = new TestModel(['content' => 'Hello world']); 132 $record = $model->toAtpRecord(); 133 134 $this->assertInstanceOf(TestRecord::class, $record); 135 $this->assertSame('Hello world', $record->text); 136 } 137 138 public function test_to_atp_record_returns_null_when_no_mapper(): void 139 { 140 $this->app->forgetInstance(MapperRegistry::class); 141 $this->app->singleton(MapperRegistry::class); 142 143 $model = new TestModel(['content' => 'Hello']); 144 145 $this->assertNull($model->toAtpRecord()); 146 } 147 148 public function test_scope_with_atp_record_filters_synced_models(): void 149 { 150 TestModel::create(['content' => 'Synced', 'atp_uri' => 'at://did/col/rkey1']); 151 TestModel::create(['content' => 'Not synced']); 152 TestModel::create(['content' => 'Also synced', 'atp_uri' => 'at://did/col/rkey2']); 153 154 $synced = TestModel::withAtpRecord()->get(); 155 156 $this->assertCount(2, $synced); 157 $this->assertTrue($synced->every(fn ($m) => $m->atp_uri !== null)); 158 } 159 160 public function test_scope_without_atp_record_filters_unsynced_models(): void 161 { 162 TestModel::create(['content' => 'Synced', 'atp_uri' => 'at://did/col/rkey']); 163 TestModel::create(['content' => 'Not synced 1']); 164 TestModel::create(['content' => 'Not synced 2']); 165 166 $unsynced = TestModel::withoutAtpRecord()->get(); 167 168 $this->assertCount(2, $unsynced); 169 $this->assertTrue($unsynced->every(fn ($m) => $m->atp_uri === null)); 170 } 171 172 public function test_scope_where_atp_uri_finds_by_uri(): void 173 { 174 TestModel::create(['content' => 'Target', 'atp_uri' => 'at://did/col/target']); 175 TestModel::create(['content' => 'Other', 'atp_uri' => 'at://did/col/other']); 176 177 $found = TestModel::whereAtpUri('at://did/col/target')->first(); 178 179 $this->assertNotNull($found); 180 $this->assertSame('Target', $found->content); 181 } 182 183 public function test_scope_where_atp_uri_returns_null_when_not_found(): void 184 { 185 TestModel::create(['content' => 'Some', 'atp_uri' => 'at://did/col/some']); 186 187 $found = TestModel::whereAtpUri('at://did/col/nonexistent')->first(); 188 189 $this->assertNull($found); 190 } 191}