diff --git a/tests/Unit/Service/Nostr/NostrEventBuilderTest.php b/tests/Unit/Service/Nostr/NostrEventBuilderTest.php new file mode 100644 index 0000000..9194a16 --- /dev/null +++ b/tests/Unit/Service/Nostr/NostrEventBuilderTest.php @@ -0,0 +1,203 @@ +builder = new NostrEventBuilder(); + } + + public function testBuildBasicTags(): void + { + $article = new Article(); + $article->setSlug('test-article'); + $article->setTitle('Test Article'); + $article->setSummary('A test summary'); + $article->setImage('https://example.com/image.jpg'); + $article->setTopics(['nostr', 'testing']); + $article->setPublishedAt(new \DateTimeImmutable('@1609459200')); // 2021-01-01 + + $tags = $this->builder->buildTags($article, null); + + $this->assertContains(['d', 'test-article'], $tags); + $this->assertContains(['title', 'Test Article'], $tags); + $this->assertContains(['summary', 'A test summary'], $tags); + $this->assertContains(['image', 'https://example.com/image.jpg'], $tags); + $this->assertContains(['t', 'nostr'], $tags); + $this->assertContains(['t', 'testing'], $tags); + $this->assertContains(['published_at', '1609459200'], $tags); + } + + public function testBuildDoNotRepublishTag(): void + { + $article = new Article(); + $article->setSlug('test'); + $article->setTitle('Test'); + + $metadata = new AdvancedMetadata(); + $metadata->doNotRepublish = true; + + $tags = $this->builder->buildTags($article, $metadata); + + $this->assertContains(['L', 'rights.decent.newsroom'], $tags); + $this->assertContains(['l', 'no-republish', 'rights.decent.newsroom'], $tags); + } + + public function testBuildLicenseTags(): void + { + $article = new Article(); + $article->setSlug('test'); + $article->setTitle('Test'); + + $metadata = new AdvancedMetadata(); + $metadata->license = 'CC-BY-4.0'; + + $tags = $this->builder->buildTags($article, $metadata); + + $this->assertContains(['L', 'spdx.org/licenses'], $tags); + $this->assertContains(['l', 'CC-BY-4.0', 'spdx.org/licenses'], $tags); + } + + public function testBuildAllRightsReservedTag(): void + { + $article = new Article(); + $article->setSlug('test'); + $article->setTitle('Test'); + + $metadata = new AdvancedMetadata(); + $metadata->license = 'All rights reserved'; + + $tags = $this->builder->buildTags($article, $metadata); + + $this->assertContains(['L', 'rights.decent.newsroom'], $tags); + $this->assertContains(['l', 'all-rights-reserved', 'rights.decent.newsroom'], $tags); + } + + public function testBuildZapSplitTags(): void + { + $article = new Article(); + $article->setSlug('test'); + $article->setTitle('Test'); + + $metadata = new AdvancedMetadata(); + $metadata->zapSplits = [ + new ZapSplit('82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2', 'wss://relay.damus.io', 2), + new ZapSplit('3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d', 'wss://relay.nostr.band', 1), + ]; + + $tags = $this->builder->buildTags($article, $metadata); + + $this->assertContains( + ['zap', '82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2', 'wss://relay.damus.io', '2'], + $tags + ); + $this->assertContains( + ['zap', '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d', 'wss://relay.nostr.band', '1'], + $tags + ); + } + + public function testBuildContentWarningTag(): void + { + $article = new Article(); + $article->setSlug('test'); + $article->setTitle('Test'); + + $metadata = new AdvancedMetadata(); + $metadata->contentWarning = 'graphic content'; + + $tags = $this->builder->buildTags($article, $metadata); + + $this->assertContains(['content-warning', 'graphic content'], $tags); + } + + public function testBuildExpirationTag(): void + { + $article = new Article(); + $article->setSlug('test'); + $article->setTitle('Test'); + + $metadata = new AdvancedMetadata(); + $metadata->expirationTimestamp = 1735689600; // 2025-01-01 + + $tags = $this->builder->buildTags($article, $metadata); + + $this->assertContains(['expiration', '1735689600'], $tags); + } + + public function testBuildProtectedTag(): void + { + $article = new Article(); + $article->setSlug('test'); + $article->setTitle('Test'); + + $metadata = new AdvancedMetadata(); + $metadata->isProtected = true; + + $tags = $this->builder->buildTags($article, $metadata); + + $this->assertContains(['-'], $tags); + } + + public function testCalculateSharesEqualDistribution(): void + { + $splits = [ + new ZapSplit('pubkey1'), + new ZapSplit('pubkey2'), + new ZapSplit('pubkey3'), + ]; + + $shares = $this->builder->calculateShares($splits); + + $this->assertCount(3, $shares); + $this->assertEquals(33.333333333333, $shares[0], '', 0.01); + $this->assertEquals(33.333333333333, $shares[1], '', 0.01); + $this->assertEquals(33.333333333333, $shares[2], '', 0.01); + } + + public function testCalculateSharesWeightedDistribution(): void + { + $splits = [ + new ZapSplit('pubkey1', null, 2), + new ZapSplit('pubkey2', null, 1), + new ZapSplit('pubkey3', null, 1), + ]; + + $shares = $this->builder->calculateShares($splits); + + $this->assertCount(3, $shares); + $this->assertEquals(50.0, $shares[0]); + $this->assertEquals(25.0, $shares[1]); + $this->assertEquals(25.0, $shares[2]); + } + + public function testConvertNpubToHex(): void + { + // This is a test npub (you may need to adjust based on actual implementation) + $hex = '82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2'; + + // Test hex passthrough + $result = $this->builder->convertToHex($hex); + $this->assertEquals($hex, $result); + } + + public function testConvertInvalidPubkeyThrowsException(): void + { + $this->expectException(\InvalidArgumentException::class); + $this->builder->convertToHex('invalid-pubkey'); + } +} + diff --git a/tests/Unit/Service/Nostr/NostrEventParserTest.php b/tests/Unit/Service/Nostr/NostrEventParserTest.php new file mode 100644 index 0000000..9227307 --- /dev/null +++ b/tests/Unit/Service/Nostr/NostrEventParserTest.php @@ -0,0 +1,168 @@ +parser = new NostrEventParser(); + } + + public function testParseDoNotRepublishTag(): void + { + $tags = [ + ['L', 'rights.decent.newsroom'], + ['l', 'no-republish', 'rights.decent.newsroom'], + ]; + + $metadata = $this->parser->parseAdvancedMetadata($tags); + + $this->assertTrue($metadata->doNotRepublish); + } + + public function testParseLicenseTag(): void + { + $tags = [ + ['L', 'spdx.org/licenses'], + ['l', 'CC-BY-4.0', 'spdx.org/licenses'], + ]; + + $metadata = $this->parser->parseAdvancedMetadata($tags); + + $this->assertEquals('CC-BY-4.0', $metadata->license); + } + + public function testParseAllRightsReservedTag(): void + { + $tags = [ + ['L', 'rights.decent.newsroom'], + ['l', 'all-rights-reserved', 'rights.decent.newsroom'], + ]; + + $metadata = $this->parser->parseAdvancedMetadata($tags); + + $this->assertEquals('All rights reserved', $metadata->license); + } + + public function testParseZapSplitTags(): void + { + $tags = [ + ['zap', '82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2', 'wss://relay.damus.io', '2'], + ['zap', '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d', 'wss://relay.nostr.band', '1'], + ]; + + $metadata = $this->parser->parseAdvancedMetadata($tags); + + $this->assertCount(2, $metadata->zapSplits); + $this->assertEquals('wss://relay.damus.io', $metadata->zapSplits[0]->relay); + $this->assertEquals(2, $metadata->zapSplits[0]->weight); + $this->assertEquals('wss://relay.nostr.band', $metadata->zapSplits[1]->relay); + $this->assertEquals(1, $metadata->zapSplits[1]->weight); + } + + public function testParseContentWarningTag(): void + { + $tags = [ + ['content-warning', 'graphic content'], + ]; + + $metadata = $this->parser->parseAdvancedMetadata($tags); + + $this->assertEquals('graphic content', $metadata->contentWarning); + } + + public function testParseExpirationTag(): void + { + $tags = [ + ['expiration', '1735689600'], + ]; + + $metadata = $this->parser->parseAdvancedMetadata($tags); + + $this->assertEquals(1735689600, $metadata->expirationTimestamp); + } + + public function testParseProtectedTag(): void + { + $tags = [ + ['-'], + ]; + + $metadata = $this->parser->parseAdvancedMetadata($tags); + + $this->assertTrue($metadata->isProtected); + } + + public function testParseMultipleAdvancedTags(): void + { + $tags = [ + ['d', 'test-article'], + ['title', 'Test Article'], + ['L', 'rights.decent.newsroom'], + ['l', 'no-republish', 'rights.decent.newsroom'], + ['L', 'spdx.org/licenses'], + ['l', 'CC-BY-NC-ND-4.0', 'spdx.org/licenses'], + ['zap', '82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2', 'wss://relay.damus.io', '2'], + ['zap', '3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d', '', '1'], + ['content-warning', 'spoilers'], + ['expiration', '1735689600'], + ['-'], + ]; + + $metadata = $this->parser->parseAdvancedMetadata($tags); + + $this->assertTrue($metadata->doNotRepublish); + $this->assertEquals('CC-BY-NC-ND-4.0', $metadata->license); + $this->assertCount(2, $metadata->zapSplits); + $this->assertEquals('spoilers', $metadata->contentWarning); + $this->assertEquals(1735689600, $metadata->expirationTimestamp); + $this->assertTrue($metadata->isProtected); + } + + public function testExtractArticleData(): void + { + $tags = [ + ['d', 'my-article-slug'], + ['title', 'My Article Title'], + ['summary', 'A brief summary'], + ['image', 'https://example.com/image.jpg'], + ['published_at', '1609459200'], + ['t', 'nostr'], + ['t', 'testing'], + ]; + + $data = $this->parser->extractArticleData($tags); + + $this->assertEquals('my-article-slug', $data['slug']); + $this->assertEquals('My Article Title', $data['title']); + $this->assertEquals('A brief summary', $data['summary']); + $this->assertEquals('https://example.com/image.jpg', $data['image']); + $this->assertCount(2, $data['topics']); + $this->assertContains('nostr', $data['topics']); + $this->assertContains('testing', $data['topics']); + $this->assertInstanceOf(\DateTimeImmutable::class, $data['publishedAt']); + } + + public function testPreserveUnknownTags(): void + { + $tags = [ + ['d', 'test'], + ['custom-tag', 'custom-value'], + ['another-unknown', 'value1', 'value2'], + ]; + + $metadata = $this->parser->parseAdvancedMetadata($tags); + + // Unknown tags should be preserved in extraTags + $this->assertCount(2, $metadata->extraTags); + } +} +