fix readme repo diagram, add agents.md
Some checks failed
CI - Multi-Platform Native / Build iOS (RSSuper) (push) Has been cancelled
CI - Multi-Platform Native / Build macOS (push) Has been cancelled
CI - Multi-Platform Native / Build Android (push) Has been cancelled
CI - Multi-Platform Native / Build Linux (push) Has been cancelled
CI - Multi-Platform Native / Integration Tests (push) Has been cancelled
CI - Multi-Platform Native / Build Summary (push) Has been cancelled
Some checks failed
CI - Multi-Platform Native / Build iOS (RSSuper) (push) Has been cancelled
CI - Multi-Platform Native / Build macOS (push) Has been cancelled
CI - Multi-Platform Native / Build Android (push) Has been cancelled
CI - Multi-Platform Native / Build Linux (push) Has been cancelled
CI - Multi-Platform Native / Integration Tests (push) Has been cancelled
CI - Multi-Platform Native / Build Summary (push) Has been cancelled
This commit is contained in:
175
AGENTS.md
Normal file
175
AGENTS.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# AGENTS.md - RSSuper Development Guide
|
||||
|
||||
This file provides guidelines for AI agents working on the RSSuper codebase.
|
||||
|
||||
## Project Overview
|
||||
|
||||
RSSuper is a native multi-platform RSS reader:
|
||||
- **iOS/macOS**: Swift + SwiftUI + Xcode
|
||||
- **Android**: Kotlin + Jetpack Compose + Gradle
|
||||
- **Linux**: Vala + GTK4 + Libadwaita + Meson
|
||||
- **Windows**: Planned (C# + WinUI3)
|
||||
|
||||
## Build Commands
|
||||
|
||||
### Main Build Script (all platforms)
|
||||
```bash
|
||||
./scripts/build.sh # Build all platforms (debug)
|
||||
./scripts/build.sh -p ios,android # Build specific platforms
|
||||
./scripts/build.sh -t release # Release build
|
||||
./scripts/build.sh --test # Build and test
|
||||
./scripts/build.sh -a clean # Clean all
|
||||
```
|
||||
|
||||
### iOS/macOS
|
||||
```bash
|
||||
./scripts/build-ios.sh # Debug build
|
||||
./scripts/build-ios.sh Release iOS build # Release build
|
||||
./scripts/build-ios.sh Debug iOS test # Run tests
|
||||
./scripts/build-ios.sh Debug iOS clean # Clean
|
||||
|
||||
# Single test file (in Xcode)
|
||||
xcodebuild test -scheme RSSuper -destination 'platform=iOS Simulator,name=iPhone 15' \
|
||||
-only-testing:RSSuperTests/SearchQueryTests
|
||||
```
|
||||
|
||||
### Android
|
||||
```bash
|
||||
cd android && ./gradlew assembleDebug # Debug APK
|
||||
cd android && ./gradlew assembleRelease # Release APK
|
||||
cd android && ./gradlew test # Run all unit tests
|
||||
cd android && ./gradlew test --tests "com.rssuper.search.SearchQueryTest" # Single test class
|
||||
cd android && ./gradlew clean # Clean
|
||||
|
||||
# Single test via Gradle
|
||||
cd android && ./gradlew test --tests "com.rssuper.search.SearchQueryTest.testParse*"
|
||||
```
|
||||
|
||||
### Linux
|
||||
```bash
|
||||
./scripts/build-linux.sh debug build # Debug build
|
||||
./scripts/build-linux.sh release test # Run tests
|
||||
./scripts/build-linux.sh debug clean # Clean
|
||||
```
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### General Principles
|
||||
- Write clean, readable code with minimal comments (only when logic is complex)
|
||||
- Follow existing patterns in each platform's codebase
|
||||
- Use dependency injection for testability
|
||||
- Prefer explicit over implicit
|
||||
|
||||
### Kotlin (Android)
|
||||
- **Formatting**: 4 spaces indentation, 140 char line limit
|
||||
- **Naming**: `camelCase` for functions/variables, `PascalCase` for classes
|
||||
- **Imports**: Grouped: standard library → Android → third-party → project
|
||||
- **Types**: Use Kotlin null safety, prefer `val` over `var`
|
||||
- **Error Handling**: Use `Result<T>` or sealed classes for errors (see `SearchQuery.kt`)
|
||||
- **Coroutines**: Use `viewModelScope` in ViewModels, structured concurrency
|
||||
- **Tests**: JUnit 4 with Mockito, Robolectric for Android-specific tests
|
||||
|
||||
### Swift (iOS/macOS)
|
||||
- **Formatting**: 4 spaces, 120 char line limit
|
||||
- **Naming**: `camelCase`, `PascalCase` for types/protocols
|
||||
- **Imports**: Foundation → SwiftUI/AppKit → third-party → project
|
||||
- **Error Handling**: Use `Result<T, Error>` and `async/await`
|
||||
- **Protocols**: Use protocols for dependency injection (see `FeedServiceProtocol`)
|
||||
- **Tests**: XCTest, arrange/act/assert pattern
|
||||
|
||||
### Vala (Linux)
|
||||
- **Formatting**: 4 spaces indentation
|
||||
- **Naming**: `snake_case` for methods/variables, `PascalCase` for classes
|
||||
- **Memory**: Use GLib's reference counting (`ref`/`unref`)
|
||||
- **Error Handling**: Use `GLib.Error` and `try/catch`
|
||||
|
||||
### Android-specific
|
||||
- **ViewModels**: Use `androidx.lifecycle.ViewModel` with `StateFlow`
|
||||
- **Database**: Room with Kotlin coroutines
|
||||
- **Background Work**: WorkManager for sync tasks
|
||||
|
||||
### iOS-specific
|
||||
- **State Management**: `@Observable` macro (iOS 17+) or `ObservableObject`
|
||||
- **Persistence**: SQLite via SQLite.swift
|
||||
- **Background**: BGTaskScheduler for background refresh
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Clean Architecture Layers
|
||||
1. **UI Layer**: SwiftUI Views / Jetpack Compose
|
||||
2. **ViewModel/ViewModel**: Business logic, state management
|
||||
3. **Service Layer**: `FeedService`, `SearchService`, `BookmarkStore`
|
||||
4. **Data Layer**: Database managers, network clients
|
||||
|
||||
### Dependency Injection
|
||||
- Android: Manual DI in constructors (no framework)
|
||||
- iOS: Protocol-based DI with default implementations
|
||||
|
||||
## Testing Guidelines
|
||||
|
||||
### Unit Tests Location
|
||||
- **Android**: `android/src/test/java/com/rssuper/`
|
||||
- **iOS**: `iOS/RSSuperTests/`
|
||||
- **Linux**: Test files alongside source in `linux/src/`
|
||||
|
||||
### Test Naming Convention
|
||||
- `MethodName_State_ExpectedResult` (e.g., `SearchQueryTest.parseEmptyQueryReturnsNull`)
|
||||
|
||||
### Test Data
|
||||
- Fixtures in `tests/fixtures/` (sample RSS/Atom feeds)
|
||||
|
||||
## File Organization
|
||||
|
||||
```
|
||||
RSSuper/
|
||||
├── android/ # Kotlin Android library
|
||||
│ ├── src/main/java/com/rssuper/
|
||||
│ │ ├── model/ # Data models
|
||||
│ │ ├── parsing/ # Feed parsers
|
||||
│ │ ├── state/ # State management
|
||||
│ │ ├── viewmodel/ # ViewModels
|
||||
│ │ ├── search/ # Search service
|
||||
│ │ └── database/ # Room database
|
||||
│ └── src/test/ # Unit tests
|
||||
├── iOS/RSSuper/ # Swift iOS app
|
||||
│ ├── Models/ # Data models
|
||||
│ ├── Parsing/ # Feed parsers
|
||||
│ ├── Services/ # Business logic
|
||||
│ ├── ViewModels/ # ViewModels
|
||||
│ ├── Networking/ # HTTP client
|
||||
│ ├── Settings/ # User preferences
|
||||
│ └── Database/ # SQLite layer
|
||||
├── iOS/RSSuperTests/ # Unit tests
|
||||
├── linux/ # Vala GTK app
|
||||
│ └── src/ # Source + tests
|
||||
├── scripts/ # Build scripts
|
||||
└── tests/fixtures/ # Test data
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Running a Single Android Test
|
||||
```bash
|
||||
cd android
|
||||
./gradlew test --tests "com.rssuper.search.SearchQueryTest"
|
||||
```
|
||||
|
||||
### Running a Single iOS Test
|
||||
```bash
|
||||
./scripts/build-ios.sh Debug iOS test
|
||||
# Or in Xcode: Product > Run Tests (select specific test)
|
||||
```
|
||||
|
||||
### Adding a New Platform Module
|
||||
1. Create directory under `native-route/`
|
||||
2. Add build command to `./scripts/build.sh`
|
||||
3. Add test configuration to CI workflow
|
||||
4. Update this AGENTS.md
|
||||
|
||||
## Important Notes
|
||||
|
||||
- The Android project uses a library module structure (not application)
|
||||
- iOS minimum deployment: iOS 16.0+
|
||||
- Android minimum SDK: 24 (Android 7.0)
|
||||
- Linux requires GTK4, Libadwaita, SQLite3 development headers
|
||||
- All platform modules share similar business logic patterns
|
||||
@@ -39,11 +39,10 @@ RSSuper uses a native-first approach, building truly native applications for eac
|
||||
|
||||
```
|
||||
RSSuper/
|
||||
├── native-route/ # Native platform projects
|
||||
│ ├── ios/ # iOS/macOS Xcode project
|
||||
│ ├── android/ # Android Gradle project
|
||||
│ ├── linux/ # Linux Meson project
|
||||
│ └── windows/ # Windows project (planned)
|
||||
ios/ # iOS/macOS Xcode project
|
||||
android/ # Android Gradle project
|
||||
linux/ # Linux Meson project
|
||||
windows/ # Windows project (planned)
|
||||
├── scripts/ # Build scripts
|
||||
│ ├── build.sh # Main build orchestrator
|
||||
│ ├── build-ios.sh # iOS/macOS builder
|
||||
|
||||
@@ -329,8 +329,10 @@ class FeedIntegrationTest {
|
||||
val fetchResult = feedFetcher.fetch(feedUrl)
|
||||
assertTrue("Fetch should succeed", fetchResult.isSuccess())
|
||||
|
||||
assertThrows<Exception> {
|
||||
try {
|
||||
feedParser.parse(fetchResult.getOrNull()!!.feedXml, feedUrl)
|
||||
fail("Parsing invalid XML should throw exception")
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21
linux/gsettings/org.rssuper.app.settings.gschema.xml
Normal file
21
linux/gsettings/org.rssuper.app.settings.gschema.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schemalist>
|
||||
<schema id="org.rssuper.app.settings" path="/org/rssuper/app/settings/">
|
||||
<key type="s" name="reading-prefs-file">
|
||||
<default>'reading_preferences.json'</default>
|
||||
<description>Reading preferences file name</description>
|
||||
</key>
|
||||
<key type="s" name="sync-prefs-file">
|
||||
<default>'sync_preferences.json'</default>
|
||||
<description>Sync preferences file name</description>
|
||||
</key>
|
||||
<key type="b" name="background-sync-enabled">
|
||||
<default>false</default>
|
||||
<description>Enable background sync</description>
|
||||
</key>
|
||||
<key type="i" name="sync-interval-minutes">
|
||||
<default>15</default>
|
||||
<description>Sync interval in minutes</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
@@ -20,6 +20,19 @@ xml_dep = dependency('libxml-2.0', version: '>= 2.0')
|
||||
soup_dep = dependency('libsoup-3.0', version: '>= 3.0')
|
||||
gtk_dep = dependency('gtk4', version: '>= 4.0')
|
||||
|
||||
# GSettings schemas
|
||||
schema_files = [
|
||||
'gsettings/org.rssuper.notification.preferences.gschema.xml',
|
||||
'gsettings/org.rssuper.app.settings.gschema.xml',
|
||||
]
|
||||
|
||||
compile_schemas = custom_target('Compile GSettings schemas',
|
||||
output: 'schemas.glibdir',
|
||||
command: glib_dep.get_variable(name: 'glib-mkenums') + ' --targetdir=build --schema-dir=gsettings schemas.glibdir',
|
||||
dependencies: glib_dep,
|
||||
install: false
|
||||
)
|
||||
|
||||
# Source files
|
||||
models = files(
|
||||
'src/models/feed-item.vala',
|
||||
@@ -32,6 +45,13 @@ models = files(
|
||||
'src/models/bookmark.vala',
|
||||
)
|
||||
|
||||
# Settings files
|
||||
settings = files(
|
||||
'src/settings-store.vala',
|
||||
'src/app-settings.vala',
|
||||
'src/notification-preferences-store.vala',
|
||||
)
|
||||
|
||||
# Database files
|
||||
database = files(
|
||||
'src/database/db-error.vala',
|
||||
@@ -76,6 +96,13 @@ models_lib = library('rssuper-models', models,
|
||||
install: false
|
||||
)
|
||||
|
||||
# Settings library
|
||||
settings_lib = library('rssuper-settings', settings,
|
||||
dependencies: [glib_dep, gio_dep, json_dep],
|
||||
link_with: [models_lib],
|
||||
install: false
|
||||
)
|
||||
|
||||
# Database library
|
||||
database_lib = library('rssuper-database', database,
|
||||
dependencies: [glib_dep, gio_dep, json_dep, sqlite_dep, gobject_dep],
|
||||
@@ -153,9 +180,19 @@ notification_manager_test_exe = executable('notification-manager-tests',
|
||||
install: false
|
||||
)
|
||||
|
||||
# Settings store test executable
|
||||
settings_store_test_exe = executable('settings-store-tests',
|
||||
'src/tests/settings-store-tests.vala',
|
||||
dependencies: [glib_dep, gio_dep, json_dep],
|
||||
link_with: [models_lib, settings_lib],
|
||||
vala_args: ['--vapidir', '.', '--pkg', 'gio-2.0'],
|
||||
install: false
|
||||
)
|
||||
|
||||
# Test definitions
|
||||
test('database tests', test_exe)
|
||||
test('parser tests', parser_test_exe)
|
||||
test('feed fetcher tests', fetcher_test_exe)
|
||||
test('notification service tests', notification_service_test_exe)
|
||||
test('notification manager tests', notification_manager_test_exe)
|
||||
test('settings store tests', settings_store_test_exe)
|
||||
|
||||
162
linux/src/app-settings.vala
Normal file
162
linux/src/app-settings.vala
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* app-settings.vala
|
||||
*
|
||||
* Application settings interface and utilities.
|
||||
* Provides a unified interface for accessing application settings.
|
||||
*/
|
||||
|
||||
using GLib;
|
||||
|
||||
namespace RSSuper {
|
||||
|
||||
/**
|
||||
* AppSettings - Application settings interface
|
||||
*
|
||||
* Provides access to all application-level settings including:
|
||||
* - Reading preferences
|
||||
* - Sync preferences
|
||||
* - Theme settings
|
||||
* - Language settings
|
||||
*/
|
||||
public class AppSettings : Object {
|
||||
|
||||
// Singleton instance
|
||||
private static AppSettings? _instance;
|
||||
|
||||
// Settings store
|
||||
private SettingsStore? _settings_store;
|
||||
|
||||
// Theme
|
||||
private Theme _theme;
|
||||
|
||||
// Language
|
||||
private string _language;
|
||||
|
||||
// GSettings schema key
|
||||
private const string SCHEMA_KEY = "org.rssuper.app.settings";
|
||||
|
||||
/**
|
||||
* Get singleton instance
|
||||
*/
|
||||
public static AppSettings? get_instance() {
|
||||
if (_instance == null) {
|
||||
_instance = new AppSettings();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
private AppSettings() {
|
||||
_settings_store = SettingsStore.get_instance();
|
||||
|
||||
// Load theme
|
||||
_theme = Theme.SYSTEM;
|
||||
_language = "en";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reading preferences
|
||||
*/
|
||||
public ReadingPreferences? get_reading_preferences() {
|
||||
return _settings_store.get_reading_preferences();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set reading preferences
|
||||
*/
|
||||
public void set_reading_preferences(ReadingPreferences prefs) {
|
||||
_settings_store.set_reading_preferences(prefs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get background sync enabled
|
||||
*/
|
||||
public bool get_background_sync_enabled() {
|
||||
return _settings_store.get_background_sync_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set background sync enabled
|
||||
*/
|
||||
public void set_background_sync_enabled(bool enabled) {
|
||||
_settings_store.set_background_sync_enabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sync interval in minutes
|
||||
*/
|
||||
public int get_sync_interval_minutes() {
|
||||
return _settings_store.get_sync_interval_minutes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sync interval in minutes
|
||||
*/
|
||||
public void set_sync_interval_minutes(int minutes) {
|
||||
_settings_store.set_sync_interval_minutes(minutes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get theme
|
||||
*/
|
||||
public Theme get_theme() {
|
||||
return _theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set theme
|
||||
*/
|
||||
public void set_theme(Theme theme) {
|
||||
_theme = theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get language
|
||||
*/
|
||||
public string get_language() {
|
||||
return _language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set language
|
||||
*/
|
||||
public void set_language(string language) {
|
||||
_language = language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all settings as dictionary
|
||||
*/
|
||||
public Dictionary<string, object> get_all_settings() {
|
||||
return _settings_store.get_all_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all settings from dictionary
|
||||
*/
|
||||
public void set_all_settings(Dictionary<string, object> settings) {
|
||||
_settings_store.set_all_settings(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all settings to defaults
|
||||
*/
|
||||
public void reset_to_defaults() {
|
||||
_settings_store.reset_to_defaults();
|
||||
_theme = Theme.SYSTEM;
|
||||
_language = "en";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme - Available theme options
|
||||
*/
|
||||
public enum RSSuper.Theme {
|
||||
SYSTEM,
|
||||
LIGHT,
|
||||
DARK
|
||||
}
|
||||
|
||||
}
|
||||
224
linux/src/tests/settings-store-tests.vala
Normal file
224
linux/src/tests/settings-store-tests.vala
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* settings-store-tests.vala
|
||||
*
|
||||
* Unit tests for settings store.
|
||||
*/
|
||||
|
||||
using GLib;
|
||||
|
||||
namespace RSSuper {
|
||||
|
||||
public void main(string[] args) {
|
||||
print("Running Settings Store Tests\n");
|
||||
print("============================\n\n");
|
||||
|
||||
// Test ReadingPreferences
|
||||
test_reading_preferences();
|
||||
|
||||
// Test SettingsStore
|
||||
test_settings_store();
|
||||
|
||||
// Test AppSettings
|
||||
test_app_settings();
|
||||
|
||||
print("\nAll tests passed!\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ReadingPreferences
|
||||
*/
|
||||
private void test_reading_preferences() {
|
||||
print("Testing ReadingPreferences...\n");
|
||||
|
||||
// Test default constructor
|
||||
var prefs = new ReadingPreferences();
|
||||
assert(prefs.font_size == FontSize.MEDIUM);
|
||||
assert(prefs.line_height == LineHeight.NORMAL);
|
||||
assert(prefs.show_table_of_contents == true);
|
||||
assert(prefs.show_reading_time == true);
|
||||
assert(prefs.show_author == true);
|
||||
assert(prefs.show_date == true);
|
||||
print(" ✓ Default constructor sets correct defaults\n");
|
||||
|
||||
// Test with_values constructor
|
||||
var prefs2 = new ReadingPreferences.with_values(
|
||||
FontSize.LARGE,
|
||||
LineHeight.RELAXED,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
);
|
||||
assert(prefs2.font_size == FontSize.LARGE);
|
||||
assert(prefs2.line_height == LineHeight.RELAXED);
|
||||
assert(prefs2.show_table_of_contents == false);
|
||||
assert(prefs2.show_reading_time == false);
|
||||
assert(prefs2.show_author == false);
|
||||
assert(prefs2.show_date == false);
|
||||
print(" ✓ with_values constructor sets correct values\n");
|
||||
|
||||
// Test to_json_string
|
||||
var json_str = prefs.to_json_string();
|
||||
assert(json_str.contains("fontSize"));
|
||||
assert(json_str.contains("lineHeight"));
|
||||
assert(json_str.contains("showTableOfContents"));
|
||||
print(" ✓ to_json_string produces valid JSON\n");
|
||||
|
||||
// Test from_json_string
|
||||
var prefs3 = ReadingPreferences.from_json_string(json_str);
|
||||
assert(prefs3 != null);
|
||||
assert(prefs3.font_size == FontSize.MEDIUM);
|
||||
print(" ✓ from_json_string parses JSON correctly\n");
|
||||
|
||||
// Test font_size_from_string
|
||||
assert(ReadingPreferences.font_size_from_string("small") == FontSize.SMALL);
|
||||
assert(ReadingPreferences.font_size_from_string("medium") == FontSize.MEDIUM);
|
||||
assert(ReadingPreferences.font_size_from_string("large") == FontSize.LARGE);
|
||||
assert(ReadingPreferences.font_size_from_string("xlarge") == FontSize.XLARGE);
|
||||
assert(ReadingPreferences.font_size_from_string("invalid") == FontSize.MEDIUM);
|
||||
print(" ✓ font_size_from_string parses correctly\n");
|
||||
|
||||
// Test line_height_from_string
|
||||
assert(ReadingPreferences.line_height_from_string("normal") == LineHeight.NORMAL);
|
||||
assert(ReadingPreferences.line_height_from_string("relaxed") == LineHeight.RELAXED);
|
||||
assert(ReadingPreferences.line_height_from_string("loose") == LineHeight.LOOSE);
|
||||
assert(ReadingPreferences.line_height_from_string("invalid") == LineHeight.NORMAL);
|
||||
print(" ✓ line_height_from_string parses correctly\n");
|
||||
|
||||
// Test equals
|
||||
assert(prefs.equals(prefs2) == false);
|
||||
var prefs4 = new ReadingPreferences();
|
||||
assert(prefs.equals(prefs4) == true);
|
||||
print(" ✓ equals works correctly\n");
|
||||
|
||||
// Test copy_from
|
||||
var prefs5 = new ReadingPreferences();
|
||||
prefs5.copy_from(prefs2);
|
||||
assert(prefs5.font_size == FontSize.LARGE);
|
||||
assert(prefs5.line_height == LineHeight.RELAXED);
|
||||
print(" ✓ copy_from copies values correctly\n");
|
||||
|
||||
// Test reset_to_defaults
|
||||
prefs.font_size = FontSize.LARGE;
|
||||
prefs.reset_to_defaults();
|
||||
assert(prefs.font_size == FontSize.MEDIUM);
|
||||
print(" ✓ reset_to_defaults resets to defaults\n");
|
||||
|
||||
print("ReadingPreferences tests passed!\n\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test SettingsStore
|
||||
*/
|
||||
private void test_settings_store() {
|
||||
print("Testing SettingsStore...\n");
|
||||
|
||||
// Test singleton pattern
|
||||
var store1 = SettingsStore.get_instance();
|
||||
var store2 = SettingsStore.get_instance();
|
||||
assert(store1 == store2);
|
||||
print(" ✓ Singleton pattern works correctly\n");
|
||||
|
||||
// Test reading preferences
|
||||
var prefs = new ReadingPreferences.with_values(FontSize.LARGE);
|
||||
store1.set_reading_preferences(prefs);
|
||||
var retrieved_prefs = store1.get_reading_preferences();
|
||||
assert(retrieved_prefs != null);
|
||||
assert(retrieved_prefs.font_size == FontSize.LARGE);
|
||||
print(" ✓ Reading preferences stored and retrieved correctly\n");
|
||||
|
||||
// Test background sync enabled
|
||||
store1.set_background_sync_enabled(true);
|
||||
assert(store1.get_background_sync_enabled() == true);
|
||||
store1.set_background_sync_enabled(false);
|
||||
assert(store1.get_background_sync_enabled() == false);
|
||||
print(" ✓ Background sync enabled works correctly\n");
|
||||
|
||||
// Test sync interval
|
||||
store1.set_sync_interval_minutes(30);
|
||||
assert(store1.get_sync_interval_minutes() == 30);
|
||||
store1.set_sync_interval_minutes(15);
|
||||
assert(store1.get_sync_interval_minutes() == 15);
|
||||
print(" ✓ Sync interval works correctly\n");
|
||||
|
||||
// Test get_all_settings
|
||||
var all_settings = store1.get_all_settings();
|
||||
assert(all_settings.containsKey("fontSize"));
|
||||
assert(all_settings.containsKey("backgroundSyncEnabled"));
|
||||
assert(all_settings.containsKey("syncIntervalMinutes"));
|
||||
print(" ✓ get_all_settings returns correct keys\n");
|
||||
|
||||
// Test set_all_settings
|
||||
var new_settings = new Dictionary<string, object>();
|
||||
new_settings["fontSize"] = "large";
|
||||
new_settings["backgroundSyncEnabled"] = true;
|
||||
new_settings["syncIntervalMinutes"] = 60;
|
||||
store1.set_all_settings(new_settings);
|
||||
assert(store1.get_reading_preferences().font_size == FontSize.LARGE);
|
||||
assert(store1.get_background_sync_enabled() == true);
|
||||
assert(store1.get_sync_interval_minutes() == 60);
|
||||
print(" ✓ set_all_settings sets all values correctly\n");
|
||||
|
||||
// Test reset_to_defaults
|
||||
store1.reset_to_defaults();
|
||||
assert(store1.get_reading_preferences().font_size == FontSize.MEDIUM);
|
||||
assert(store1.get_background_sync_enabled() == false);
|
||||
assert(store1.get_sync_interval_minutes() == 15);
|
||||
print(" ✓ reset_to_defaults resets all values\n");
|
||||
|
||||
print("SettingsStore tests passed!\n\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test AppSettings
|
||||
*/
|
||||
private void test_app_settings() {
|
||||
print("Testing AppSettings...\n");
|
||||
|
||||
// Test singleton pattern
|
||||
var settings1 = AppSettings.get_instance();
|
||||
var settings2 = AppSettings.get_instance();
|
||||
assert(settings1 == settings2);
|
||||
print(" ✓ Singleton pattern works correctly\n");
|
||||
|
||||
// Test theme
|
||||
settings1.set_theme(Theme.DARK);
|
||||
assert(settings1.get_theme() == Theme.DARK);
|
||||
settings1.set_theme(Theme.LIGHT);
|
||||
assert(settings1.get_theme() == Theme.LIGHT);
|
||||
settings1.set_theme(Theme.SYSTEM);
|
||||
assert(settings1.get_theme() == Theme.SYSTEM);
|
||||
print(" ✓ Theme works correctly\n");
|
||||
|
||||
// Test language
|
||||
settings1.set_language("en");
|
||||
assert(settings1.get_language() == "en");
|
||||
settings1.set_language("es");
|
||||
assert(settings1.get_language() == "es");
|
||||
print(" ✓ Language works correctly\n");
|
||||
|
||||
// Test reading preferences through AppSettings
|
||||
var prefs = new ReadingPreferences.with_values(FontSize.XLARGE);
|
||||
settings1.set_reading_preferences(prefs);
|
||||
var retrieved_prefs = settings1.get_reading_preferences();
|
||||
assert(retrieved_prefs != null);
|
||||
assert(retrieved_prefs.font_size == FontSize.XLARGE);
|
||||
print(" ✓ Reading preferences through AppSettings works\n");
|
||||
|
||||
// Test sync settings through AppSettings
|
||||
settings1.set_background_sync_enabled(true);
|
||||
assert(settings1.get_background_sync_enabled() == true);
|
||||
settings1.set_sync_interval_minutes(45);
|
||||
assert(settings1.get_sync_interval_minutes() == 45);
|
||||
print(" ✓ Sync settings through AppSettings works\n");
|
||||
|
||||
// Test reset_to_defaults
|
||||
settings1.reset_to_defaults();
|
||||
assert(settings1.get_theme() == Theme.SYSTEM);
|
||||
assert(settings1.get_language() == "en");
|
||||
print(" ✓ reset_to_defaults works correctly\n");
|
||||
|
||||
print("AppSettings tests passed!\n\n");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user