-
unique-id-123
https://example.com/article
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('unique-id-123', $items[0]->get_id());
}
public function testRssGetIdFallsBackToLink(): void {
$xml = '
-
https://example.com/article
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('https://example.com/article', $items[0]->get_id());
}
public function testRssGetDateFromPubDate(): void {
$xml = '
-
Mon, 01 Jan 2024 12:00:00 GMT
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$timestamp = $items[0]->get_date();
$this->assertEquals(1704110400, $timestamp); // 2024-01-01 12:00:00 GMT
}
public function testRssGetDateFromDcDate(): void {
$xml = '
-
2024-01-01T12:00:00Z
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$timestamp = $items[0]->get_date();
$this->assertEquals(1704110400, $timestamp); // 2024-01-01 12:00:00 GMT
}
public function testRssGetDateReturnsFalseForMissingDate(): void {
$xml = '
-
No date
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertFalse($items[0]->get_date());
}
public function testRssGetLinkFromAtomLink(): void {
$xml = '
-
https://example.com/old-link
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('https://example.com/article', $items[0]->get_link());
}
public function testRssGetLinkFromPermaLinkGuid(): void {
$xml = '
-
https://example.com/permalink
https://example.com/link
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
// Permalink guid is checked AFTER atom:link but BEFORE
// Since there's no atom:link, permalink guid is used
$this->assertEquals('https://example.com/permalink', $items[0]->get_link());
}
public function testRssGetLinkFromLinkElement(): void {
$xml = '
-
https://example.com/article
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('https://example.com/article', $items[0]->get_link());
}
public function testRssGetTitle(): void {
$xml = '
-
Test Article Title
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('Test Article Title', $items[0]->get_title());
}
public function testRssGetContentFromEncoded(): void {
$xml = '
-
Full article content]]>
Short description
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$content = $items[0]->get_content();
$this->assertStringContainsString('Full article content', $content);
}
public function testRssGetContentPrefersLonger(): void {
$xml = '
-
Short
This is a much longer description with more text
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$content = $items[0]->get_content();
$this->assertStringContainsString('longer description', $content);
}
// ===== FeedItem_Atom Tests =====
public function testAtomGetIdFromIdElement(): void {
$xml = '
tag:example.com,2024:entry-123
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('tag:example.com,2024:entry-123', $items[0]->get_id());
}
public function testAtomGetIdFallsBackToLink(): void {
$xml = '
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('https://example.com/article', $items[0]->get_id());
}
public function testAtomGetDateFromUpdated(): void {
$xml = '
2024-01-01T12:00:00Z
2024-01-01T10:00:00Z
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$timestamp = $items[0]->get_date();
$this->assertEquals(1704110400, $timestamp); // updated time
}
public function testAtomGetDateFromPublished(): void {
$xml = '
2024-01-01T12:00:00Z
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$timestamp = $items[0]->get_date();
$this->assertEquals(1704110400, $timestamp);
}
public function testAtomGetLink(): void {
$xml = '
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('https://example.com/article', $items[0]->get_link());
}
public function testAtomGetLinkWithoutRel(): void {
$xml = '
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('https://example.com/article', $items[0]->get_link());
}
public function testAtomGetTitle(): void {
$xml = '
Atom Entry Title
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('Atom Entry Title', $items[0]->get_title());
}
public function testAtomGetContentFromContent(): void {
$xml = '
Full content]]>
Short summary
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$content = $items[0]->get_content();
$this->assertStringContainsString('Full content', $content);
}
public function testAtomGetContentReturnsContentOnly(): void {
$xml = '
Short
This is a much longer summary with more details
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
// Atom get_content() returns only , not
$this->assertEquals('Short', $items[0]->get_content());
}
// ===== Edge Cases =====
public function testRssEmptyItemReturnsEmptyStrings(): void {
$xml = '
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('', $items[0]->get_link());
$this->assertEquals('', $items[0]->get_title());
}
public function testAtomEmptyEntryReturnsEmptyStrings(): void {
$xml = '
';
$parser = new FeedParser($xml);
$parser->init();
$items = $parser->get_items();
$this->assertCount(1, $items);
$this->assertEquals('', $items[0]->get_link());
$this->assertEquals('', $items[0]->get_title());
}
// ===== FeedItem_Common::normalize_categories() Tests =====
public function testNormalizeCategoriesHandlesSingleCategory(): void {
$cats = ['Technology'];
$result = FeedItem_Common::normalize_categories($cats);
$this->assertCount(1, $result);
$this->assertContains('technology', $result);
}
public function testNormalizeCategoriesHandlesCommaSeparatedCategories(): void {
$cats = ['Tech,News,Programming'];
$result = FeedItem_Common::normalize_categories($cats);
$this->assertCount(3, $result);
$this->assertContains('tech', $result);
$this->assertContains('news', $result);
$this->assertContains('programming', $result);
}
public function testNormalizeCategoriesConvertsToLowercase(): void {
$cats = ['TECHNOLOGY', 'NeWs', 'PrOgRaMmInG'];
$result = FeedItem_Common::normalize_categories($cats);
$this->assertContains('technology', $result);
$this->assertContains('news', $result);
$this->assertContains('programming', $result);
$this->assertNotContains('TECHNOLOGY', $result);
}
public function testNormalizeCategoriesTrimsWhitespace(): void {
$cats = [' technology ', ' news ', 'programming'];
$result = FeedItem_Common::normalize_categories($cats);
$this->assertContains('technology', $result);
$this->assertContains('news', $result);
$this->assertNotContains(' technology ', $result);
}
public function testNormalizeCategoriesRemovesDuplicates(): void {
$cats = ['tech', 'Tech', 'TECH', 'technology', 'tech'];
$result = FeedItem_Common::normalize_categories($cats);
// After lowercase normalization, 'tech' appears 4 times, 'technology' once
$this->assertContains('tech', $result);
$this->assertContains('technology', $result);
// Count occurrences - 'tech' should appear only once
$tech_count = count(array_filter($result, fn($c) => $c === 'tech'));
$this->assertEquals(1, $tech_count);
}
public function testNormalizeCategoriesRemovesEmptyValues(): void {
$cats = ['tech', '', ' ', 'news', ''];
$result = FeedItem_Common::normalize_categories($cats);
$this->assertCount(2, $result);
$this->assertContains('tech', $result);
$this->assertContains('news', $result);
$this->assertNotContains('', $result);
}
public function testNormalizeCategoriesHandlesNumericTags(): void {
$cats = ['123', '456'];
$result = FeedItem_Common::normalize_categories($cats);
// Numeric tags are prefixed with 't:'
$this->assertContains('t:123', $result);
$this->assertContains('t:456', $result);
$this->assertNotContains('123', $result);
}
public function testNormalizeCategoriesRemovesSpecialCharacters(): void {
$cats = ["tech,news", "tech'news", 'tech"news'];
$result = FeedItem_Common::normalize_categories($cats);
// Commas split categories, quotes are removed
$this->assertContains('tech', $result);
$this->assertContains('news', $result);
$this->assertContains('technews', $result);
}
public function testNormalizeCategoriesTruncatesLongCategories(): void {
$long_cat = str_repeat('a', 300);
$cats = [$long_cat];
$result = FeedItem_Common::normalize_categories($cats);
$this->assertCount(1, $result);
$this->assertEquals(250, mb_strlen($result[0]));
$this->assertEquals(str_repeat('a', 250), $result[0]);
}
public function testNormalizeCategoriesHandlesMultibyteCharacters(): void {
$cats = ['技術', 'ニュース', '日本'];
$result = FeedItem_Common::normalize_categories($cats);
$this->assertCount(3, $result);
$this->assertContains('技術', $result);
$this->assertContains('ニュース', $result);
$this->assertContains('日本', $result);
}
public function testNormalizeCategoriesSortsResults(): void {
$cats = ['zebra', 'apple', 'mango', 'banana'];
$result = FeedItem_Common::normalize_categories($cats);
// Results should be sorted alphabetically
$expected = ['apple', 'banana', 'mango', 'zebra'];
$this->assertEquals($expected, array_values($result));
}
public function testNormalizeCategoriesHandlesEmptyArray(): void {
$cats = [];
$result = FeedItem_Common::normalize_categories($cats);
$this->assertIsArray($result);
$this->assertEmpty($result);
}
public function testNormalizeCategoriesHandlesComplexInput(): void {
$cats = [
'Tech,News',
' PROGRAMMING ',
'123',
'Tech', // duplicate
"tech'news", // special chars
'', // empty
str_repeat('x', 300), // too long
];
$result = FeedItem_Common::normalize_categories($cats);
// Should contain: tech, news, programming, t:123, technews, xxx... (250 chars)
$this->assertContains('tech', $result);
$this->assertContains('news', $result);
$this->assertContains('programming', $result);
$this->assertContains('t:123', $result);
$this->assertContains('technews', $result);
$this->assertContains(str_repeat('x', 250), $result);
// Count occurrences - 'tech' should appear only once despite duplicates
$tech_count = count(array_filter($result, fn($c) => $c === 'tech'));
$this->assertEquals(1, $tech_count);
}
}