feat: implement cross-platform features and UI integration

- iOS: Add BackgroundSyncService, SyncScheduler, SyncWorker, BookmarkViewModel, FeedViewModel
- iOS: Add BackgroundSyncService, SyncScheduler, SyncWorker services
- Linux: Add settings-store.vala, State.vala signals, view widgets (FeedList, FeedDetail, AddFeed, Search, Settings, Bookmark)
- Linux: Add bookmark-store.vala, bookmark vala model, search-service.vala
- Android: Add NotificationService, NotificationManager, NotificationPreferencesStore
- Android: Add BookmarkDao, BookmarkRepository, SettingsStore
- Add unit tests for iOS, Android, Linux
- Add integration tests
- Add performance benchmarks
- Update tasks and documentation

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-03-30 23:06:12 -04:00
parent 6191458730
commit 14efe072fa
98 changed files with 11262 additions and 109 deletions

52
tests/fixtures/sample-atom.xml vendored Normal file
View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Test Atom Feed</title>
<link href="https://example.com" rel="alternate"/>
<link href="https://example.com/feed.xml" rel="self"/>
<id>https://example.com/feed.xml</id>
<updated>2026-03-31T12:00:00Z</updated>
<author>
<name>Test Author</name>
<email>test@example.com</email>
</author>
<generator>RSSuper Test Generator</generator>
<entry>
<title>Test Article 1</title>
<link href="https://example.com/article1" rel="alternate"/>
<id>https://example.com/article1</id>
<updated>2026-03-31T10:00:00Z</updated>
<published>2026-03-31T10:00:00Z</published>
<author>
<name>Test Author</name>
</author>
<summary type="html">This is the first test article</summary>
<category term="technology"/>
</entry>
<entry>
<title>Test Article 2</title>
<link href="https://example.com/article2" rel="alternate"/>
<id>https://example.com/article2</id>
<updated>2026-03-31T11:00:00Z</updated>
<published>2026-03-31T11:00:00Z</published>
<author>
<name>Test Author</name>
</author>
<summary type="html">This is the second test article</summary>
<category term="news"/>
</entry>
<entry>
<title>Test Article 3</title>
<link href="https://example.com/article3" rel="alternate"/>
<id>https://example.com/article3</id>
<updated>2026-03-31T12:00:00Z</updated>
<published>2026-03-31T12:00:00Z</published>
<author>
<name>Test Author</name>
</author>
<summary type="html">This is the third test article with more content</summary>
<category term="technology"/>
</entry>
</feed>

40
tests/fixtures/sample-rss.xml vendored Normal file
View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>Test RSS Feed</title>
<link>https://example.com</link>
<description>A test RSS feed for integration testing</description>
<language>en-us</language>
<lastBuildDate>Mon, 31 Mar 2026 12:00:00 GMT</lastBuildDate>
<item>
<title>Test Article 1</title>
<link>https://example.com/article1</link>
<description>This is the first test article</description>
<author>test@example.com</author>
<pubDate>Mon, 31 Mar 2026 10:00:00 GMT</pubDate>
<guid>article-1</guid>
<category>technology</category>
</item>
<item>
<title>Test Article 2</title>
<link>https://example.com/article2</link>
<description>This is the second test article</description>
<author>test@example.com</author>
<pubDate>Mon, 31 Mar 2026 11:00:00 GMT</pubDate>
<guid>article-2</guid>
<category>news</category>
</item>
<item>
<title>Test Article 3</title>
<link>https://example.com/article3</link>
<description>This is the third test article with more content</description>
<author>test@example.com</author>
<pubDate>Mon, 31 Mar 2026 12:00:00 GMT</pubDate>
<guid>article-3</guid>
<category>technology</category>
</item>
</channel>
</rss>

107
tests/generate_test_data.py Executable file
View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""
Test Data Generator for RSSuper Integration Tests
Generates sample feeds and test data for cross-platform testing.
"""
import json
import random
from datetime import datetime, timedelta
from pathlib import Path
def generate_random_feed_items(count: int = 10) -> list[dict]:
"""Generate random feed items for testing."""
categories = ["technology", "news", "sports", "entertainment", "science"]
titles = [
"Understanding Modern Web Development",
"The Future of AI in Software Engineering",
"Best Practices for Database Design",
"Introduction to Functional Programming",
"Building Scalable Microservices",
"Deep Dive into React Hooks",
"Performance Optimization Techniques",
"Security Best Practices for APIs",
"Cloud Native Application Architecture",
"Introduction to GraphQL"
]
items = []
base_date = datetime.now()
for i in range(count):
item = {
"id": f"test-item-{i:03d}",
"title": titles[i % len(titles)],
"link": f"https://example.com/article{i}",
"description": f"This is test article number {i + 1}",
"author": f"author{i}@example.com",
"published": (base_date - timedelta(hours=i)).isoformat(),
"categories": [categories[i % len(categories)]],
"read": random.random() > 0.7,
"subscription_id": f"subscription-{i // 3}",
"subscription_title": f"Subscription {i // 3 + 1}"
}
items.append(item)
return items
def generate_subscription() -> dict:
"""Generate a test subscription."""
return {
"id": "test-subscription-1",
"url": "https://example.com/feed.xml",
"title": "Test Subscription",
"category": "technology",
"enabled": True,
"fetch_interval": 3600,
"created_at": datetime.now().isoformat(),
"updated_at": datetime.now().isoformat(),
"last_fetched_at": None,
"error": None
}
def generate_test_data() -> dict:
"""Generate complete test data package."""
return {
"subscriptions": [generate_subscription()],
"feed_items": generate_random_feed_items(10),
"bookmarks": [
{
"id": "bookmark-1",
"feed_item_id": "test-item-000",
"created_at": datetime.now().isoformat(),
"tags": ["important", "read-later"]
}
],
"search_history": [
{
"id": "search-1",
"query": "test query",
"timestamp": datetime.now().isoformat()
}
]
}
def save_test_data(output_path: str = "tests/fixtures/test-data.json"):
"""Save generated test data to file."""
data = generate_test_data()
output = Path(output_path)
output.parent.mkdir(parents=True, exist_ok=True)
with open(output, "w") as f:
json.dump(data, f, indent=2)
print(f"Test data saved to {output}")
return data
if __name__ == "__main__":
import sys
output_file = sys.argv[1] if len(sys.argv) > 1 else "tests/fixtures/test-data.json"
save_test_data(output_file)