Test Feed https://example.com Article 1 https://example.com/1 '; $parser = new FeedParser($xml); $this->assertTrue($parser->init()); $this->assertEquals(FeedParser::FEED_RSS, $parser->get_type()); $this->assertEquals('Test Feed', $parser->get_title()); $this->assertEquals('https://example.com', $parser->get_link()); $this->assertCount(1, $parser->get_items()); } public function testParseRssFeedWithMultipleItems(): void { $xml = ' Multi-Item Feed https://example.com Item 1 Item 2 Item 3 '; $parser = new FeedParser($xml); $parser->init(); $this->assertCount(3, $parser->get_items()); } public function testRssFeedTrimsWhitespaceInTitleAndLink(): void { $xml = ' Whitespace Title https://example.com '; $parser = new FeedParser($xml); $parser->init(); $this->assertEquals('Whitespace Title', $parser->get_title()); $this->assertEquals('https://example.com', $parser->get_link()); } // ===== Atom Feed Tests ===== public function testParseValidAtomFeed(): void { $xml = ' Atom Feed Entry 1 '; $parser = new FeedParser($xml); $this->assertTrue($parser->init()); $this->assertEquals(FeedParser::FEED_ATOM, $parser->get_type()); $this->assertEquals('Atom Feed', $parser->get_title()); $this->assertEquals('https://example.com', $parser->get_link()); $this->assertCount(1, $parser->get_items()); } public function testAtomFeedWithAlternateLinkRel(): void { $xml = ' Test '; $parser = new FeedParser($xml); $parser->init(); $this->assertEquals('https://example.com/alternate', $parser->get_link()); } public function testAtom03Feed(): void { $xml = ' Atom 0.3 Feed Old Entry '; $parser = new FeedParser($xml); $this->assertTrue($parser->init()); $this->assertEquals(FeedParser::FEED_ATOM, $parser->get_type()); $this->assertEquals('Atom 0.3 Feed', $parser->get_title()); $this->assertCount(1, $parser->get_items()); } // ===== RDF/RSS 1.0 Feed Tests ===== public function testParseRdfFeed(): void { $xml = ' RDF Feed https://example.com RDF Item '; $parser = new FeedParser($xml); $this->assertTrue($parser->init()); $this->assertEquals(FeedParser::FEED_RDF, $parser->get_type()); $this->assertEquals('RDF Feed', $parser->get_title()); $this->assertEquals('https://example.com', $parser->get_link()); $this->assertCount(1, $parser->get_items()); } // ===== Error Handling Tests ===== public function testInvalidXmlReturnsError(): void { $xml = ''; $parser = new FeedParser($xml); $this->assertFalse($parser->init()); $this->assertNotEmpty($parser->error()); } public function testUnknownFeedTypeReturnsError(): void { $xml = ''; $parser = new FeedParser($xml); $this->assertFalse($parser->init()); $this->assertEquals(FeedParser::FEED_UNKNOWN, $parser->get_type()); $this->assertStringContainsString('Unknown/unsupported feed type', $parser->error()); } public function testEmptyXmlReturnsError(): void { $parser = new FeedParser(''); $this->assertFalse($parser->init()); $this->assertStringContainsString('Empty feed data', $parser->error()); } public function testLibxmlErrorsAreCollected(): void { $xml = 'Test</broken></channel></rss>'; $parser = new FeedParser($xml); $errors = $parser->errors(); $this->assertNotEmpty($errors); } // ===== Feed Type Detection Tests ===== public function testGetTypeBeforeInitReturnsUnknown(): void { $xml = '<?xml version="1.0"?><rss version="2.0"><channel></channel></rss>'; $parser = new FeedParser($xml); // get_type() before init() should detect type automatically $this->assertEquals(FeedParser::FEED_RSS, $parser->get_type()); } public function testGetTypeCachesResult(): void { $xml = '<?xml version="1.0"?><rss version="2.0"><channel></channel></rss>'; $parser = new FeedParser($xml); $type1 = $parser->get_type(); $type2 = $parser->get_type(); $this->assertEquals($type1, $type2); } // ===== Link Extraction Tests ===== public function testGetLinksFromAtomFeed(): void { $xml = '<?xml version="1.0"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>Test '; $parser = new FeedParser($xml); $parser->init(); $selfLinks = $parser->get_links('self'); $this->assertCount(1, $selfLinks); $this->assertEquals('https://example.com/self', $selfLinks[0]); $hubLinks = $parser->get_links('hub'); $this->assertCount(1, $hubLinks); $this->assertEquals('https://example.com/hub', $hubLinks[0]); } public function testGetLinksFromRssFeed(): void { $xml = ' Test '; $parser = new FeedParser($xml); $parser->init(); $selfLinks = $parser->get_links('self'); $this->assertCount(1, $selfLinks); $this->assertEquals('https://example.com/self', $selfLinks[0]); } public function testGetLinksWithoutRelReturnsAllLinks(): void { $xml = ' Test '; $parser = new FeedParser($xml); $parser->init(); $allLinks = $parser->get_links(''); $this->assertCount(2, $allLinks); } // ===== Empty/Missing Data Tests ===== public function testFeedWithoutTitleReturnsEmptyString(): void { $xml = ' https://example.com '; $parser = new FeedParser($xml); $parser->init(); $this->assertEquals('', $parser->get_title()); } public function testFeedWithoutLinkReturnsEmptyString(): void { $xml = ' Test '; $parser = new FeedParser($xml); $parser->init(); $this->assertEquals('', $parser->get_link()); } public function testFeedWithoutItemsReturnsEmptyArray(): void { $xml = ' Empty Feed '; $parser = new FeedParser($xml); $parser->init(); $this->assertCount(0, $parser->get_items()); } // ===== RSS Link Attribute Handling ===== public function testRssLinkWithHrefAttribute(): void { $xml = ' Test '; $parser = new FeedParser($xml); $parser->init(); $this->assertEquals('https://example.com/href-link', $parser->get_link()); } public function testRssLinkWithNodeValue(): void { $xml = ' Test https://example.com/node-link '; $parser = new FeedParser($xml); $parser->init(); $this->assertEquals('https://example.com/node-link', $parser->get_link()); } }