From 9316e31baee0acdee1d7371e854de741cce224b8 Mon Sep 17 00:00:00 2001 From: Austin Chang Date: Mon, 5 Jan 2026 16:49:11 +0800 Subject: [PATCH 1/5] fix: resolve all flutter analyze warnings and regenerate mocks --- .../architecture_analysis_2026-01-05.md | 727 ++++++++++++++++++ .../http/transaction_http_command.dart | 4 +- lib/core/jnap/models/wirless_connection.dart | 2 +- lib/core/usp/jnap_tr181_mapper.dart | 22 +- .../internet_settings_form_validator.dart | 12 +- .../views/ipv4_connection_view.dart | 1 - .../views/ipv6_connection_view.dart | 1 - .../views/release_and_renew_view.dart | 1 - .../widgets/optional_settings_form.dart | 1 - .../wan_forms/ipv6/automatic_ipv6_form.dart | 1 - .../widgets/wan_forms/pppoe_form.dart | 6 +- .../widgets/wan_forms/pptp_form.dart | 1 - .../views/manual_firmware_update_view.dart | 2 +- .../services/instant_safety_service.dart | 2 + .../providers/pnp_isp_settings_provider.dart | 1 - .../pnp_isp_type_selection_view.dart | 1 - .../views/isp_settings/pnp_pppoe_view.dart | 1 - .../isp_settings/pnp_static_ip_view.dart | 1 - lib/route/route_add_nodes.dart | 2 +- lib/route/route_cloud_login.dart | 2 +- lib/route/route_dashboard.dart | 2 +- lib/route/route_home.dart | 2 +- lib/route/route_pnp.dart | 2 +- lib/util/extensions.dart | 2 +- lib/utils.dart | 2 +- .../src/services/usp_topology_service.dart | 2 +- .../src/converter/usp_protobuf_converter.dart | 7 - .../firmware_update_service_test.dart | 8 +- test/mocks/auth_notifier_mocks.dart | 415 ++++++---- test/mocks/dashboard_home_notifier_mocks.dart | 49 +- .../dashboard_manager_notifier_mocks.dart | 110 +-- test/mocks/device_manager_notifier_mocks.dart | 94 +-- .../internet_settings_notifier_mocks.dart | 126 +-- test/mocks/node_detail_notifier_mocks.dart | 107 +-- test/mocks/polling_notifier_mocks.dart | 29 +- .../test_data/dashboard_home_test_data.dart | 2 +- .../dashboard_manager_test_data.dart | 4 +- test/mocks/test_data/ddns_test_data.dart | 6 +- test/mocks/test_data/polling_test_data.dart | 4 +- .../port_range_forwarding_test_data.dart | 6 +- .../port_range_triggering_test_data.dart | 2 +- .../single_port_forwarding_test_data.dart | 2 +- .../test_data/static_routing_test_data.dart | 1 - .../ddns/providers/ddns_provider_test.dart | 2 +- .../port_range_forwarding_service_test.dart | 10 +- .../port_range_triggering_service_test.dart | 10 +- .../providers/dmz_settings_state_test.dart | 14 +- .../dmz/providers/dmz_status_test.dart | 2 +- .../services/dmz_settings_service_test.dart | 5 +- .../dmz_settings_service_test_data.dart | 2 +- .../providers/firewall_provider_test.dart | 1 - .../providers/firewall_state_test.dart | 14 +- .../ipv6_port_service_list_provider_test.dart | 12 +- .../ipv6_port_service_rule_state_test.dart | 6 +- .../firewall_settings_service_test.dart | 2 - .../ipv6_port_service_list_service_test.dart | 70 +- ...6_port_service_list_service_test_data.dart | 4 +- .../internet_settings_ui_model_test.dart | 8 +- .../internet_settings_service_test.dart | 32 +- .../internet_settings_view_test.dart | 1 - .../dhcp_reservations_provider_test.dart | 2 +- .../dhcp_reservations_state_test.dart | 1 - .../local_network_settings_state_test.dart | 2 - .../static_route_entry_ui_model_test.dart | 2 +- .../static_routing_rule_ui_model_test.dart | 2 +- .../static_routing_rule_provider_test.dart | 2 - .../providers/static_routing_state_test.dart | 13 +- .../services/static_routing_service_test.dart | 1 - .../localizations/snack_bar_test.dart | 3 +- .../views/components/loading_tile_test.dart | 1 - .../providers/health_check_provider_test.dart | 2 +- .../manual_firmware_update_provider_test.dart | 10 +- .../providers/timezone_state_test.dart | 1 - .../router_password_service_test.dart | 1 - .../services/timezone_service_test.dart | 6 +- .../providers/instant_privacy_state_test.dart | 4 +- .../services/instant_safety_service_test.dart | 6 +- .../instant_setup/pnp_step_state_test.dart | 2 +- .../pnp_isp_settings_provider_test.dart | 1 - .../services/pnp_isp_service_test.dart | 10 +- .../models/instant_verify_ui_models_test.dart | 8 +- .../instant_verify_provider_test.dart | 2 +- .../providers/instant_verify_state_test.dart | 4 +- .../providers/wifi_advanced_state_test.dart | 2 +- .../providers/wifi_state_test.dart | 4 +- .../services/channel_finder_service_test.dart | 8 +- .../input_validators_test.dart | 46 +- test_scripts/test_result_parser.dart | 2 + ...generate_screenshot_test_cases_report.dart | 8 +- tools/remove_unused_strings.dart | 2 + tools/run_screenshot_tests.dart | 2 + 91 files changed, 1394 insertions(+), 736 deletions(-) create mode 100644 doc/analysis/architecture_analysis_2026-01-05.md diff --git a/doc/analysis/architecture_analysis_2026-01-05.md b/doc/analysis/architecture_analysis_2026-01-05.md new file mode 100644 index 000000000..972169c8d --- /dev/null +++ b/doc/analysis/architecture_analysis_2026-01-05.md @@ -0,0 +1,727 @@ +# PrivacyGUI 專案架構分析報告 + +## 執行摘要 + +對 PrivacyGUI 專案進行了全面的架構分析,評估模組間的解耦狀況。專案整體架構設計良好,但存在若干需要改進的耦合問題。 + +--- + +## 1. 專案結構概覽 + +``` +lib/ +├── ai/ # AI 助手模組 (15 files) ✅ 解耦良好 +├── core/ # 核心基礎設施 (170 files) +│ ├── bluetooth/ # 藍牙連接 +│ ├── cache/ # 快取機制 +│ ├── cloud/ # 雲端服務 (31 files) +│ ├── http/ # HTTP 客戶端 +│ ├── jnap/ # JNAP 協議層 (99 files) ⚠️ 重度依賴 +│ ├── usp/ # USP 協議層 (11 files) +│ └── utils/ # 工具類 +├── page/ # UI 頁面模組 (391 files) +│ ├── advanced_settings/ # 136 files +│ ├── dashboard/ # 21 files +│ ├── wifi_settings/ # 36 files +│ └── ... (18 more feature modules) +├── providers/ # 全局狀態管理 (25 files) +└── route/ # 路由配置 (14 files) + +packages/ +├── usp_client_core/ # USP 協議核心 (獨立 package) +└── usp_protocol_common/ # USP 協議共享 (獨立 package) +``` + +--- + +## 2. 架構層次分析 + +### 2.1 理想的 4 層架構 (已文件化於 specs/002-dmz-refactor/) + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Data Layer (core/jnap/models/) │ +│ - JNAP domain models │ +│ - Protocol serialization (toMap/fromMap) │ +└────────────────────┬────────────────────────────────────────┘ + │ Only Service knows about these + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Service Layer (page/*/services/) │ +│ - Converts Data models ↔ UI models │ +│ - All protocol handling │ +└────────────────────┬────────────────────────────────────────┘ + │ Service returns only UI models + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Application Layer (page/*/providers/) │ +│ - UI-specific models │ +│ - Riverpod state management │ +└────────────────────┬────────────────────────────────────────┘ + │ Only UI models exposed + ↓ +┌─────────────────────────────────────────────────────────────┐ +│ Presentation Layer (page/*/views/) │ +│ - Flutter widgets │ +│ - Only knows about UI models │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 3. 解耦狀況評估 + +### ✅ 良好的解耦實踐 + +#### 3.1 AI 模組 (`lib/ai/`) +- **評分: 優秀** +- 使用 `IRouterCommandProvider` 抽象介面 +- 遵循 MCP (Model Context Protocol) 模式 +- 支援 JNAP 和 USP 的多實現切換 + +```dart +// lib/ai/abstraction/i_router_command_provider.dart +abstract class IRouterCommandProvider { + Future> listCommands(); // ≈ MCP tools/list + Future execute(...); // ≈ MCP tools/call + List listResources(); // ≈ MCP resources/list + Future readResource(...); // ≈ MCP resources/read +} +``` + +#### 3.2 USP 協議層 (`packages/`) +- **評分: 優秀** +- 獨立的 Flutter package +- 與主專案通過 `core/usp/` 橋接 +- 支援協議切換而不影響上層 + +#### 3.3 DMZ 設定模組 (`page/advanced_settings/dmz/`) +- **評分: 優秀** +- 嚴格遵循 4 層架構 +- 有 `DMZUISettings` 等 UI 專用模型 +- Service 層負責所有模型轉換 + +--- + +### ⚠️ 需要改進的耦合問題 + +#### 3.4 Provider 層直接引用 Data 模型 (詳細分析) + +**問題**: Provider 層直接 import `core/jnap/models/`,違反層次分離原則。 + +--- + +##### 3.4.1 `auto_parent_first_login_provider.dart` + +**檔案位置**: `lib/page/login/auto_parent/providers/auto_parent_first_login_provider.dart` + +**違規導入**: +```dart +import 'package:privacy_gui/core/jnap/models/firmware_update_settings.dart'; +``` + +**問題程式碼** (第 56-87 行): +```dart +Future setFirmwareUpdatePolicy() async { + final repo = ref.read(routerRepositoryProvider); + final firmwareUpdateSettings = await repo + .send(JNAPAction.getFirmwareUpdateSettings, ...) + .then((value) => value.output) + .then( + (output) => FirmwareUpdateSettings.fromMap(output).copyWith( + updatePolicy: FirmwareUpdateSettings.firmwareUpdatePolicyAuto), + ); + // ... + repo.send(JNAPAction.setFirmwareUpdateSettings, + data: firmwareUpdateSettings.toMap(), ...); +} +``` + +**問題分析**: +- Provider 直接調用 `FirmwareUpdateSettings.fromMap()` 反序列化 JNAP 響應 +- Provider 直接調用 `.toMap()` 序列化回 JNAP 格式 +- 這些是 Data 層的協議細節,不應暴露給 Application 層 + +**修復建議**: +1. 創建 UI 模型 `FirmwareUpdatePolicyUI` +2. 在新建的 `AutoParentFirstLoginService` 中處理轉換 +3. Provider 只調用 Service 方法 + +```dart +// 新增: lib/page/login/auto_parent/services/auto_parent_first_login_service.dart +class AutoParentFirstLoginService { + Future setAutoFirmwareUpdatePolicy(Ref ref) async { + final repo = ref.read(routerRepositoryProvider); + final currentSettings = await repo.send(JNAPAction.getFirmwareUpdateSettings, ...); + + // 在 Service 層處理 Data 模型 + final updated = FirmwareUpdateSettings.fromMap(currentSettings.output) + .copyWith(updatePolicy: FirmwareUpdateSettings.firmwareUpdatePolicyAuto); + + await repo.send(JNAPAction.setFirmwareUpdateSettings, data: updated.toMap()); + } +} +``` + +--- + +##### 3.4.2 `add_nodes_provider.dart` + +**檔案位置**: `lib/page/nodes/providers/add_nodes_provider.dart` + +**違規導入**: +```dart +import 'package:privacy_gui/core/jnap/models/back_haul_info.dart'; +``` + +**問題程式碼** (第 115, 226-271 行): +```dart +List backhaulInfoList = []; // 直接使用 Data 模型 + +Stream> pollNodesBackhaulInfo(...) { + return repo.scheduledCommand(...) + .transform( + StreamTransformer>.fromHandlers( + handleData: (result, sink) { + final backhaulList = List.from(result.output['backhaulDevices'] ?? []) + .map((e) => BackHaulInfoData.fromMap(e)).toList(); // 直接反序列化 + sink.add(backhaulList); + }, + ), + ); +} +``` + +**問題分析**: +- `BackHaulInfoData` 是 JNAP 協議的 Data 模型 +- Provider 直接處理 Stream 轉換和反序列化 +- `collectChildNodeData()` 方法直接操作 `BackHaulInfoData` + +**修復建議**: +1. 創建 UI 模型 `BackhaulInfoUI` 在 `lib/page/nodes/providers/add_nodes_state.dart` +2. 創建 `AddNodesService` 處理 JNAP 調用和模型轉換 +3. Provider 只持有 `BackhaulInfoUI` 列表 + +```dart +// 新增: lib/page/nodes/models/backhaul_info_ui.dart +class BackhaulInfoUI { + final String deviceUUID; + final String connectionType; + final WirelessConnectionInfo? wirelessInfo; + // ... 只包含 UI 需要的欄位 +} + +// 新增: lib/page/nodes/services/add_nodes_service.dart +class AddNodesService { + Stream> pollNodesBackhaulInfo(List nodes) { + // 在 Service 層處理 BackHaulInfoData 轉換 + } +} +``` + +--- + +##### 3.4.3 `add_wired_nodes_provider.dart` + +**檔案位置**: `lib/page/nodes/providers/add_wired_nodes_provider.dart` + +**違規導入**: +```dart +import 'package:privacy_gui/core/jnap/models/back_haul_info.dart'; +``` + +**問題程式碼** (第 145-204 行): +```dart +Stream pollBackhaulInfo(BuildContext context, [bool refreshing = false]) { + // ... + condition: (result) { + final backhaulInfoList = List.from(result.output['backhaulDevices'] ?? []) + .map((e) => BackHaulInfoData.fromMap(e)).toList(); // 直接反序列化 + // ... + }, +} +``` + +**問題分析**: +- 與 `add_nodes_provider.dart` 類似的問題 +- 存在重複的 `BackHaulInfoData.fromMap()` 調用 +- 兩個 Provider 有潛在的代碼重複 + +**修復建議**: +1. 重用 `add_nodes_provider.dart` 的解決方案 +2. 考慮合併共享的 backhaul 邏輯到統一的 Service +3. 創建 `lib/page/nodes/services/backhaul_service.dart` 處理所有 backhaul 相關邏輯 + +--- + +##### 3.4.4 `pnp_provider.dart` + +**檔案位置**: `lib/page/instant_setup/providers/pnp_provider.dart` + +**違規導入**: +```dart +import 'package:privacy_gui/core/jnap/models/auto_configuration_settings.dart'; +``` + +**問題程式碼** (第 140-143, 452-457 行): +```dart +// 抽象方法定義 +Future autoConfigurationCheck(); + +// 實現 +Future autoConfigurationCheck() { + final pnpService = ref.read(pnpServiceProvider); + return pnpService.autoConfigurationCheck(); // Service 返回 Data 模型 +} +``` + +**問題分析**: +- `AutoConfigurationSettings` 是 Data 模型,但被用作方法返回類型 +- 雖然 Provider 委託給 Service,但 Service 仍返回 Data 模型穿透了層次邊界 +- 這違反了「Service 只返回 UI 模型」的原則 + +**修復建議**: +1. 創建 `AutoConfigurationUI` 或簡化的 enum/record 類型 +2. 修改 `PnpService.autoConfigurationCheck()` 返回 UI 模型 +3. 將 `ConfigurationResult` 擴展以包含所有必要資訊 + +```dart +// 修改: lib/page/instant_setup/services/pnp_service.dart +Future autoConfigurationCheck() async { + final result = await _fetchAutoConfigSettings(); + return AutoConfigurationUI( + isConfigured: result.isConfigured, + passwordToUse: result.adminPassword, + // ... 只暴露 UI 需要的欄位 + ); +} +``` + +--- + +##### 3.4.5 `mock_pnp_providers.dart` + +**檔案位置**: `lib/page/instant_setup/providers/mock_pnp_providers.dart` + +**違規導入**: +```dart +import 'package:privacy_gui/core/jnap/models/auto_configuration_settings.dart'; +``` + +**問題分析**: +- 這是測試/Demo 用的 Mock 實現 +- 需要返回與主 Provider 相同的類型 +- 當主 Provider 修復後,此檔案需同步更新 + +--- + +#### 3.5 跨頁面 Provider 依賴 (詳細分析) + +**問題**: 頁面模組之間的 Provider 直接依賴形成了複雜的依賴網絡。 + +--- + +##### 3.5.1 依賴圖譜 + +```mermaid +graph LR + subgraph wifi_settings["wifi_settings/"] + WBP[wifi_bundle_provider] + CFP[channelfinder_provider] + DMP2[displayed_mac_filtering_devices_provider] + end + + subgraph dashboard["dashboard/"] + DHP[dashboard_home_provider] + end + + subgraph instant_device["instant_device/"] + DLP[device_list_provider] + DFLP[device_filtered_list_provider] + EDDP[external_device_detail_provider] + end + + subgraph instant_privacy["instant_privacy/"] + IPP[instant_privacy_provider] + IPDL[instant_privacy_device_list_provider] + end + + subgraph health_check["health_check/"] + HCP[health_check_provider] + end + + subgraph instant_topology["instant_topology/"] + ITP[instant_topology_provider] + end + + subgraph nodes["nodes/"] + NDP[node_detail_provider] + ANP[add_nodes_provider] + AWNP[add_wired_nodes_provider] + end + + WBP --> DHP + WBP --> IPP + DHP --> HCP + DFLP --> WBP + DMP2 --> WBP + IPDL --> IPP + NDP --> DLP +``` + +--- + +##### 3.5.2 關鍵耦合熱點分析 + +**熱點 1: `wifi_bundle_provider.dart` (高風險)** + +```dart +// 當前導入 +import 'package:privacy_gui/page/dashboard/providers/dashboard_home_provider.dart'; +import 'package:privacy_gui/page/instant_privacy/providers/instant_privacy_state.dart'; +``` + +**耦合原因分析** (第 35-81 行): +```dart +WifiBundleState build() { + final dashboardManagerState = ref.read(dashboardManagerProvider); // ✓ OK - core provider + final deviceManagerState = ref.read(deviceManagerProvider); // ✓ OK - core provider + final homeState = ref.read(dashboardHomeProvider); // ✗ 跨頁面依賴 + + final initialWifiListStatus = WiFiListStatus( + canDisableMainWiFi: homeState.lanPortConnections.isNotEmpty); // 需要 dashboard 狀態 + // ... + final initialPrivacySettings = InstantPrivacySettings.init(); // ✗ 引用 privacy 的 State +} +``` + +**問題**: +- 需要 `lanPortConnections` 來決定 WiFi 禁用能力 +- 直接引用 `InstantPrivacySettings` 類型 + +**修復建議**: +```dart +// 方案 A: 提取共享狀態到 core +// lib/core/jnap/providers/connectivity_status_provider.dart +final connectivityStatusProvider = Provider((ref) { + final dashboardState = ref.watch(dashboardManagerProvider); + return ConnectivityStatus( + hasLanConnections: dashboardState.lanPortConnections.isNotEmpty, + // ... 其他共享狀態 + ); +}); + +// 方案 B: 使用依賴注入傳遞必要資訊 +// wifi_bundle_provider.dart +WifiBundleState build() { + final hasLanConnections = ref.read(connectivityStatusProvider).hasLanConnections; + // ... +} +``` + +--- + +**熱點 2: `dashboard_home_provider.dart` → `health_check_provider.dart`** + +```dart +// lib/page/dashboard/providers/dashboard_home_provider.dart +import 'package:privacy_gui/page/health_check/providers/health_check_provider.dart'; + +class DashboardHomeNotifier extends Notifier { + @override + DashboardHomeState build() { + // Watch healthCheckProvider to maintain reactivity + ref.watch(healthCheckProvider); // ✗ 跨頁面依賴 + // ... + } +} +``` + +**問題分析**: +- Dashboard 需要知道 HealthCheck 的狀態來顯示速度測試結果 +- 這是 UI 層級的數據共享需求 + +**修復建議**: +```dart +// 方案: 將 HealthCheck 結果提取到共享層 +// lib/providers/network_health_provider.dart +final networkHealthProvider = Provider((ref) { + // 監聽底層數據,提供給多個頁面使用 + final speedTestResult = ref.watch(_speedTestResultProvider); + return NetworkHealthState(lastSpeedTest: speedTestResult); +}); +``` + +--- + +**熱點 3: `device_filtered_list_provider.dart` → `wifi_bundle_provider.dart`** + +```dart +import 'package:privacy_gui/page/wifi_settings/providers/wifi_bundle_provider.dart'; +``` + +**問題分析**: +- `device_filtered_list` 需要 WiFi 資訊來過濾裝置 +- 這創建了 `instant_device` ↔ `wifi_settings` 的雙向依賴風險 + +**修復建議**: +- 將 WiFi 狀態的「裝置可見」部分提取到 `core/jnap/providers/` +- 或創建專門的 `device_wifi_binding_provider.dart` 在 `lib/providers/` + +--- + +##### 3.5.3 跨頁面依賴完整清單 + +| 來源 Provider | 目標 Provider | 耦合類型 | 風險等級 | +|--------------|--------------|----------|----------| +| `wifi_bundle_provider` | `dashboard_home_provider` | 狀態讀取 | 🔴 高 | +| `wifi_bundle_provider` | `instant_privacy_state` | 類型引用 | 🟡 中 | +| `dashboard_home_provider` | `health_check_provider` | 反應式監聽 | 🔴 高 | +| `device_filtered_list_provider` | `wifi_bundle_provider` | 狀態讀取 | 🟡 中 | +| `displayed_mac_filtering_devices_provider` | `wifi_bundle_provider` | 狀態讀取 | 🟡 中 | +| `instant_privacy_device_list_provider` | `instant_privacy_provider` | 同模組 | 🟢 低 | +| `node_detail_provider` | `device_list_provider` | 數據共享 | 🟡 中 | + +--- + +##### 3.5.4 核心 Provider 的合理引用 + +以下導入被認為是**合理的**,因為它們引用的是 `core/jnap/providers/` 中的共享全局狀態: + +| 被引用的 Core Provider | 引用來源 (page/*) | 用途 | +|-----------------------|------------------|------| +| `dashboardManagerProvider` | 6 個頁面 | 全局 Dashboard 狀態 | +| `deviceManagerProvider` | 11 個頁面 | 裝置列表管理 | +| `pollingProvider` | 9 個頁面 | 輪詢控制 | +| `firmwareUpdateProvider` | 2 個頁面 | 韌體更新狀態 | +| `wanExternalProvider` | 1 個頁面 | WAN 狀態 | + +**這些都是設計良好的共享狀態**,應保持這種模式,但需確保: +- 這些 Provider 不直接返回 Data 模型 +- 它們提供的是 UI 友好的狀態抽象 + +--- + +#### 3.6 巨型檔案 + +| 檔案 | 大小 | 問題 | +|------|------|------| +| `core/usp/jnap_tr181_mapper.dart` | 42.5KB | JNAP↔TR-181 映射邏輯過於集中 | +| `route/router_provider.dart` | 19.8KB | 路由邏輯與認證邏輯混合 | +| `core/jnap/router_repository.dart` | 15.6KB | 多種命令類型處理混合 | +| `core/cloud/linksys_cloud_repository.dart` | 16KB | 雲端功能過於集中 | + +--- + +## 4. 模組間依賴統計 (詳細分析) + +### 4.1 核心模組被引用統計 + +#### 4.1.1 `core/jnap/providers/` 被引用分布 + +``` +dashboardManagerProvider → 6 files (wifi_settings, instant_device, dashboard) +deviceManagerProvider → 11 files (節點、設備、WiFi 相關) +pollingProvider → 9 files (需要控制輪詢的功能) +firmwareUpdateProvider → 2 files (topology, login) +device_manager_state → 7 files (使用 LinksysDevice 類型) +side_effect_provider → 1 file +wan_external_provider → 1 file +``` + +#### 4.1.2 `core/jnap/models/` 被違規引用 + +``` +firmware_update_settings.dart → 1 provider ⚠️ +back_haul_info.dart → 2 providers ⚠️ +auto_configuration_settings.dart → 2 providers ⚠️ +``` + +#### 4.1.3 跨頁面 Provider 引用熱度圖 + +``` + 被引用次數 +wifi_bundle_provider ████████ 3次 +dashboard_home_provider ██████ 2次 +device_list_provider ████ 1次 +health_check_provider ████ 1次 +instant_privacy_provider ████ 1次 +``` + +--- + +### 4.2 依賴方向與違規分析 + +```mermaid +graph TD + subgraph Presentation["Presentation Layer"] + Views[page/*/views/] + end + + subgraph Application["Application Layer"] + Providers[page/*/providers/] + SharedProviders[providers/ - 全局共享] + end + + subgraph Service["Service Layer"] + Services[page/*/services/] + CoreServices[core/*/services/] + end + + subgraph Data["Data Layer"] + JnapModels[core/jnap/models/] + CloudModels[core/cloud/model/] + CoreProviders[core/jnap/providers/] + end + + Views --> Providers + Providers --> Services + Providers --> SharedProviders + Providers --> CoreProviders + Providers -.->|⚠️ 5處違規| JnapModels + Providers -.->|⚠️ 7處跨頁面| Providers + Services --> JnapModels + Services --> CloudModels + CoreProviders --> JnapModels + + style JnapModels fill:#ffcccc + style Providers fill:#ffffcc +``` + +--- + +### 4.3 建議的依賴層次結構 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ page/*/views/ │ +│ - 只 import page/*/providers/ 和 UI Kit │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ page/*/providers/ │ +│ - import page/*/services/ │ +│ - import page/*/models/ (UI 模型) │ +│ - import lib/providers/ (全局共享狀態) │ +│ - import core/jnap/providers/ (✓ 合理的共享狀態) │ +│ - ❌ 禁止 import core/jnap/models/ │ +│ - ❌ 禁止 import 其他 page/*/providers/ │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ page/*/services/ │ +│ - import core/jnap/models/ (✓ Data 模型處理) │ +│ - import core/jnap/router_repository.dart │ +│ - 負責 Data ↔ UI 模型轉換 │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ lib/providers/ (全局共享) │ +│ - 跨頁面共享的狀態 │ +│ - 例: connectivityStatusProvider, networkHealthProvider │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ core/jnap/providers/ (核心共享狀態) │ +│ - dashboardManagerProvider │ +│ - deviceManagerProvider │ +│ - pollingProvider │ +│ - 這些應該只暴露 UI 友好的狀態 │ +└─────────────────────────────────────────────────────────────────┘ + +``` + +--- + +### 4.4 修復優先級矩陣 + +| 優先級 | 問題 | 影響範圍 | 修復難度 | 建議時程 | +|--------|------|---------|---------|---------| +| P0 | Provider 直接引用 Data 模型 | 5 個檔案 | 中 | 1-2 週 | +| P1 | `wifi_bundle` ↔ `dashboard` 耦合 | 3 個檔案 | 高 | 2-3 週 | +| P2 | `dashboard` → `health_check` 耦合 | 2 個檔案 | 中 | 1 週 | +| P3 | 其他跨頁面依賴 | 5+ 個檔案 | 中 | 持續進行 | +| P4 | 巨型檔案拆分 | 4 個檔案 | 高 | 按需進行 | + +--- + +### 4.5 驗證命令 + +**檢查 Provider 層是否有 Data 模型引用**: +```bash +grep -r "import 'package:privacy_gui/core/jnap/models/" \ + lib/page/*/providers/*.dart +# 預期: 0 個結果 (修復後) +``` + +**檢查跨頁面 Provider 引用**: +```bash +grep -r "import 'package:privacy_gui/page/" lib/page/*/providers/*.dart \ + | grep -v "import 'package:privacy_gui/page/\($(basename $(dirname $PWD))\)" \ + | grep -v "_state.dart" | grep -v "/models/" +# 應只顯示必要的跨頁面引用 +``` + +--- + +## 5. 符合架構規範的模組 + +以下模組展現了良好的解耦實踐: + +| 模組 | 結構 | 解耦評分 | +|------|------|----------| +| `page/advanced_settings/dmz/` | models/providers/services/views | ⭐⭐⭐⭐⭐ | +| `page/wifi_settings/` | models/providers/services/views | ⭐⭐⭐⭐ | +| `page/instant_admin/` | providers/services/views | ⭐⭐⭐⭐ | +| `page/health_check/` | models/providers/services/views | ⭐⭐⭐⭐ | +| `ai/` | abstraction/orchestrator/providers | ⭐⭐⭐⭐⭐ | + +--- + +## 6. 改進建議 + +### 高優先級 + +1. **Provider 層淨化** + - 移除所有 Provider 對 `core/jnap/models/` 的直接引用 + - 為每個受影響的 Provider 創建對應的 UI 模型 + +2. **共享狀態提取** + - 將 `deviceManagerProvider`、`dashboardManagerProvider` 等全局狀態移至 `lib/providers/` + - 減少 `page/` 模組間的直接依賴 + +### 中優先級 + +3. **拆分巨型檔案** + - `jnap_tr181_mapper.dart` → 按功能域拆分 + - `router_provider.dart` → 分離路由與認證邏輯 + +4. **建立模組邊界** + - 為每個 `page/*` 模組創建 barrel export (`_module.dart`) + - 只暴露公開 API,隱藏內部實現 + +### 低優先級 + +5. **文件化架構規範** + - 擴展 `specs/002-dmz-refactor/ARCHITECTURE_DECISION.md` 為全專案指南 + - 添加 linter 規則強制架構約束 + +--- + +## 7. 總結評分 + +| 維度 | 評分 | 說明 | +|------|------|------| +| 整體架構設計 | ⭐⭐⭐⭐ | 4 層架構清晰,有文件化規範 | +| 核心模組解耦 | ⭐⭐⭐⭐⭐ | AI、USP 模組解耦良好 | +| 頁面模組解耦 | ⭐⭐⭐ | 存在跨模組依賴問題 | +| Provider 層純淨度 | ⭐⭐⭐ | 5 處違規需修復 | +| 模組邊界清晰度 | ⭐⭐⭐ | barrel export 使用不一致 | + +**總體評分: 3.6/5 ⭐** + +專案架構設計良好,主要問題集中在 Provider 層的直接 Data 模型引用和跨頁面依賴。建議優先解決 Provider 層淨化問題,並逐步建立更嚴格的模組邊界。 diff --git a/lib/core/jnap/command/http/transaction_http_command.dart b/lib/core/jnap/command/http/transaction_http_command.dart index 2c2bbddbd..d95bf6bd8 100644 --- a/lib/core/jnap/command/http/transaction_http_command.dart +++ b/lib/core/jnap/command/http/transaction_http_command.dart @@ -44,14 +44,14 @@ class TransactionHttpCommand if (cacheLevel == CacheLevel.localCached) { final prefs = await SharedPreferences.getInstance(); final serialNumber = prefs.getString(pCurrentSN); - jnap.data.forEach((entry) { + for (var entry in jnap.data) { final dataResult = { "target": entry.key.actionValue, "cachedAt": DateTime.now().millisecondsSinceEpoch, }; dataResult["data"] = (entry.value as JNAPSuccess).toJson(); cache.data[entry.key.actionValue] = dataResult; - }); + } if (serialNumber != null) { logger.d( diff --git a/lib/core/jnap/models/wirless_connection.dart b/lib/core/jnap/models/wirless_connection.dart index 351ee54d4..8a3bdf08a 100644 --- a/lib/core/jnap/models/wirless_connection.dart +++ b/lib/core/jnap/models/wirless_connection.dart @@ -38,7 +38,7 @@ class WirelessConnection extends Equatable { isGuest: isGuest ?? this.isGuest, radioID: radioID ?? this.radioID, band: band ?? this.band, - signalDecibels: signalBecibels ?? this.signalDecibels, + signalDecibels: signalBecibels ?? signalDecibels, txRate: txRate ?? this.txRate, rxRate: rxRate ?? this.rxRate, isMLOCapable: isMLOCapable ?? this.isMLOCapable, diff --git a/lib/core/usp/jnap_tr181_mapper.dart b/lib/core/usp/jnap_tr181_mapper.dart index 7ec3cf2a4..216770941 100644 --- a/lib/core/usp/jnap_tr181_mapper.dart +++ b/lib/core/usp/jnap_tr181_mapper.dart @@ -599,7 +599,7 @@ class JnapTr181Mapper { // Mock IPs for demonstration as standard MultiAP APDevice doesn't expose IP easily // In real scenario, we might look this up or USP provides it. final mockIp = '192.168.1.${10 + i}'; - final mockParentIp = '192.168.1.1'; // Assume master is parent + const mockParentIp = '192.168.1.1'; // Assume master is parent backhaulDevices.add({ 'deviceUUID': mac, @@ -740,11 +740,13 @@ class JnapTr181Mapper { String wanConnection = 'Disconnected'; if (wanEnable) { - if (wanBitRate == '1000') + if (wanBitRate == '1000') { wanConnection = '1Gbps'; - else if (wanBitRate == '100') + } else if (wanBitRate == '100') { wanConnection = '100Mbps'; - else if (wanBitRate != '0') wanConnection = '${wanBitRate}Mbps'; + } else if (wanBitRate != '0') { + wanConnection = '${wanBitRate}Mbps'; + } } // LAN Ports (Interfaces 3+ in mock data) @@ -768,13 +770,15 @@ class JnapTr181Mapper { String status = 'Disconnected'; if (enable) { - if (bitRate == '1000') + if (bitRate == '1000') { status = '1Gbps'; - else if (bitRate == '100') + } else if (bitRate == '100') { status = '100Mbps'; - else if (bitRate == '10') + } else if (bitRate == '10') { status = '10Mbps'; - else if (bitRate != '0') status = '${bitRate}Mbps'; + } else if (bitRate != '0') { + status = '${bitRate}Mbps'; + } } lanList.add(status); } @@ -933,7 +937,7 @@ class JnapTr181Mapper { // Usually MAC filtering is global or per-AP. JNAP usually sets it globally or // for the main APs. We'll look at the first AP as the "master" switch. - final prefix = 'Device.WiFi.AccessPoint.1'; + const prefix = 'Device.WiFi.AccessPoint.1'; final isEnabled = values['$prefix.MACAddressControlEnabled']?.toString() == 'true'; diff --git a/lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart b/lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart index 0255c2d8e..282c68af3 100644 --- a/lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart +++ b/lib/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart @@ -11,8 +11,9 @@ class InternetSettingsFormValidator { InputValidator([IpAddressNoReservedRule()]); ValidationError? validateMacAddress(String? value) { - if (value == null || value.isEmpty) + if (value == null || value.isEmpty) { return ValidationError.invalidMACAddress; + } if (_macValidator.validate(value)) { return null; } else { @@ -39,8 +40,9 @@ class InternetSettingsFormValidator { } ValidationError? validateSubnetMask(String? value) { - if (value == null || value.isEmpty) + if (value == null || value.isEmpty) { return ValidationError.invalidSubnetMask; + } final subnetMaskValidator = SubnetMaskValidator(); if (subnetMaskValidator.validate(value)) { return null; @@ -50,8 +52,9 @@ class InternetSettingsFormValidator { } ValidationError? validateIpAddress(String? value, [allowEmpty = false]) { - if (value == null || value.isEmpty) + if (value == null || value.isEmpty) { return allowEmpty ? null : ValidationError.invalidIpAddress; + } if (_ipv4Validator.validate(value)) { return null; } else { @@ -60,8 +63,9 @@ class InternetSettingsFormValidator { } ValidationError? validateEmpty(String? value) { - if (value == null || value.isEmpty) + if (value == null || value.isEmpty) { return ValidationError.fieldCannotBeEmpty; + } return null; } } diff --git a/lib/page/advanced_settings/internet_settings/views/ipv4_connection_view.dart b/lib/page/advanced_settings/internet_settings/views/ipv4_connection_view.dart index 57a244464..3cdac6a28 100644 --- a/lib/page/advanced_settings/internet_settings/views/ipv4_connection_view.dart +++ b/lib/page/advanced_settings/internet_settings/views/ipv4_connection_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:privacy_gui/constants/build_config.dart'; import 'package:privacy_gui/core/utils/extension.dart'; import 'package:privacy_gui/localization/localization_hook.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_provider.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_state.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/widgets/optional_settings_form.dart'; diff --git a/lib/page/advanced_settings/internet_settings/views/ipv6_connection_view.dart b/lib/page/advanced_settings/internet_settings/views/ipv6_connection_view.dart index 30a55847a..98da8a328 100644 --- a/lib/page/advanced_settings/internet_settings/views/ipv6_connection_view.dart +++ b/lib/page/advanced_settings/internet_settings/views/ipv6_connection_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:privacy_gui/constants/build_config.dart'; import 'package:privacy_gui/core/utils/extension.dart'; import 'package:privacy_gui/localization/localization_hook.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_provider.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_state.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/widgets/optional_settings_form.dart'; diff --git a/lib/page/advanced_settings/internet_settings/views/release_and_renew_view.dart b/lib/page/advanced_settings/internet_settings/views/release_and_renew_view.dart index 6c1e3c79f..73f0aa771 100644 --- a/lib/page/advanced_settings/internet_settings/views/release_and_renew_view.dart +++ b/lib/page/advanced_settings/internet_settings/views/release_and_renew_view.dart @@ -8,7 +8,6 @@ import 'package:privacy_gui/core/jnap/providers/polling_provider.dart'; import 'package:privacy_gui/core/errors/service_error.dart'; import 'package:privacy_gui/core/jnap/result/jnap_result.dart'; import 'package:privacy_gui/localization/localization_hook.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_provider.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_state.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/views/internet_settings_view.dart'; diff --git a/lib/page/advanced_settings/internet_settings/widgets/optional_settings_form.dart b/lib/page/advanced_settings/internet_settings/widgets/optional_settings_form.dart index 511b323be..f039eb95c 100644 --- a/lib/page/advanced_settings/internet_settings/widgets/optional_settings_form.dart +++ b/lib/page/advanced_settings/internet_settings/widgets/optional_settings_form.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:privacy_gui/core/utils/extension.dart'; import 'package:privacy_gui/localization/localization_hook.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_provider.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_state.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart'; diff --git a/lib/page/advanced_settings/internet_settings/widgets/wan_forms/ipv6/automatic_ipv6_form.dart b/lib/page/advanced_settings/internet_settings/widgets/wan_forms/ipv6/automatic_ipv6_form.dart index 103678573..4145ec478 100644 --- a/lib/page/advanced_settings/internet_settings/widgets/wan_forms/ipv6/automatic_ipv6_form.dart +++ b/lib/page/advanced_settings/internet_settings/widgets/wan_forms/ipv6/automatic_ipv6_form.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:privacy_gui/localization/localization_hook.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_provider.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_state.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart'; diff --git a/lib/page/advanced_settings/internet_settings/widgets/wan_forms/pppoe_form.dart b/lib/page/advanced_settings/internet_settings/widgets/wan_forms/pppoe_form.dart index e0901e941..48bf5bd37 100644 --- a/lib/page/advanced_settings/internet_settings/widgets/wan_forms/pppoe_form.dart +++ b/lib/page/advanced_settings/internet_settings/widgets/wan_forms/pppoe_form.dart @@ -48,13 +48,15 @@ class _PppoeFormState extends BaseWanFormState { // Initialize focus nodes with listeners _usernameFocusNode = FocusNode() ..addListener(() { - if (!_usernameFocusNode.hasFocus) + if (!_usernameFocusNode.hasFocus) { setState(() => _usernameTouched = true); + } }); _passwordFocusNode = FocusNode() ..addListener(() { - if (!_passwordFocusNode.hasFocus) + if (!_passwordFocusNode.hasFocus) { setState(() => _passwordTouched = true); + } }); _vlanIdFocusNode = FocusNode() ..addListener(() { diff --git a/lib/page/advanced_settings/internet_settings/widgets/wan_forms/pptp_form.dart b/lib/page/advanced_settings/internet_settings/widgets/wan_forms/pptp_form.dart index 2e5e069e4..de51a51cc 100644 --- a/lib/page/advanced_settings/internet_settings/widgets/wan_forms/pptp_form.dart +++ b/lib/page/advanced_settings/internet_settings/widgets/wan_forms/pptp_form.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:privacy_gui/core/utils/extension.dart'; import 'package:privacy_gui/localization/localization_hook.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_provider.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_state.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/utils/internet_settings_form_validator.dart'; diff --git a/lib/page/instant_admin/views/manual_firmware_update_view.dart b/lib/page/instant_admin/views/manual_firmware_update_view.dart index c8abfeb34..e89edc6f9 100644 --- a/lib/page/instant_admin/views/manual_firmware_update_view.dart +++ b/lib/page/instant_admin/views/manual_firmware_update_view.dart @@ -183,7 +183,7 @@ class _ManualFirmwareUpdateViewState child: SizedBox( width: MediaQuery.of(context).size.width * 0.5, child: Column( - children: [ + children: const [ AppLoader( variant: LoaderVariant.linear, ), diff --git a/lib/page/instant_safety/services/instant_safety_service.dart b/lib/page/instant_safety/services/instant_safety_service.dart index 88b656f5c..976beb4c1 100644 --- a/lib/page/instant_safety/services/instant_safety_service.dart +++ b/lib/page/instant_safety/services/instant_safety_service.dart @@ -205,6 +205,7 @@ class _CompatibilityItem { const _CompatibilityItem({ required this.modelRegExp, + // ignore: unused_element_parameter this.compatibleFW, }); } @@ -216,6 +217,7 @@ class _CompatibilityFW { const _CompatibilityFW({ required this.min, + // ignore: unused_element_parameter this.max, }); } diff --git a/lib/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider.dart b/lib/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider.dart index 66293fd16..85d7f5e43 100644 --- a/lib/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider.dart +++ b/lib/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider.dart @@ -1,6 +1,5 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:privacy_gui/core/utils/logger.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/_providers.dart'; import 'package:privacy_gui/page/instant_setup/services/pnp_service.dart'; import 'package:privacy_gui/page/instant_setup/troubleshooter/providers/_providers.dart'; diff --git a/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_isp_type_selection_view.dart b/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_isp_type_selection_view.dart index 610e94101..132497c5f 100644 --- a/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_isp_type_selection_view.dart +++ b/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_isp_type_selection_view.dart @@ -5,7 +5,6 @@ import 'package:privacy_gui/core/errors/service_error.dart'; import 'package:privacy_gui/core/jnap/result/jnap_result.dart'; import 'package:privacy_gui/core/utils/logger.dart'; import 'package:privacy_gui/localization/localization_hook.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/_providers.dart'; import 'package:privacy_gui/page/components/shortcuts/dialogs.dart'; import 'package:privacy_gui/page/components/ui_kit_page_view.dart'; diff --git a/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_pppoe_view.dart b/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_pppoe_view.dart index 9e98f6099..80603f631 100644 --- a/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_pppoe_view.dart +++ b/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_pppoe_view.dart @@ -5,7 +5,6 @@ import 'package:privacy_gui/core/errors/service_error.dart'; import 'package:privacy_gui/core/jnap/result/jnap_result.dart'; import 'package:privacy_gui/core/utils/logger.dart'; import 'package:privacy_gui/localization/localization_hook.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/_providers.dart'; import 'package:privacy_gui/page/components/shortcuts/dialogs.dart'; import 'package:privacy_gui/page/components/ui_kit_page_view.dart'; diff --git a/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart b/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart index 00ff3a8cd..aa9302d43 100644 --- a/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart +++ b/lib/page/instant_setup/troubleshooter/views/isp_settings/pnp_static_ip_view.dart @@ -5,7 +5,6 @@ import 'package:privacy_gui/core/errors/service_error.dart'; import 'package:privacy_gui/core/jnap/result/jnap_result.dart'; import 'package:privacy_gui/core/utils/logger.dart'; import 'package:privacy_gui/localization/localization_hook.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/_providers.dart'; import 'package:privacy_gui/page/components/shortcuts/dialogs.dart'; import 'package:privacy_gui/page/components/ui_kit_page_view.dart'; diff --git a/lib/route/route_add_nodes.dart b/lib/route/route_add_nodes.dart index 35f126c9c..9456980a2 100644 --- a/lib/route/route_add_nodes.dart +++ b/lib/route/route_add_nodes.dart @@ -8,5 +8,5 @@ final addNodesRoute = LinksysRoute( builder: (context, state) => AddNodesView( args: state.extra as Map? ?? {}, ), - routes: [], + routes: const [], ); diff --git a/lib/route/route_cloud_login.dart b/lib/route/route_cloud_login.dart index 65a245cc9..e85add7b1 100644 --- a/lib/route/route_cloud_login.dart +++ b/lib/route/route_cloud_login.dart @@ -8,7 +8,7 @@ final cloudLoginRoute = LinksysRoute( args: state.extra as Map? ?? {} ..addAll(state.extra as Map? ?? {}) ..addAll(state.uri.queryParameters)), - routes: [], + routes: const [], ); final cloudLoginAuthRoute = LinksysRoute( diff --git a/lib/route/route_dashboard.dart b/lib/route/route_dashboard.dart index 774fd89d8..a4664a34a 100644 --- a/lib/route/route_dashboard.dart +++ b/lib/route/route_dashboard.dart @@ -3,7 +3,7 @@ part of 'router_provider.dart'; final shellNavigatorKey = GlobalKey(); final dashboardRoute = ShellRoute( navigatorKey: shellNavigatorKey, - observers: [], + observers: const [], builder: (BuildContext context, GoRouterState state, Widget child) => DashboardShell( child: child, diff --git a/lib/route/route_home.dart b/lib/route/route_home.dart index 27f859bf4..840a2b180 100644 --- a/lib/route/route_home.dart +++ b/lib/route/route_home.dart @@ -7,7 +7,7 @@ final homeRoute = LinksysRoute( column: ColumnGrid(column: 9, centered: true), ), builder: (context, state) => const HomeView(), - routes: [ + routes: const [ // cloudLoginRoute, // cloudRALoginRoute, //setupRoute diff --git a/lib/route/route_pnp.dart b/lib/route/route_pnp.dart index f96fab46b..2f83ab777 100644 --- a/lib/route/route_pnp.dart +++ b/lib/route/route_pnp.dart @@ -30,7 +30,7 @@ final pnpRoute = LinksysRoute( builder: (context, state) => AddNodesView( args: state.extra as Map? ?? {}, ), - routes: [], + routes: const [], ) ], ), diff --git a/lib/util/extensions.dart b/lib/util/extensions.dart index 4aef3f64f..784951354 100644 --- a/lib/util/extensions.dart +++ b/lib/util/extensions.dart @@ -15,7 +15,7 @@ extension Unique on List { /// /// Returns a list containing only the unique elements. List unique([Id Function(E element)? id, bool inplace = true]) { - final ids = Set(); + final ids = {}; var list = inplace ? this : List.from(this); if (list.isEmpty) { return list; diff --git a/lib/utils.dart b/lib/utils.dart index c030c3ae4..4cc8bbf4a 100644 --- a/lib/utils.dart +++ b/lib/utils.dart @@ -106,7 +106,7 @@ class Utils { return '$header$encryptedPassword'; } else { // If encryption fails, return the original match, but mask the password - return '${header}************'; + return '$header************'; } }); } diff --git a/packages/usp_client_core/lib/src/services/usp_topology_service.dart b/packages/usp_client_core/lib/src/services/usp_topology_service.dart index 401bd94bd..ea7867b57 100644 --- a/packages/usp_client_core/lib/src/services/usp_topology_service.dart +++ b/packages/usp_client_core/lib/src/services/usp_topology_service.dart @@ -260,7 +260,7 @@ class UspTopologyService { // Mock IPs for demonstration final mockIp = '192.168.1.${10 + i}'; - final mockParentIp = '192.168.1.1'; // Assume master is parent + const mockParentIp = '192.168.1.1'; // Assume master is parent backhaulDevices.add({ 'deviceUUID': mac, diff --git a/packages/usp_protocol_common/lib/src/converter/usp_protobuf_converter.dart b/packages/usp_protocol_common/lib/src/converter/usp_protobuf_converter.dart index 4aac94e1a..47ce5b697 100644 --- a/packages/usp_protocol_common/lib/src/converter/usp_protobuf_converter.dart +++ b/packages/usp_protocol_common/lib/src/converter/usp_protobuf_converter.dart @@ -1,13 +1,6 @@ import 'package:collection/collection.dart'; import 'package:usp_protocol_common/usp_protocol_common.dart'; import '../generated/usp_msg.pb.dart' as pb; -import '../dtos/base_dto.dart'; -import '../dtos/requests/usp_requests.dart'; -import '../dtos/responses/usp_responses.dart'; -import '../value_objects/usp_path.dart'; -import '../value_objects/usp_value.dart'; -import '../value_objects/usp_value_type.dart'; -import '../exceptions/usp_exception.dart'; /// A utility class for converting between USP DTOs and Protobuf messages. class UspProtobufConverter { diff --git a/test/core/jnap/services/firmware_update_service_test.dart b/test/core/jnap/services/firmware_update_service_test.dart index ab1ad97e8..0e94a6c75 100644 --- a/test/core/jnap/services/firmware_update_service_test.dart +++ b/test/core/jnap/services/firmware_update_service_test.dart @@ -839,7 +839,7 @@ void main() { requestTimeoutOverride: anyNamed('requestTimeoutOverride'), auth: anyNamed('auth'))) .thenAnswer((_) => Stream.value( - JNAPSuccess(result: 'OK', output: {'firmwareUpdateStatus': []}))); + JNAPSuccess(result: 'OK', output: const {'firmwareUpdateStatus': []}))); final resultStream = service.fetchFirmwareUpdateStream( force: true, retry: 2, currentNodesStatus: nodesStatus); @@ -875,7 +875,7 @@ void main() { { 'deviceUUID': 'uuid1', 'lastSuccessfulCheckTime': DateTime.now().toIso8601String(), - 'availableUpdate': { + 'availableUpdate': const { 'firmwareVersion': '1.0.0', 'firmwareDate': '2025-01-01', }, @@ -896,7 +896,7 @@ void main() { '_checkFirmwareUpdateComplete returns false when firmware update is not complete for nodes', () { final service = container.read(firmwareUpdateServiceProvider); - final result = JNAPSuccess(result: 'OK', output: { + final result = JNAPSuccess(result: 'OK', output: const { 'firmwareUpdateStatus': [ { 'deviceUUID': 'uuid1', @@ -926,7 +926,7 @@ void main() { '_checkFirmwareUpdateComplete returns true when firmware update is complete for nodes', () { final service = container.read(firmwareUpdateServiceProvider); - final result = JNAPSuccess(result: 'OK', output: { + final result = JNAPSuccess(result: 'OK', output: const { 'firmwareUpdateStatus': [ { 'deviceUUID': 'uuid1', diff --git a/test/mocks/auth_notifier_mocks.dart b/test/mocks/auth_notifier_mocks.dart index a95c3e535..38c3f1edb 100644 --- a/test/mocks/auth_notifier_mocks.dart +++ b/test/mocks/auth_notifier_mocks.dart @@ -1,15 +1,18 @@ -// Mocks generated by Mockito 5.4.5 from annotations +// Mocks generated by Mockito 5.4.6 from annotations // in privacy_gui/test/mocks/mockito_specs/auth_notifier_spec.dart. // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i4; +import 'dart:async' as _i5; import 'package:flutter_riverpod/flutter_riverpod.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; -import 'package:privacy_gui/core/cloud/model/cloud_session_model.dart' as _i5; -import 'package:privacy_gui/core/cloud/model/region_code.dart' as _i6; -import 'package:privacy_gui/providers/auth/auth_provider.dart' as _i3; +import 'package:privacy_gui/core/cloud/model/cloud_session_model.dart' as _i6; +import 'package:privacy_gui/core/cloud/model/guardians_remote_assistance.dart' + as _i7; +import 'package:privacy_gui/core/cloud/model/region_code.dart' as _i8; +import 'package:privacy_gui/providers/auth/auth_provider.dart' as _i4; +import 'package:privacy_gui/providers/auth/auth_state.dart' as _i3; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -24,29 +27,43 @@ import 'package:privacy_gui/providers/auth/auth_provider.dart' as _i3; // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeAsyncNotifierProviderRef_0 extends _i1.SmartFake implements _i2.AsyncNotifierProviderRef { - _FakeAsyncNotifierProviderRef_0(Object parent, Invocation parentInvocation) - : super(parent, parentInvocation); + _FakeAsyncNotifierProviderRef_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); } class _FakeAsyncValue_1 extends _i1.SmartFake implements _i2.AsyncValue { - _FakeAsyncValue_1(Object parent, Invocation parentInvocation) - : super(parent, parentInvocation); + _FakeAsyncValue_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); } class _FakeAuthState_2 extends _i1.SmartFake implements _i3.AuthState { - _FakeAuthState_2(Object parent, Invocation parentInvocation) - : super(parent, parentInvocation); + _FakeAuthState_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); } /// A class which mocks [AuthNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockAuthNotifier extends _i2.AsyncNotifier<_i3.AuthState> - with _i1.Mock - implements _i3.AuthNotifier { +class MockAuthNotifier extends _i1.Mock implements _i4.AuthNotifier { @override _i2.AsyncNotifierProviderRef<_i3.AuthState> get ref => (super.noSuchMethod( Invocation.getter(#ref), @@ -74,119 +91,160 @@ class MockAuthNotifier extends _i2.AsyncNotifier<_i3.AuthState> ), ) as _i2.AsyncValue<_i3.AuthState>); + @override + _i5.Future<_i3.AuthState> get future => (super.noSuchMethod( + Invocation.getter(#future), + returnValue: _i5.Future<_i3.AuthState>.value(_FakeAuthState_2( + this, + Invocation.getter(#future), + )), + returnValueForMissingStub: + _i5.Future<_i3.AuthState>.value(_FakeAuthState_2( + this, + Invocation.getter(#future), + )), + ) as _i5.Future<_i3.AuthState>); + @override set state(_i2.AsyncValue<_i3.AuthState>? newState) => super.noSuchMethod( - Invocation.setter(#state, newState), + Invocation.setter( + #state, + newState, + ), returnValueForMissingStub: null, ); @override - _i4.Future<_i3.AuthState> get future => (super.noSuchMethod( - Invocation.getter(#future), - returnValue: _i4.Future<_i3.AuthState>.value( - _FakeAuthState_2(this, Invocation.getter(#future)), - ), - returnValueForMissingStub: _i4.Future<_i3.AuthState>.value( - _FakeAuthState_2(this, Invocation.getter(#future)), + _i5.Future<_i3.AuthState> build() => (super.noSuchMethod( + Invocation.method( + #build, + [], ), - ) as _i4.Future<_i3.AuthState>); + returnValue: _i5.Future<_i3.AuthState>.value(_FakeAuthState_2( + this, + Invocation.method( + #build, + [], + ), + )), + returnValueForMissingStub: + _i5.Future<_i3.AuthState>.value(_FakeAuthState_2( + this, + Invocation.method( + #build, + [], + ), + )), + ) as _i5.Future<_i3.AuthState>); @override - _i4.Future<_i3.AuthState> build() => (super.noSuchMethod( - Invocation.method(#build, []), - returnValue: _i4.Future<_i3.AuthState>.value( - _FakeAuthState_2(this, Invocation.method(#build, [])), - ), - returnValueForMissingStub: _i4.Future<_i3.AuthState>.value( - _FakeAuthState_2(this, Invocation.method(#build, [])), + _i5.Future<_i3.AuthState?> init() => (super.noSuchMethod( + Invocation.method( + #init, + [], ), - ) as _i4.Future<_i3.AuthState>); + returnValue: _i5.Future<_i3.AuthState?>.value(), + returnValueForMissingStub: _i5.Future<_i3.AuthState?>.value(), + ) as _i5.Future<_i3.AuthState?>); @override - _i4.Future<_i3.AuthState?> init() => (super.noSuchMethod( - Invocation.method(#init, []), - returnValue: _i4.Future<_i3.AuthState?>.value(), - returnValueForMissingStub: _i4.Future<_i3.AuthState?>.value(), - ) as _i4.Future<_i3.AuthState?>); - - @override - _i4.Future<_i5.SessionToken?> checkSessionToken() => (super.noSuchMethod( - Invocation.method(#checkSessionToken, []), - returnValue: _i4.Future<_i5.SessionToken?>.value(), - returnValueForMissingStub: _i4.Future<_i5.SessionToken?>.value(), - ) as _i4.Future<_i5.SessionToken?>); + _i5.Future<_i6.SessionToken?> checkSessionToken() => (super.noSuchMethod( + Invocation.method( + #checkSessionToken, + [], + ), + returnValue: _i5.Future<_i6.SessionToken?>.value(), + returnValueForMissingStub: _i5.Future<_i6.SessionToken?>.value(), + ) as _i5.Future<_i6.SessionToken?>); @override - _i4.Future<_i5.SessionToken?> handleSessionTokenError( + _i5.Future<_i6.SessionToken?> handleSessionTokenError( Object? error, StackTrace? trace, ) => (super.noSuchMethod( - Invocation.method(#handleSessionTokenError, [error, trace]), - returnValue: _i4.Future<_i5.SessionToken?>.value(), - returnValueForMissingStub: _i4.Future<_i5.SessionToken?>.value(), - ) as _i4.Future<_i5.SessionToken?>); + Invocation.method( + #handleSessionTokenError, + [ + error, + trace, + ], + ), + returnValue: _i5.Future<_i6.SessionToken?>.value(), + returnValueForMissingStub: _i5.Future<_i6.SessionToken?>.value(), + ) as _i5.Future<_i6.SessionToken?>); @override - _i4.Future<_i5.SessionToken?> refreshToken(String? refreshToken) => + _i5.Future<_i6.SessionToken?> refreshToken(String? refreshToken) => (super.noSuchMethod( - Invocation.method(#refreshToken, [refreshToken]), - returnValue: _i4.Future<_i5.SessionToken?>.value(), - returnValueForMissingStub: _i4.Future<_i5.SessionToken?>.value(), - ) as _i4.Future<_i5.SessionToken?>); + Invocation.method( + #refreshToken, + [refreshToken], + ), + returnValue: _i5.Future<_i6.SessionToken?>.value(), + returnValueForMissingStub: _i5.Future<_i6.SessionToken?>.value(), + ) as _i5.Future<_i6.SessionToken?>); @override - _i4.Future cloudLogin({ - required String? username, - required String? password, - _i5.SessionToken? sessionToken, + _i5.Future cloudLoginAuth({ + required String? token, + required String? sn, + required _i7.GRASessionInfo? sessionInfo, }) => (super.noSuchMethod( - Invocation.method(#cloudLogin, [], { - #username: username, - #password: password, - #sessionToken: sessionToken, - }), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + Invocation.method( + #cloudLoginAuth, + [], + { + #token: token, + #sn: sn, + #sessionInfo: sessionInfo, + }, + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); @override - _i4.Future<_i3.AuthState> updateCloudCredientials({ - _i5.SessionToken? sessionToken, - String? username, - String? password, + _i5.Future<_i7.GRASessionInfo?> testSessionAuthentication({ + required String? token, + required String? session, }) => (super.noSuchMethod( - Invocation.method(#updateCloudCredientials, [], { - #sessionToken: sessionToken, - #username: username, - #password: password, - }), - returnValue: _i4.Future<_i3.AuthState>.value( - _FakeAuthState_2( - this, - Invocation.method(#updateCloudCredientials, [], { - #sessionToken: sessionToken, - #username: username, - #password: password, - }), - ), + Invocation.method( + #testSessionAuthentication, + [], + { + #token: token, + #session: session, + }, ), - returnValueForMissingStub: _i4.Future<_i3.AuthState>.value( - _FakeAuthState_2( - this, - Invocation.method(#updateCloudCredientials, [], { - #sessionToken: sessionToken, - #username: username, - #password: password, - }), - ), + returnValue: _i5.Future<_i7.GRASessionInfo?>.value(), + returnValueForMissingStub: _i5.Future<_i7.GRASessionInfo?>.value(), + ) as _i5.Future<_i7.GRASessionInfo?>); + + @override + _i5.Future cloudLogin({ + required String? username, + required String? password, + _i6.SessionToken? sessionToken, + }) => + (super.noSuchMethod( + Invocation.method( + #cloudLogin, + [], + { + #username: username, + #password: password, + #sessionToken: sessionToken, + }, ), - ) as _i4.Future<_i3.AuthState>); + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); @override - _i4.Future localLogin( + _i5.Future localLogin( String? password, { bool? pnp = false, bool? guardError = true, @@ -195,76 +253,96 @@ class MockAuthNotifier extends _i2.AsyncNotifier<_i3.AuthState> Invocation.method( #localLogin, [password], - {#pnp: pnp, #guardError: guardError}, + { + #pnp: pnp, + #guardError: guardError, + }, ), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); @override - _i4.Future getPasswordHint() => (super.noSuchMethod( - Invocation.method(#getPasswordHint, []), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + _i5.Future getPasswordHint() => (super.noSuchMethod( + Invocation.method( + #getPasswordHint, + [], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); @override - _i4.Future?> getAdminPasswordAuthStatus( - List? services, - ) => + _i5.Future?> getAdminPasswordAuthStatus( + List? services) => (super.noSuchMethod( - Invocation.method(#getAdminPasswordAuthStatus, [services]), - returnValue: _i4.Future?>.value(), - returnValueForMissingStub: _i4.Future?>.value(), - ) as _i4.Future?>); + Invocation.method( + #getAdminPasswordAuthStatus, + [services], + ), + returnValue: _i5.Future?>.value(), + returnValueForMissingStub: _i5.Future?>.value(), + ) as _i5.Future?>); @override - _i4.Future getDeviceInfo() => (super.noSuchMethod( - Invocation.method(#getDeviceInfo, []), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + _i5.Future getDeviceInfo() => (super.noSuchMethod( + Invocation.method( + #getDeviceInfo, + [], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); @override - _i4.Future logout() => (super.noSuchMethod( - Invocation.method(#logout, []), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + _i5.Future logout() => (super.noSuchMethod( + Invocation.method( + #logout, + [], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); @override bool isCloudLogin() => (super.noSuchMethod( - Invocation.method(#isCloudLogin, []), + Invocation.method( + #isCloudLogin, + [], + ), returnValue: false, returnValueForMissingStub: false, ) as bool); @override - _i4.Future> fetchRegionCodes() => (super.noSuchMethod( - Invocation.method(#fetchRegionCodes, []), - returnValue: _i4.Future>.value( - <_i6.RegionCode>[], - ), - returnValueForMissingStub: _i4.Future>.value( - <_i6.RegionCode>[], + _i5.Future> fetchRegionCodes() => (super.noSuchMethod( + Invocation.method( + #fetchRegionCodes, + [], ), - ) as _i4.Future>); + returnValue: _i5.Future>.value(<_i8.RegionCode>[]), + returnValueForMissingStub: + _i5.Future>.value(<_i8.RegionCode>[]), + ) as _i5.Future>); @override - _i4.Future raLogin( + _i5.Future raLogin( String? sessionToken, String? networkId, String? serialNumber, ) => (super.noSuchMethod( - Invocation.method(#raLogin, [ - sessionToken, - networkId, - serialNumber, - ]), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) as _i4.Future); + Invocation.method( + #raLogin, + [ + sessionToken, + networkId, + serialNumber, + ], + ), + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); @override void listenSelf( @@ -272,33 +350,52 @@ class MockAuthNotifier extends _i2.AsyncNotifier<_i3.AuthState> _i2.AsyncValue<_i3.AuthState>?, _i2.AsyncValue<_i3.AuthState>, )? listener, { - void Function(Object, StackTrace)? onError, + void Function( + Object, + StackTrace, + )? onError, }) => super.noSuchMethod( - Invocation.method(#listenSelf, [listener], {#onError: onError}), + Invocation.method( + #listenSelf, + [listener], + {#onError: onError}, + ), returnValueForMissingStub: null, ); @override - _i4.Future<_i3.AuthState> update( - _i4.FutureOr<_i3.AuthState> Function(_i3.AuthState)? cb, { - _i4.FutureOr<_i3.AuthState> Function(Object, StackTrace)? onError, + _i5.Future<_i3.AuthState> update( + _i5.FutureOr<_i3.AuthState> Function(_i3.AuthState)? cb, { + _i5.FutureOr<_i3.AuthState> Function( + Object, + StackTrace, + )? onError, }) => (super.noSuchMethod( - Invocation.method(#update, [cb], {#onError: onError}), - returnValue: _i4.Future<_i3.AuthState>.value( - _FakeAuthState_2( - this, - Invocation.method(#update, [cb], {#onError: onError}), - ), + Invocation.method( + #update, + [cb], + {#onError: onError}, ), - returnValueForMissingStub: _i4.Future<_i3.AuthState>.value( - _FakeAuthState_2( - this, - Invocation.method(#update, [cb], {#onError: onError}), + returnValue: _i5.Future<_i3.AuthState>.value(_FakeAuthState_2( + this, + Invocation.method( + #update, + [cb], + {#onError: onError}, ), - ), - ) as _i4.Future<_i3.AuthState>); + )), + returnValueForMissingStub: + _i5.Future<_i3.AuthState>.value(_FakeAuthState_2( + this, + Invocation.method( + #update, + [cb], + {#onError: onError}, + ), + )), + ) as _i5.Future<_i3.AuthState>); @override bool updateShouldNotify( @@ -306,7 +403,13 @@ class MockAuthNotifier extends _i2.AsyncNotifier<_i3.AuthState> _i2.AsyncValue<_i3.AuthState>? next, ) => (super.noSuchMethod( - Invocation.method(#updateShouldNotify, [previous, next]), + Invocation.method( + #updateShouldNotify, + [ + previous, + next, + ], + ), returnValue: false, returnValueForMissingStub: false, ) as bool); diff --git a/test/mocks/dashboard_home_notifier_mocks.dart b/test/mocks/dashboard_home_notifier_mocks.dart index 86092253c..7eebd7f09 100644 --- a/test/mocks/dashboard_home_notifier_mocks.dart +++ b/test/mocks/dashboard_home_notifier_mocks.dart @@ -5,16 +5,10 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'package:flutter_riverpod/flutter_riverpod.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; -import 'package:privacy_gui/core/jnap/providers/dashboard_manager_state.dart' - as _i5; -import 'package:privacy_gui/core/jnap/providers/device_manager_state.dart' - as _i6; import 'package:privacy_gui/page/dashboard/providers/dashboard_home_provider.dart' as _i4; import 'package:privacy_gui/page/dashboard/providers/dashboard_home_state.dart' as _i3; -import 'package:privacy_gui/page/health_check/providers/health_check_state.dart' - as _i7; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -29,6 +23,7 @@ import 'package:privacy_gui/page/health_check/providers/health_check_state.dart' // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeNotifierProviderRef_0 extends _i1.SmartFake implements _i2.NotifierProviderRef { @@ -55,8 +50,7 @@ class _FakeDashboardHomeState_1 extends _i1.SmartFake /// A class which mocks [DashboardHomeNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockDashboardHomeNotifier extends _i2.Notifier<_i3.DashboardHomeState> - with _i1.Mock +class MockDashboardHomeNotifier extends _i1.Mock implements _i4.DashboardHomeNotifier { @override _i2.NotifierProviderRef<_i3.DashboardHomeState> get ref => @@ -117,45 +111,6 @@ class MockDashboardHomeNotifier extends _i2.Notifier<_i3.DashboardHomeState> ), ) as _i3.DashboardHomeState); - @override - _i3.DashboardHomeState createState( - _i5.DashboardManagerState? dashboardManagerState, - _i6.DeviceManagerState? deviceManagerState, - _i7.HealthCheckState? healthCheckState, - ) => - (super.noSuchMethod( - Invocation.method( - #createState, - [ - dashboardManagerState, - deviceManagerState, - healthCheckState, - ], - ), - returnValue: _FakeDashboardHomeState_1( - this, - Invocation.method( - #createState, - [ - dashboardManagerState, - deviceManagerState, - healthCheckState, - ], - ), - ), - returnValueForMissingStub: _FakeDashboardHomeState_1( - this, - Invocation.method( - #createState, - [ - dashboardManagerState, - deviceManagerState, - healthCheckState, - ], - ), - ), - ) as _i3.DashboardHomeState); - @override void listenSelf( void Function( diff --git a/test/mocks/dashboard_manager_notifier_mocks.dart b/test/mocks/dashboard_manager_notifier_mocks.dart index 41181a3f1..bbc025fbe 100644 --- a/test/mocks/dashboard_manager_notifier_mocks.dart +++ b/test/mocks/dashboard_manager_notifier_mocks.dart @@ -1,18 +1,17 @@ -// Mocks generated by Mockito 5.4.4 from annotations -// in privacy_gui/test/page/login/localizations/login_local_view_test.dart. +// Mocks generated by Mockito 5.4.6 from annotations +// in privacy_gui/test/mocks/mockito_specs/dashboard_manager_notifier_spec.dart. // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i12; +import 'dart:async' as _i6; import 'package:flutter_riverpod/flutter_riverpod.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; import 'package:privacy_gui/core/jnap/models/device_info.dart' as _i4; import 'package:privacy_gui/core/jnap/providers/dashboard_manager_provider.dart' - as _i10; + as _i5; import 'package:privacy_gui/core/jnap/providers/dashboard_manager_state.dart' as _i3; -import 'package:privacy_gui/core/jnap/providers/polling_provider.dart' as _i11; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -22,10 +21,12 @@ import 'package:privacy_gui/core/jnap/providers/polling_provider.dart' as _i11; // ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeNotifierProviderRef_0 extends _i1.SmartFake implements _i2.NotifierProviderRef { @@ -63,10 +64,8 @@ class _FakeNodeDeviceInfo_2 extends _i1.SmartFake /// A class which mocks [DashboardManagerNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockDashboardManagerNotifier - extends _i2.Notifier<_i3.DashboardManagerState> - with _i1.Mock - implements _i10.DashboardManagerNotifier { +class MockDashboardManagerNotifier extends _i1.Mock + implements _i5.DashboardManagerNotifier { @override _i2.NotifierProviderRef<_i3.DashboardManagerState> get ref => (super.noSuchMethod( @@ -127,58 +126,53 @@ class MockDashboardManagerNotifier ) as _i3.DashboardManagerState); @override - _i3.DashboardManagerState createState( - {_i11.CoreTransactionData? pollingResult}) => + _i6.Future saveSelectedNetwork( + String? serialNumber, + String? networkId, + ) => (super.noSuchMethod( Invocation.method( - #createState, + #saveSelectedNetwork, + [ + serialNumber, + networkId, + ], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + + @override + _i6.Future<_i4.NodeDeviceInfo> checkRouterIsBack() => (super.noSuchMethod( + Invocation.method( + #checkRouterIsBack, [], - {#pollingResult: pollingResult}, ), - returnValue: _FakeDashboardManagerState_1( + returnValue: _i6.Future<_i4.NodeDeviceInfo>.value(_FakeNodeDeviceInfo_2( this, Invocation.method( - #createState, + #checkRouterIsBack, [], - {#pollingResult: pollingResult}, ), - ), - returnValueForMissingStub: _FakeDashboardManagerState_1( + )), + returnValueForMissingStub: + _i6.Future<_i4.NodeDeviceInfo>.value(_FakeNodeDeviceInfo_2( this, Invocation.method( - #createState, + #checkRouterIsBack, [], - {#pollingResult: pollingResult}, ), - ), - ) as _i3.DashboardManagerState); - - @override - _i12.Future saveSelectedNetwork( - String? serialNumber, - String? networkId, - ) => - (super.noSuchMethod( - Invocation.method( - #saveSelectedNetwork, - [ - serialNumber, - networkId, - ], - ), - returnValue: _i12.Future.value(), - returnValueForMissingStub: _i12.Future.value(), - ) as _i12.Future); + )), + ) as _i6.Future<_i4.NodeDeviceInfo>); @override - _i12.Future<_i4.NodeDeviceInfo> checkDeviceInfo(String? serialNumber) => + _i6.Future<_i4.NodeDeviceInfo> checkDeviceInfo(String? serialNumber) => (super.noSuchMethod( Invocation.method( #checkDeviceInfo, [serialNumber], ), - returnValue: - _i12.Future<_i4.NodeDeviceInfo>.value(_FakeNodeDeviceInfo_2( + returnValue: _i6.Future<_i4.NodeDeviceInfo>.value(_FakeNodeDeviceInfo_2( this, Invocation.method( #checkDeviceInfo, @@ -186,24 +180,34 @@ class MockDashboardManagerNotifier ), )), returnValueForMissingStub: - _i12.Future<_i4.NodeDeviceInfo>.value(_FakeNodeDeviceInfo_2( + _i6.Future<_i4.NodeDeviceInfo>.value(_FakeNodeDeviceInfo_2( this, Invocation.method( #checkDeviceInfo, [serialNumber], ), )), - ) as _i12.Future<_i4.NodeDeviceInfo>); + ) as _i6.Future<_i4.NodeDeviceInfo>); - // @override - // bool isHealthCheckModuleSupported(String? module) => (super.noSuchMethod( - // Invocation.method( - // #isHealthCheckModuleSupported, - // [module], - // ), - // returnValue: false, - // returnValueForMissingStub: false, - // ) as bool); + @override + void listenSelf( + void Function( + _i3.DashboardManagerState?, + _i3.DashboardManagerState, + )? listener, { + void Function( + Object, + StackTrace, + )? onError, + }) => + super.noSuchMethod( + Invocation.method( + #listenSelf, + [listener], + {#onError: onError}, + ), + returnValueForMissingStub: null, + ); @override bool updateShouldNotify( diff --git a/test/mocks/device_manager_notifier_mocks.dart b/test/mocks/device_manager_notifier_mocks.dart index d183c6deb..b4434d77e 100644 --- a/test/mocks/device_manager_notifier_mocks.dart +++ b/test/mocks/device_manager_notifier_mocks.dart @@ -1,19 +1,18 @@ -// Mocks generated by Mockito 5.4.4 from annotations +// Mocks generated by Mockito 5.4.6 from annotations // in privacy_gui/test/mocks/mockito_specs/device_manager_notifier_spec.dart. // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i8; +import 'dart:async' as _i6; import 'package:flutter_riverpod/flutter_riverpod.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i7; +import 'package:mockito/src/dummies.dart' as _i5; import 'package:privacy_gui/core/jnap/providers/device_manager_provider.dart' - as _i5; + as _i4; import 'package:privacy_gui/core/jnap/providers/device_manager_state.dart' as _i3; -import 'package:privacy_gui/core/jnap/providers/polling_provider.dart' as _i6; -import 'package:privacy_gui/core/utils/icon_device_category.dart' as _i9; +import 'package:privacy_gui/core/utils/icon_device_category.dart' as _i7; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -23,10 +22,12 @@ import 'package:privacy_gui/core/utils/icon_device_category.dart' as _i9; // ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeNotifierProviderRef_0 extends _i1.SmartFake implements _i2.NotifierProviderRef { @@ -53,9 +54,8 @@ class _FakeDeviceManagerState_1 extends _i1.SmartFake /// A class which mocks [DeviceManagerNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockDeviceManagerNotifier extends _i2.Notifier<_i3.DeviceManagerState> - with _i1.Mock - implements _i5.DeviceManagerNotifier { +class MockDeviceManagerNotifier extends _i1.Mock + implements _i4.DeviceManagerNotifier { @override _i2.NotifierProviderRef<_i3.DeviceManagerState> get ref => (super.noSuchMethod( @@ -116,31 +116,13 @@ class MockDeviceManagerNotifier extends _i2.Notifier<_i3.DeviceManagerState> ) as _i3.DeviceManagerState); @override - _i3.DeviceManagerState createState( - {_i6.CoreTransactionData? pollingResult}) => - (super.noSuchMethod( + void init() => super.noSuchMethod( Invocation.method( - #createState, + #init, [], - {#pollingResult: pollingResult}, - ), - returnValue: _FakeDeviceManagerState_1( - this, - Invocation.method( - #createState, - [], - {#pollingResult: pollingResult}, - ), ), - returnValueForMissingStub: _FakeDeviceManagerState_1( - this, - Invocation.method( - #createState, - [], - {#pollingResult: pollingResult}, - ), - ), - ) as _i3.DeviceManagerState); + returnValueForMissingStub: null, + ); @override bool isEmptyState() => (super.noSuchMethod( @@ -167,14 +149,14 @@ class MockDeviceManagerNotifier extends _i2.Notifier<_i3.DeviceManagerState> #getBandConnectedBy, [device], ), - returnValue: _i7.dummyValue( + returnValue: _i5.dummyValue( this, Invocation.method( #getBandConnectedBy, [device], ), ), - returnValueForMissingStub: _i7.dummyValue( + returnValueForMissingStub: _i5.dummyValue( this, Invocation.method( #getBandConnectedBy, @@ -200,11 +182,11 @@ class MockDeviceManagerNotifier extends _i2.Notifier<_i3.DeviceManagerState> ) as _i3.LinksysDevice?); @override - _i8.Future updateDeviceNameAndIcon({ + _i6.Future updateDeviceNameAndIcon({ required String? targetId, required String? newName, required bool? isLocation, - _i9.IconDeviceCategory? icon, + _i7.IconDeviceCategory? icon, }) => (super.noSuchMethod( Invocation.method( @@ -217,33 +199,53 @@ class MockDeviceManagerNotifier extends _i2.Notifier<_i3.DeviceManagerState> #icon: icon, }, ), - returnValue: _i8.Future.value(), - returnValueForMissingStub: _i8.Future.value(), - ) as _i8.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i8.Future deleteDevices({required List? deviceIds}) => + _i6.Future deleteDevices({required List? deviceIds}) => (super.noSuchMethod( Invocation.method( #deleteDevices, [], {#deviceIds: deviceIds}, ), - returnValue: _i8.Future.value(), - returnValueForMissingStub: _i8.Future.value(), - ) as _i8.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); @override - _i8.Future deauthClient({required String? macAddress}) => + _i6.Future deauthClient({required String? macAddress}) => (super.noSuchMethod( Invocation.method( #deauthClient, [], {#macAddress: macAddress}, ), - returnValue: _i8.Future.value(), - returnValueForMissingStub: _i8.Future.value(), - ) as _i8.Future); + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + + @override + void listenSelf( + void Function( + _i3.DeviceManagerState?, + _i3.DeviceManagerState, + )? listener, { + void Function( + Object, + StackTrace, + )? onError, + }) => + super.noSuchMethod( + Invocation.method( + #listenSelf, + [listener], + {#onError: onError}, + ), + returnValueForMissingStub: null, + ); @override bool updateShouldNotify( diff --git a/test/mocks/internet_settings_notifier_mocks.dart b/test/mocks/internet_settings_notifier_mocks.dart index 09adfe9db..a7683706c 100644 --- a/test/mocks/internet_settings_notifier_mocks.dart +++ b/test/mocks/internet_settings_notifier_mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.4.5 from annotations +// Mocks generated by Mockito 5.4.6 from annotations // in privacy_gui/test/mocks/mockito_specs/internet_settings_notifier_spec.dart. // Do not manually edit this file. @@ -7,8 +7,6 @@ import 'dart:async' as _i5; import 'package:flutter_riverpod/flutter_riverpod.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i7; -import 'package:privacy_gui/core/jnap/actions/better_action.dart' as _i6; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_provider.dart' as _i4; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_state.dart' @@ -27,6 +25,7 @@ import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/i // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeNotifierProviderRef_0 extends _i1.SmartFake implements _i2.NotifierProviderRef { @@ -53,9 +52,7 @@ class _FakeInternetSettingsState_1 extends _i1.SmartFake /// A class which mocks [InternetSettingsNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockInternetSettingsNotifier - extends _i2.Notifier<_i3.InternetSettingsState> - with _i1.Mock +class MockInternetSettingsNotifier extends _i1.Mock implements _i4.InternetSettingsNotifier { @override _i2.NotifierProviderRef<_i3.InternetSettingsState> get ref => @@ -117,27 +114,35 @@ class MockInternetSettingsNotifier ) as _i3.InternetSettingsState); @override - _i5.Future< - (_i3.InternetSettings?, _i3.InternetSettingsStatus?)> performFetch({ + _i5.Future<(_i3.InternetSettingsUIModel?, _i3.InternetSettingsStatusUIModel?)> + performFetch({ bool? forceRemote = false, bool? updateStatusOnly = false, }) => - (super.noSuchMethod( - Invocation.method( - #performFetch, - [], - { - #forceRemote: forceRemote, - #updateStatusOnly: updateStatusOnly, - }, - ), - returnValue: _i5 - .Future<(_i3.InternetSettings?, _i3.InternetSettingsStatus?)>.value( - (null, null)), - returnValueForMissingStub: _i5 - .Future<(_i3.InternetSettings?, _i3.InternetSettingsStatus?)>.value( - (null, null)), - ) as _i5.Future<(_i3.InternetSettings?, _i3.InternetSettingsStatus?)>); + (super.noSuchMethod( + Invocation.method( + #performFetch, + [], + { + #forceRemote: forceRemote, + #updateStatusOnly: updateStatusOnly, + }, + ), + returnValue: _i5.Future< + ( + _i3.InternetSettingsUIModel?, + _i3.InternetSettingsStatusUIModel? + )>.value((null, null)), + returnValueForMissingStub: _i5.Future< + ( + _i3.InternetSettingsUIModel?, + _i3.InternetSettingsStatusUIModel? + )>.value((null, null)), + ) as _i5.Future< + ( + _i3.InternetSettingsUIModel?, + _i3.InternetSettingsStatusUIModel? + )>); @override _i5.Future performSave() => (super.noSuchMethod( @@ -150,20 +155,7 @@ class MockInternetSettingsNotifier ) as _i5.Future); @override - List>> getSaveIpv4Transactions( - _i3.InternetSettings? data) => - (super.noSuchMethod( - Invocation.method( - #getSaveIpv4Transactions, - [data], - ), - returnValue: >>[], - returnValueForMissingStub: >>[], - ) as List>>); - - @override - _i5.Future savePnpIpv4(_i3.InternetSettings? data) => + _i5.Future savePnpIpv4(_i3.InternetSettingsUIModel? data) => (super.noSuchMethod( Invocation.method( #savePnpIpv4, @@ -173,56 +165,6 @@ class MockInternetSettingsNotifier returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); - @override - List>> getSaveIpv6Transactions( - _i3.InternetSettings? data) => - (super.noSuchMethod( - Invocation.method( - #getSaveIpv6Transactions, - [data], - ), - returnValue: >>[], - returnValueForMissingStub: >>[], - ) as List>>); - - @override - MapEntry<_i6.JNAPAction, Map> getMacAddressCloneTransaction( - bool? isMACAddressCloneEnabled, - String? macAddress, - ) => - (super.noSuchMethod( - Invocation.method( - #getMacAddressCloneTransaction, - [ - isMACAddressCloneEnabled, - macAddress, - ], - ), - returnValue: - _i7.dummyValue>>( - this, - Invocation.method( - #getMacAddressCloneTransaction, - [ - isMACAddressCloneEnabled, - macAddress, - ], - ), - ), - returnValueForMissingStub: - _i7.dummyValue>>( - this, - Invocation.method( - #getMacAddressCloneTransaction, - [ - isMACAddressCloneEnabled, - macAddress, - ], - ), - ), - ) as MapEntry<_i6.JNAPAction, Map>); - @override _i5.Future getMyMACAddress() => (super.noSuchMethod( Invocation.method( @@ -254,7 +196,7 @@ class MockInternetSettingsNotifier ) as _i5.Future); @override - void updateStatus(_i3.InternetSettingsStatus? newStatus) => + void updateStatus(_i3.InternetSettingsStatusUIModel? newStatus) => super.noSuchMethod( Invocation.method( #updateStatus, @@ -291,7 +233,8 @@ class MockInternetSettingsNotifier ); @override - void updateIpv4Settings(_i3.Ipv4Setting? ipv4Setting) => super.noSuchMethod( + void updateIpv4Settings(_i3.Ipv4SettingsUIModel? ipv4Setting) => + super.noSuchMethod( Invocation.method( #updateIpv4Settings, [ipv4Setting], @@ -300,7 +243,8 @@ class MockInternetSettingsNotifier ); @override - void updateIpv6Settings(_i3.Ipv6Setting? ipv6Setting) => super.noSuchMethod( + void updateIpv6Settings(_i3.Ipv6SettingsUIModel? ipv6Setting) => + super.noSuchMethod( Invocation.method( #updateIpv6Settings, [ipv6Setting], diff --git a/test/mocks/node_detail_notifier_mocks.dart b/test/mocks/node_detail_notifier_mocks.dart index 8769a6461..33d6d8499 100644 --- a/test/mocks/node_detail_notifier_mocks.dart +++ b/test/mocks/node_detail_notifier_mocks.dart @@ -1,15 +1,14 @@ -// Mocks generated by Mockito 5.4.4 from annotations +// Mocks generated by Mockito 5.4.6 from annotations // in privacy_gui/test/mocks/mockito_specs/node_detail_notifier_spec.dart. // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i6; +import 'dart:async' as _i5; import 'package:flutter_riverpod/flutter_riverpod.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; import 'package:privacy_gui/core/jnap/providers/device_manager_state.dart' - as _i5; -import 'package:privacy_gui/core/jnap/result/jnap_result.dart' as _i4; + as _i4; import 'package:privacy_gui/page/nodes/_nodes.dart' as _i3; // ignore_for_file: type=lint @@ -20,10 +19,12 @@ import 'package:privacy_gui/page/nodes/_nodes.dart' as _i3; // ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeNotifierProviderRef_0 extends _i1.SmartFake implements _i2.NotifierProviderRef { @@ -47,21 +48,10 @@ class _FakeNodeDetailState_1 extends _i1.SmartFake ); } -class _FakeJNAPResult_2 extends _i1.SmartFake implements _i4.JNAPResult { - _FakeJNAPResult_2( - Object parent, - Invocation parentInvocation, - ) : super( - parent, - parentInvocation, - ); -} - /// A class which mocks [NodeDetailNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockNodeDetailNotifier extends _i2.Notifier<_i3.NodeDetailState> - with _i1.Mock +class MockNodeDetailNotifier extends _i1.Mock implements _i3.NodeDetailNotifier { @override _i2.NotifierProviderRef<_i3.NodeDetailState> get ref => (super.noSuchMethod( @@ -123,7 +113,7 @@ class MockNodeDetailNotifier extends _i2.Notifier<_i3.NodeDetailState> @override _i3.NodeDetailState createState( - _i5.DeviceManagerState? deviceManagerState, + _i4.DeviceManagerState? deviceManagerState, String? targetId, ) => (super.noSuchMethod( @@ -157,72 +147,45 @@ class MockNodeDetailNotifier extends _i2.Notifier<_i3.NodeDetailState> ) as _i3.NodeDetailState); @override - _i6.Future<_i4.JNAPResult> startBlinkNodeLED(String? deviceId) => - (super.noSuchMethod( - Invocation.method( - #startBlinkNodeLED, - [deviceId], - ), - returnValue: _i6.Future<_i4.JNAPResult>.value(_FakeJNAPResult_2( - this, - Invocation.method( - #startBlinkNodeLED, - [deviceId], - ), - )), - returnValueForMissingStub: - _i6.Future<_i4.JNAPResult>.value(_FakeJNAPResult_2( - this, - Invocation.method( - #startBlinkNodeLED, - [deviceId], - ), - )), - ) as _i6.Future<_i4.JNAPResult>); - - @override - _i6.Future<_i4.JNAPResult> stopBlinkNodeLED() => (super.noSuchMethod( - Invocation.method( - #stopBlinkNodeLED, - [], - ), - returnValue: _i6.Future<_i4.JNAPResult>.value(_FakeJNAPResult_2( - this, - Invocation.method( - #stopBlinkNodeLED, - [], - ), - )), - returnValueForMissingStub: - _i6.Future<_i4.JNAPResult>.value(_FakeJNAPResult_2( - this, - Invocation.method( - #stopBlinkNodeLED, - [], - ), - )), - ) as _i6.Future<_i4.JNAPResult>); - - @override - _i6.Future toggleBlinkNode([bool? stopOnly = false]) => + _i5.Future toggleBlinkNode([bool? stopOnly = false]) => (super.noSuchMethod( Invocation.method( #toggleBlinkNode, [stopOnly], ), - returnValue: _i6.Future.value(), - returnValueForMissingStub: _i6.Future.value(), - ) as _i6.Future); + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); @override - _i6.Future updateDeviceName(String? newName) => (super.noSuchMethod( + _i5.Future updateDeviceName(String? newName) => (super.noSuchMethod( Invocation.method( #updateDeviceName, [newName], ), - returnValue: _i6.Future.value(), - returnValueForMissingStub: _i6.Future.value(), - ) as _i6.Future); + returnValue: _i5.Future.value(), + returnValueForMissingStub: _i5.Future.value(), + ) as _i5.Future); + + @override + void listenSelf( + void Function( + _i3.NodeDetailState?, + _i3.NodeDetailState, + )? listener, { + void Function( + Object, + StackTrace, + )? onError, + }) => + super.noSuchMethod( + Invocation.method( + #listenSelf, + [listener], + {#onError: onError}, + ), + returnValueForMissingStub: null, + ); @override bool updateShouldNotify( diff --git a/test/mocks/polling_notifier_mocks.dart b/test/mocks/polling_notifier_mocks.dart index 9e3667351..4a9ddae04 100644 --- a/test/mocks/polling_notifier_mocks.dart +++ b/test/mocks/polling_notifier_mocks.dart @@ -7,7 +7,6 @@ import 'dart:async' as _i4; import 'package:flutter_riverpod/flutter_riverpod.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; -import 'package:mockito/src/dummies.dart' as _i5; import 'package:privacy_gui/core/jnap/providers/polling_provider.dart' as _i3; // ignore_for_file: type=lint @@ -23,6 +22,7 @@ import 'package:privacy_gui/core/jnap/providers/polling_provider.dart' as _i3; // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeAsyncNotifierProviderRef_0 extends _i1.SmartFake implements _i2.AsyncNotifierProviderRef { @@ -59,9 +59,7 @@ class _FakeCoreTransactionData_2 extends _i1.SmartFake /// A class which mocks [PollingNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockPollingNotifier extends _i2.AsyncNotifier<_i3.CoreTransactionData> - with _i1.Mock - implements _i3.PollingNotifier { +class MockPollingNotifier extends _i1.Mock implements _i3.PollingNotifier { @override bool get paused => (super.noSuchMethod( Invocation.getter(#paused), @@ -174,29 +172,6 @@ class MockPollingNotifier extends _i2.AsyncNotifier<_i3.CoreTransactionData> returnValueForMissingStub: null, ); - @override - _i4.Future checkSmartMode() => (super.noSuchMethod( - Invocation.method( - #checkSmartMode, - [], - ), - returnValue: _i4.Future.value(_i5.dummyValue( - this, - Invocation.method( - #checkSmartMode, - [], - ), - )), - returnValueForMissingStub: - _i4.Future.value(_i5.dummyValue( - this, - Invocation.method( - #checkSmartMode, - [], - ), - )), - ) as _i4.Future); - @override void listenSelf( void Function( diff --git a/test/mocks/test_data/dashboard_home_test_data.dart b/test/mocks/test_data/dashboard_home_test_data.dart index 0931fb2b2..53110b169 100644 --- a/test/mocks/test_data/dashboard_home_test_data.dart +++ b/test/mocks/test_data/dashboard_home_test_data.dart @@ -404,7 +404,7 @@ class DashboardHomeTestData { 'description': 'Test Router', 'firmwareVersion': '1.0.0', 'firmwareDate': '2024-01-01T00:00:00Z', - 'services': ['http://linksys.com/jnap/core/Core'], + 'services': const ['http://linksys.com/jnap/core/Core'], }); } diff --git a/test/mocks/test_data/dashboard_manager_test_data.dart b/test/mocks/test_data/dashboard_manager_test_data.dart index 66e0bf023..359d2cd42 100644 --- a/test/mocks/test_data/dashboard_manager_test_data.dart +++ b/test/mocks/test_data/dashboard_manager_test_data.dart @@ -31,7 +31,7 @@ class DashboardManagerTestData { 'manufacturer': manufacturer, 'description': description, 'firmwareDate': firmwareDate, - 'services': ['http://linksys.com/jnap/core/Core'], + 'services': const ['http://linksys.com/jnap/core/Core'], }, ); @@ -271,7 +271,7 @@ class DashboardManagerTestData { return createSuccessfulPollingData( localTime: JNAPSuccess( result: 'OK', - output: { + output: const { 'currentTime': 'invalid-time-format', }, ), diff --git a/test/mocks/test_data/ddns_test_data.dart b/test/mocks/test_data/ddns_test_data.dart index 676b2d1b7..837c7bbb7 100644 --- a/test/mocks/test_data/ddns_test_data.dart +++ b/test/mocks/test_data/ddns_test_data.dart @@ -75,9 +75,9 @@ class DDNSTestData { 'detectedWANType': 'DHCP', 'wanStatus': wanStatus, 'wanIPv6Status': 'Disconnected', - 'supportedWANTypes': ['DHCP', 'Static', 'PPPoE'], - 'supportedIPv6WANTypes': [], - 'supportedWANCombinations': [], + 'supportedWANTypes': const ['DHCP', 'Static', 'PPPoE'], + 'supportedIPv6WANTypes': const [], + 'supportedWANCombinations': const [], 'wanConnection': { 'wanType': 'DHCP', 'ipAddress': wanIP, diff --git a/test/mocks/test_data/polling_test_data.dart b/test/mocks/test_data/polling_test_data.dart index 3e253007f..0af9f8bbf 100644 --- a/test/mocks/test_data/polling_test_data.dart +++ b/test/mocks/test_data/polling_test_data.dart @@ -47,7 +47,7 @@ class PollingTestData { /// Create getRadioInfo success response static JNAPSuccess createRadioInfoSuccess() => JNAPSuccess( result: 'OK', - output: { + output: const { 'isBandSteeringSupported': true, 'radios': [ { @@ -178,7 +178,7 @@ class PollingTestData { result: 'OK', output: { 'isEnabled': isEnabled, - 'macAddresses': [], + 'macAddresses': const [], }, ); diff --git a/test/mocks/test_data/port_range_forwarding_test_data.dart b/test/mocks/test_data/port_range_forwarding_test_data.dart index 35885e179..30c1fdc5f 100644 --- a/test/mocks/test_data/port_range_forwarding_test_data.dart +++ b/test/mocks/test_data/port_range_forwarding_test_data.dart @@ -80,7 +80,7 @@ class PortRangeForwardingTestData { return JNAPSuccess( result: 'ok', output: { - 'rules': [], + 'rules': const [], 'maxRules': maxRules, 'maxDescriptionLength': maxDescriptionLength, }, @@ -104,11 +104,11 @@ class PortRangeForwardingTestData { 'maxAllowedDHCPLeaseMinutes': 10080, 'maxDHCPReservationDescriptionLength': 32, 'hostName': 'Linksys', - 'dhcpSettings': { + 'dhcpSettings': const { 'firstClientIPAddress': '192.168.1.100', 'lastClientIPAddress': '192.168.1.200', 'leaseMinutes': 1440, - 'reservations': const >[], + 'reservations': >[], }, }, ); diff --git a/test/mocks/test_data/port_range_triggering_test_data.dart b/test/mocks/test_data/port_range_triggering_test_data.dart index 486e7fbea..d5beeb467 100644 --- a/test/mocks/test_data/port_range_triggering_test_data.dart +++ b/test/mocks/test_data/port_range_triggering_test_data.dart @@ -80,7 +80,7 @@ class PortRangeTriggeringTestData { return JNAPSuccess( result: 'ok', output: { - 'rules': [], + 'rules': const [], 'maxRules': maxRules, 'maxDescriptionLength': maxDescriptionLength, }, diff --git a/test/mocks/test_data/single_port_forwarding_test_data.dart b/test/mocks/test_data/single_port_forwarding_test_data.dart index 2a8a3f939..085e260d1 100644 --- a/test/mocks/test_data/single_port_forwarding_test_data.dart +++ b/test/mocks/test_data/single_port_forwarding_test_data.dart @@ -23,7 +23,7 @@ class SinglePortForwardingTestData { 'hostName': 'linksys', 'maxDHCPReservationDescriptionLength': 32, 'isDHCPEnabled': true, - 'dhcpSettings': { + 'dhcpSettings': const { 'lastClientIPAddress': '192.168.1.254', 'leaseMinutes': 1440, 'reservations': [], diff --git a/test/mocks/test_data/static_routing_test_data.dart b/test/mocks/test_data/static_routing_test_data.dart index a8b66285d..f8a00cbb0 100644 --- a/test/mocks/test_data/static_routing_test_data.dart +++ b/test/mocks/test_data/static_routing_test_data.dart @@ -3,7 +3,6 @@ import 'package:privacy_gui/core/jnap/models/lan_settings.dart'; import 'package:privacy_gui/page/advanced_settings/static_routing/models/static_route_entry_ui_model.dart'; import 'package:privacy_gui/page/advanced_settings/static_routing/models/static_routing_rule_ui_model.dart'; import 'package:privacy_gui/page/advanced_settings/static_routing/providers/static_routing_rule_state.dart'; -import 'package:privacy_gui/utils.dart'; /// Test data builder for StaticRoutingService tests /// diff --git a/test/page/advanced_settings/apps_and_gaming/ddns/providers/ddns_provider_test.dart b/test/page/advanced_settings/apps_and_gaming/ddns/providers/ddns_provider_test.dart index 6f324cd1e..e2fd37532 100644 --- a/test/page/advanced_settings/apps_and_gaming/ddns/providers/ddns_provider_test.dart +++ b/test/page/advanced_settings/apps_and_gaming/ddns/providers/ddns_provider_test.dart @@ -40,7 +40,7 @@ void main() { ), ); final status = DDNSStatusUIModel( - supportedProviders: ['', 'DynDNS'], + supportedProviders: const ['', 'DynDNS'], status: 'Connected', ipAddress: '192.168.1.1', ); diff --git a/test/page/advanced_settings/apps_and_gaming/ports/services/port_range_forwarding_service_test.dart b/test/page/advanced_settings/apps_and_gaming/ports/services/port_range_forwarding_service_test.dart index 9dca67f79..25414f9f2 100644 --- a/test/page/advanced_settings/apps_and_gaming/ports/services/port_range_forwarding_service_test.dart +++ b/test/page/advanced_settings/apps_and_gaming/ports/services/port_range_forwarding_service_test.dart @@ -237,8 +237,8 @@ void main() { () async { // Arrange final uiModel = PortRangeForwardingRuleListUIModel( - rules: [ - const PortRangeForwardingRuleUIModel( + rules: const [ + PortRangeForwardingRuleUIModel( isEnabled: true, firstExternalPort: 5000, protocol: 'TCP', @@ -306,8 +306,8 @@ void main() { test('saves multiple rules correctly', () async { // Arrange final uiModel = PortRangeForwardingRuleListUIModel( - rules: [ - const PortRangeForwardingRuleUIModel( + rules: const [ + PortRangeForwardingRuleUIModel( isEnabled: true, firstExternalPort: 3000, protocol: 'TCP', @@ -315,7 +315,7 @@ void main() { lastExternalPort: 3000, description: 'Rule 1', ), - const PortRangeForwardingRuleUIModel( + PortRangeForwardingRuleUIModel( isEnabled: false, firstExternalPort: 4000, protocol: 'UDP', diff --git a/test/page/advanced_settings/apps_and_gaming/ports/services/port_range_triggering_service_test.dart b/test/page/advanced_settings/apps_and_gaming/ports/services/port_range_triggering_service_test.dart index b7779cbb8..e909b1728 100644 --- a/test/page/advanced_settings/apps_and_gaming/ports/services/port_range_triggering_service_test.dart +++ b/test/page/advanced_settings/apps_and_gaming/ports/services/port_range_triggering_service_test.dart @@ -180,8 +180,8 @@ void main() { () async { // Arrange final uiModel = PortRangeTriggeringRuleListUIModel( - rules: [ - const PortRangeTriggeringRuleUIModel( + rules: const [ + PortRangeTriggeringRuleUIModel( isEnabled: true, firstTriggerPort: 5000, lastTriggerPort: 5000, @@ -251,8 +251,8 @@ void main() { test('saves multiple rules correctly', () async { // Arrange final uiModel = PortRangeTriggeringRuleListUIModel( - rules: [ - const PortRangeTriggeringRuleUIModel( + rules: const [ + PortRangeTriggeringRuleUIModel( isEnabled: true, firstTriggerPort: 3000, lastTriggerPort: 3000, @@ -260,7 +260,7 @@ void main() { lastForwardedPort: 3100, description: 'Rule 1', ), - const PortRangeTriggeringRuleUIModel( + PortRangeTriggeringRuleUIModel( isEnabled: false, firstTriggerPort: 4000, lastTriggerPort: 4100, diff --git a/test/page/advanced_settings/dmz/providers/dmz_settings_state_test.dart b/test/page/advanced_settings/dmz/providers/dmz_settings_state_test.dart index dd8411665..824ed9c0b 100644 --- a/test/page/advanced_settings/dmz/providers/dmz_settings_state_test.dart +++ b/test/page/advanced_settings/dmz/providers/dmz_settings_state_test.dart @@ -600,7 +600,7 @@ void main() { ); const state = DMZSettingsState( settings: preservableSettings, - status: const DMZStatus(), + status: DMZStatus(), ); const newSettings = DMZUISettings( @@ -634,7 +634,7 @@ void main() { ); const state = DMZSettingsState( settings: preservableSettings, - status: const DMZStatus(), + status: DMZStatus(), ); const newStatus = DMZStatus( @@ -663,7 +663,7 @@ void main() { ); const state = DMZSettingsState( settings: preservableSettings, - status: const DMZStatus(), + status: DMZStatus(), ); // Act @@ -747,7 +747,7 @@ void main() { ); const state = DMZSettingsState( settings: preservableSettings, - status: const DMZStatus(), + status: DMZStatus(), ); // Act @@ -774,7 +774,7 @@ void main() { ); const originalState = DMZSettingsState( settings: preservableSettings, - status: const DMZStatus(), + status: DMZStatus(), ); final json = originalState.toJson(); @@ -834,11 +834,11 @@ void main() { ); const state1 = DMZSettingsState( settings: preservableSettings, - status: const DMZStatus(), + status: DMZStatus(), ); const state2 = DMZSettingsState( settings: preservableSettings, - status: const DMZStatus(), + status: DMZStatus(), ); // Assert diff --git a/test/page/advanced_settings/dmz/providers/dmz_status_test.dart b/test/page/advanced_settings/dmz/providers/dmz_status_test.dart index 90cd0dc3a..4f96da0ef 100644 --- a/test/page/advanced_settings/dmz/providers/dmz_status_test.dart +++ b/test/page/advanced_settings/dmz/providers/dmz_status_test.dart @@ -40,7 +40,7 @@ void main() { }); test('fromMap uses defaults for missing values', () { - final status = DMZStatus.fromMap({}); + final status = DMZStatus.fromMap(const {}); expect(status.ipAddress, '192.168.1.1'); expect(status.subnetMask, '255.255.0.0'); }); diff --git a/test/page/advanced_settings/dmz/services/dmz_settings_service_test.dart b/test/page/advanced_settings/dmz/services/dmz_settings_service_test.dart index fc21ab1c3..29fe8a362 100644 --- a/test/page/advanced_settings/dmz/services/dmz_settings_service_test.dart +++ b/test/page/advanced_settings/dmz/services/dmz_settings_service_test.dart @@ -4,7 +4,6 @@ import 'package:privacy_gui/core/jnap/actions/better_action.dart'; import 'package:privacy_gui/core/jnap/actions/jnap_transaction.dart'; import 'package:privacy_gui/core/jnap/result/jnap_result.dart'; import 'package:privacy_gui/core/jnap/router_repository.dart'; -import 'package:privacy_gui/core/jnap/models/dmz_settings.dart' as jnap_models; import 'package:privacy_gui/page/advanced_settings/dmz/providers/dmz_settings_state.dart'; import 'package:privacy_gui/page/advanced_settings/dmz/services/dmz_settings_service.dart'; @@ -214,7 +213,7 @@ void main() { cacheLevel: any(named: 'cacheLevel'), auth: any(named: 'auth'), data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'ok', output: {})); + )).thenAnswer((_) async => JNAPSuccess(result: 'ok', output: const {})); final mockRef = UnitTestHelper.createMockRef( routerRepository: mockRepository, @@ -281,7 +280,7 @@ void main() { cacheLevel: any(named: 'cacheLevel'), auth: any(named: 'auth'), data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'ok', output: {})); + )).thenAnswer((_) async => JNAPSuccess(result: 'ok', output: const {})); final mockRef = UnitTestHelper.createMockRef( routerRepository: mockRepository, diff --git a/test/page/advanced_settings/dmz/services/dmz_settings_service_test_data.dart b/test/page/advanced_settings/dmz/services/dmz_settings_service_test_data.dart index 24c2b9401..97fc3616e 100644 --- a/test/page/advanced_settings/dmz/services/dmz_settings_service_test_data.dart +++ b/test/page/advanced_settings/dmz/services/dmz_settings_service_test_data.dart @@ -21,7 +21,7 @@ class DMZSettingsTestData { 'maxNetworkPrefixLength': 30, 'minAllowedDHCPLeaseMinutes': 1, 'maxAllowedDHCPLeaseMinutes': 525600, - 'dhcpSettings': { + 'dhcpSettings': const { 'firstClientIPAddress': '192.168.1.10', 'lastClientIPAddress': '192.168.1.254', 'leaseMinutes': 1440, diff --git a/test/page/advanced_settings/firewall/providers/firewall_provider_test.dart b/test/page/advanced_settings/firewall/providers/firewall_provider_test.dart index 8eab799aa..b231b464d 100644 --- a/test/page/advanced_settings/firewall/providers/firewall_provider_test.dart +++ b/test/page/advanced_settings/firewall/providers/firewall_provider_test.dart @@ -4,7 +4,6 @@ import 'package:mocktail/mocktail.dart'; import 'package:privacy_gui/core/jnap/router_repository.dart'; import 'package:privacy_gui/page/advanced_settings/firewall/providers/firewall_provider.dart'; import 'package:privacy_gui/page/advanced_settings/firewall/providers/firewall_state.dart'; -import 'package:privacy_gui/page/advanced_settings/firewall/services/firewall_settings_service.dart'; // Mock class for Ref class MockRef extends Mock implements Ref {} diff --git a/test/page/advanced_settings/firewall/providers/firewall_state_test.dart b/test/page/advanced_settings/firewall/providers/firewall_state_test.dart index 59d060b9d..b5af8f6a4 100644 --- a/test/page/advanced_settings/firewall/providers/firewall_state_test.dart +++ b/test/page/advanced_settings/firewall/providers/firewall_state_test.dart @@ -700,7 +700,7 @@ void main() { ); const state = FirewallState( settings: preservableSettings, - status: const EmptyStatus(), + status: EmptyStatus(), ); const newSettings = FirewallUISettings( @@ -746,7 +746,7 @@ void main() { ); const state = FirewallState( settings: preservableSettings, - status: const EmptyStatus(), + status: EmptyStatus(), ); const newStatus = EmptyStatus(); @@ -778,7 +778,7 @@ void main() { ); const state = FirewallState( settings: preservableSettings, - status: const EmptyStatus(), + status: EmptyStatus(), ); // Act @@ -809,7 +809,7 @@ void main() { ); const state = FirewallState( settings: preservableSettings, - status: const EmptyStatus(), + status: EmptyStatus(), ); // Act @@ -839,7 +839,7 @@ void main() { ); const originalState = FirewallState( settings: preservableSettings, - status: const EmptyStatus(), + status: EmptyStatus(), ); final map = originalState.toMap(); @@ -870,7 +870,7 @@ void main() { ); const originalState = FirewallState( settings: preservableSettings, - status: const EmptyStatus(), + status: EmptyStatus(), ); // Act @@ -901,7 +901,7 @@ void main() { ); const originalState = FirewallState( settings: preservableSettings, - status: const EmptyStatus(), + status: EmptyStatus(), ); final map = originalState.toMap(); final json = jsonEncode(map); diff --git a/test/page/advanced_settings/firewall/providers/ipv6_port_service_list_provider_test.dart b/test/page/advanced_settings/firewall/providers/ipv6_port_service_list_provider_test.dart index f0bd52e38..377b9b14d 100644 --- a/test/page/advanced_settings/firewall/providers/ipv6_port_service_list_provider_test.dart +++ b/test/page/advanced_settings/firewall/providers/ipv6_port_service_list_provider_test.dart @@ -105,7 +105,6 @@ void main() { // Act notifier.setRules(rules); - final state = container.read(ipv6PortServiceListProvider); // Assert expect(notifier.isExceedMax(), false); @@ -128,7 +127,6 @@ void main() { // Act notifier.setRules(rules); - final state = container.read(ipv6PortServiceListProvider); // Assert expect(notifier.isExceedMax(), true); @@ -873,12 +871,12 @@ void main() { group('performFetch integration', () { test('fetches rules via service provider', () async { // Arrange - final testRules = IPv6PortServiceRuleUIList(rules: [ + final testRules = IPv6PortServiceRuleUIList(rules: const [ IPv6PortServiceRuleUI( enabled: true, description: 'Test Rule', ipv6Address: '2001:db8::1', - portRanges: const [ + portRanges: [ PortRangeUI(protocol: 'TCP', firstPort: 80, lastPort: 80) ], ), @@ -886,7 +884,7 @@ void main() { enabled: false, description: 'Another Rule', ipv6Address: '2001:db8::2', - portRanges: const [ + portRanges: [ PortRangeUI(protocol: 'UDP', firstPort: 53, lastPort: 53) ], ) @@ -913,12 +911,12 @@ void main() { test('fetches with forceRemote parameter', () async { // Arrange - final testRules = IPv6PortServiceRuleUIList(rules: [ + final testRules = IPv6PortServiceRuleUIList(rules: const [ IPv6PortServiceRuleUI( enabled: true, description: 'Remote Rule', ipv6Address: '2001:db8::1', - portRanges: const [ + portRanges: [ PortRangeUI(protocol: 'TCP', firstPort: 22, lastPort: 22) ], ) diff --git a/test/page/advanced_settings/firewall/providers/ipv6_port_service_rule_state_test.dart b/test/page/advanced_settings/firewall/providers/ipv6_port_service_rule_state_test.dart index dbc2016e3..687e71578 100644 --- a/test/page/advanced_settings/firewall/providers/ipv6_port_service_rule_state_test.dart +++ b/test/page/advanced_settings/firewall/providers/ipv6_port_service_rule_state_test.dart @@ -99,7 +99,7 @@ void main() { lastPort: 8080, ); - final portRange = PortRangeUI.fromMap({ + final portRange = PortRangeUI.fromMap(const { 'protocol': 'TCP', 'firstPort': 80, 'lastPort': 8080, @@ -258,7 +258,7 @@ void main() { ], ); - final rule = IPv6PortServiceRuleUI.fromMap({ + final rule = IPv6PortServiceRuleUI.fromMap(const { 'enabled': true, 'description': 'Test', 'ipv6Address': '2001:db8::1', @@ -472,7 +472,7 @@ void main() { ), ]); - final list = IPv6PortServiceRuleUIList.fromMap({ + final list = IPv6PortServiceRuleUIList.fromMap(const { 'rules': [ { 'enabled': true, diff --git a/test/page/advanced_settings/firewall/services/firewall_settings_service_test.dart b/test/page/advanced_settings/firewall/services/firewall_settings_service_test.dart index 5cce84078..fd690ffdb 100644 --- a/test/page/advanced_settings/firewall/services/firewall_settings_service_test.dart +++ b/test/page/advanced_settings/firewall/services/firewall_settings_service_test.dart @@ -318,8 +318,6 @@ void main() { routerRepository: mockRepository, ); - final uiSettings = - FirewallSettingsTestData.createSuccessfulResponse().output; final firewallUISettings = service.fetchFirewallSettings(mockRef).then((value) => value.$1!); diff --git a/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test.dart b/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test.dart index dbb9c41ac..40a441ab6 100644 --- a/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test.dart +++ b/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test.dart @@ -36,8 +36,8 @@ void main() { isEnabled: true, description: 'SSH Access', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 22, lastPort: 22), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 22, lastPort: 22), ], ); @@ -62,17 +62,17 @@ void main() { isEnabled: true, description: 'Web Server', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 80, lastPort: 80), - const PortRange(protocol: 'TCP', firstPort: 443, lastPort: 443), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 80, lastPort: 80), + PortRange(protocol: 'TCP', firstPort: 443, lastPort: 443), ], ), IPv6FirewallRule( isEnabled: false, description: 'DNS', ipv6Address: '2001:db8::2', - portRanges: [ - const PortRange(protocol: 'UDP', firstPort: 53, lastPort: 53), + portRanges: const [ + PortRange(protocol: 'UDP', firstPort: 53, lastPort: 53), ], ), ]; @@ -101,24 +101,24 @@ void main() { isEnabled: true, description: 'TCP Rule', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 1000, lastPort: 2000), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 1000, lastPort: 2000), ], ), IPv6FirewallRule( isEnabled: true, description: 'UDP Rule', ipv6Address: '2001:db8::2', - portRanges: [ - const PortRange(protocol: 'UDP', firstPort: 3000, lastPort: 4000), + portRanges: const [ + PortRange(protocol: 'UDP', firstPort: 3000, lastPort: 4000), ], ), IPv6FirewallRule( isEnabled: true, description: 'Both Rule', ipv6Address: '2001:db8::3', - portRanges: [ - const PortRange( + portRanges: const [ + PortRange( protocol: 'Both', firstPort: 5000, lastPort: 6000), ], ), @@ -136,8 +136,8 @@ void main() { isEnabled: true, description: 'Edge Ports', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 0, lastPort: 65535), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 0, lastPort: 65535), ], ); @@ -154,8 +154,8 @@ void main() { isEnabled: true, description: 'Test-Rule_#123!@Special', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 8080, lastPort: 8080), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 8080, lastPort: 8080), ], ); @@ -170,8 +170,8 @@ void main() { isEnabled: true, description: longDescription, ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 80, lastPort: 80), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 80, lastPort: 80), ], ); @@ -186,8 +186,8 @@ void main() { isEnabled: true, description: 'Test', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 80, lastPort: 80), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 80, lastPort: 80), ], ); @@ -220,9 +220,9 @@ void main() { isEnabled: true, description: 'Preserve Test', ipv6Address: '2001:db8::10', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 1000, lastPort: 2000), - const PortRange(protocol: 'UDP', firstPort: 3000, lastPort: 4000), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 1000, lastPort: 2000), + PortRange(protocol: 'UDP', firstPort: 3000, lastPort: 4000), ], ); @@ -277,8 +277,8 @@ void main() { isEnabled: true, description: 'Single Port', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 80, lastPort: 80), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 80, lastPort: 80), ], ); @@ -388,9 +388,9 @@ void main() { isEnabled: true, description: 'Round-trip Test', ipv6Address: '2001:db8::10', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 1000, lastPort: 2000), - const PortRange(protocol: 'UDP', firstPort: 3000, lastPort: 4000), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 1000, lastPort: 2000), + PortRange(protocol: 'UDP', firstPort: 3000, lastPort: 4000), ], ); @@ -462,8 +462,8 @@ void main() { isEnabled: true, description: 'Bad Protocol', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'INVALID', firstPort: 80, lastPort: 80), + portRanges: const [ + PortRange(protocol: 'INVALID', firstPort: 80, lastPort: 80), ], ); @@ -481,8 +481,8 @@ void main() { isEnabled: true, description: 'Bad Port', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 65536, lastPort: 65537), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 65536, lastPort: 65537), ], ); @@ -500,8 +500,8 @@ void main() { isEnabled: true, description: 'Reversed Range', ipv6Address: '2001:db8::1', - portRanges: [ - const PortRange(protocol: 'TCP', firstPort: 443, lastPort: 80), + portRanges: const [ + PortRange(protocol: 'TCP', firstPort: 443, lastPort: 80), ], ); diff --git a/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test_data.dart b/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test_data.dart index 363792868..57243eb7b 100644 --- a/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test_data.dart +++ b/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test_data.dart @@ -23,7 +23,7 @@ class IPv6PortServiceTestData { JNAPSuccess( result: 'OK', output: { - 'rules': [], + 'rules': const [], 'maxRules': maxRules, 'maxDescriptionLength': maxDescriptionLength, }, @@ -86,7 +86,7 @@ class IPv6PortServiceTestData { JNAPSuccess( result: 'OK', output: { - 'rules': [ + 'rules': const [ { 'description': 'Web Server', 'ipv6Address': '2001:db8::1', diff --git a/test/page/advanced_settings/internet_settings/models/internet_settings_ui_model_test.dart b/test/page/advanced_settings/internet_settings/models/internet_settings_ui_model_test.dart index 00ffeb897..cb2932e1a 100644 --- a/test/page/advanced_settings/internet_settings/models/internet_settings_ui_model_test.dart +++ b/test/page/advanced_settings/internet_settings/models/internet_settings_ui_model_test.dart @@ -214,7 +214,7 @@ void main() { test('toMap and fromMap work correctly', () { // Arrange - final original = const InternetSettingsStatusUIModel( + const original = InternetSettingsStatusUIModel( supportedIPv4ConnectionType: ['DHCP', 'PPPoE'], supportedWANCombinations: [], supportedIPv6ConnectionType: ['Automatic'], @@ -235,7 +235,7 @@ void main() { test('toJson and fromJson work correctly', () { // Arrange - final original = const InternetSettingsStatusUIModel( + const original = InternetSettingsStatusUIModel( supportedIPv4ConnectionType: ['Static'], supportedWANCombinations: [], supportedIPv6ConnectionType: ['PPPoE'], @@ -254,7 +254,7 @@ void main() { test('equality works correctly', () { // Arrange - final model1 = const InternetSettingsStatusUIModel( + const model1 = InternetSettingsStatusUIModel( supportedIPv4ConnectionType: ['DHCP'], supportedWANCombinations: [], supportedIPv6ConnectionType: ['Automatic'], @@ -263,7 +263,7 @@ void main() { redirection: null, ); - final model2 = const InternetSettingsStatusUIModel( + const model2 = InternetSettingsStatusUIModel( supportedIPv4ConnectionType: ['DHCP'], supportedWANCombinations: [], supportedIPv6ConnectionType: ['Automatic'], diff --git a/test/page/advanced_settings/internet_settings/services/internet_settings_service_test.dart b/test/page/advanced_settings/internet_settings/services/internet_settings_service_test.dart index b70675f6c..56aed1c76 100644 --- a/test/page/advanced_settings/internet_settings/services/internet_settings_service_test.dart +++ b/test/page/advanced_settings/internet_settings/services/internet_settings_service_test.dart @@ -351,18 +351,18 @@ void main() { final mockTransaction = JNAPTransactionSuccessWrap( result: 'OK', - data: [ + data: const [ MapEntry( JNAPAction.setMACAddressCloneSettings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), MapEntry( JNAPAction.setWANSettings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), MapEntry( JNAPAction.setIPv6Settings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), ], ); @@ -394,18 +394,18 @@ void main() { final mockTransaction = JNAPTransactionSuccessWrap( result: 'OK', - data: [ + data: const [ MapEntry( JNAPAction.setMACAddressCloneSettings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), MapEntry( JNAPAction.setWANSettings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), MapEntry( JNAPAction.setIPv6Settings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), ], ); @@ -439,14 +439,14 @@ void main() { final mockTransaction = JNAPTransactionSuccessWrap( result: 'OK', - data: [ + data: const [ MapEntry( JNAPAction.setMACAddressCloneSettings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), MapEntry( JNAPAction.setWANSettings, - const JNAPSuccess( + JNAPSuccess( result: 'OK', output: { 'redirection': {'url': 'http://192.168.1.1'} @@ -455,7 +455,7 @@ void main() { ), MapEntry( JNAPAction.setIPv6Settings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), ], ); @@ -523,14 +523,14 @@ void main() { cacheLevel: any(named: 'cacheLevel'), )).thenAnswer((_) async => JNAPTransactionSuccessWrap( result: 'OK', - data: [ + data: const [ MapEntry( JNAPAction.setMACAddressCloneSettings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), MapEntry( JNAPAction.setWANSettings, - const JNAPSuccess(result: 'OK', output: {}), + JNAPSuccess(result: 'OK', output: {}), ), ], )); @@ -604,7 +604,7 @@ void main() { ); // Create ServiceSideEffectError without originalResult - final sideEffectError = const ServiceSideEffectError(null); + const sideEffectError = ServiceSideEffectError(null); when(() => mockRepo.transaction( any(), diff --git a/test/page/advanced_settings/internet_settings/views/localizations/internet_settings_view_test.dart b/test/page/advanced_settings/internet_settings/views/localizations/internet_settings_view_test.dart index d2ce2b313..69d16a5fb 100644 --- a/test/page/advanced_settings/internet_settings/views/localizations/internet_settings_view_test.dart +++ b/test/page/advanced_settings/internet_settings/views/localizations/internet_settings_view_test.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:privacy_gui/core/utils/extension.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/internet_settings_state.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/views/internet_settings_view.dart'; import 'package:ui_kit_library/ui_kit.dart'; diff --git a/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_provider_test.dart b/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_provider_test.dart index dc1390e47..050170077 100644 --- a/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_provider_test.dart +++ b/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_provider_test.dart @@ -311,7 +311,7 @@ void main() { ), ); notifier - .updateSettings(DHCPReservationsSettings(reservations: [newItem])); + .updateSettings(DHCPReservationsSettings(reservations: const [newItem])); final state = container.read(dhcpReservationProvider); expect(state.settings.current.reservations, hasLength(1)); diff --git a/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_state_test.dart b/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_state_test.dart index fa5aae543..d5886659c 100644 --- a/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_state_test.dart +++ b/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_state_test.dart @@ -1,7 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:privacy_gui/page/advanced_settings/local_network_settings/models/dhcp_reservation_ui_model.dart'; import 'package:privacy_gui/page/advanced_settings/local_network_settings/providers/dhcp_reservations_state.dart'; -import 'package:privacy_gui/providers/preservable.dart'; void main() { group('DHCPReservationsSettings', () { diff --git a/test/page/advanced_settings/local_network_settings/providers/local_network_settings_state_test.dart b/test/page/advanced_settings/local_network_settings/providers/local_network_settings_state_test.dart index 0ed0d1359..567e64209 100644 --- a/test/page/advanced_settings/local_network_settings/providers/local_network_settings_state_test.dart +++ b/test/page/advanced_settings/local_network_settings/providers/local_network_settings_state_test.dart @@ -1,7 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:privacy_gui/page/advanced_settings/local_network_settings/models/dhcp_reservation_ui_model.dart'; import 'package:privacy_gui/page/advanced_settings/local_network_settings/providers/local_network_settings_state.dart'; -import 'package:privacy_gui/providers/preservable.dart'; void main() { group('LocalNetworkSettings', () { diff --git a/test/page/advanced_settings/static_routing/models/static_route_entry_ui_model_test.dart b/test/page/advanced_settings/static_routing/models/static_route_entry_ui_model_test.dart index f48b8a584..b0d1496c1 100644 --- a/test/page/advanced_settings/static_routing/models/static_route_entry_ui_model_test.dart +++ b/test/page/advanced_settings/static_routing/models/static_route_entry_ui_model_test.dart @@ -60,7 +60,7 @@ void main() { }); test('fromMap uses defaults for missing values', () { - final model = StaticRouteEntryUIModel.fromMap({}); + final model = StaticRouteEntryUIModel.fromMap(const {}); expect(model.name, ''); expect(model.interface, 'LAN'); }); diff --git a/test/page/advanced_settings/static_routing/models/static_routing_rule_ui_model_test.dart b/test/page/advanced_settings/static_routing/models/static_routing_rule_ui_model_test.dart index 42b8443af..6e6c3443b 100644 --- a/test/page/advanced_settings/static_routing/models/static_routing_rule_ui_model_test.dart +++ b/test/page/advanced_settings/static_routing/models/static_routing_rule_ui_model_test.dart @@ -75,7 +75,7 @@ void main() { }); test('fromMap uses defaults for missing values', () { - final model = StaticRoutingRuleUIModel.fromMap({}); + final model = StaticRoutingRuleUIModel.fromMap(const {}); expect(model.name, ''); expect(model.networkPrefixLength, 24); expect(model.interface, 'LAN'); diff --git a/test/page/advanced_settings/static_routing/providers/static_routing_rule_provider_test.dart b/test/page/advanced_settings/static_routing/providers/static_routing_rule_provider_test.dart index 444ac62ae..806f9af21 100644 --- a/test/page/advanced_settings/static_routing/providers/static_routing_rule_provider_test.dart +++ b/test/page/advanced_settings/static_routing/providers/static_routing_rule_provider_test.dart @@ -2,7 +2,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:privacy_gui/page/advanced_settings/static_routing/models/static_routing_rule_ui_model.dart'; import 'package:privacy_gui/page/advanced_settings/static_routing/providers/static_routing_rule_provider.dart'; -import 'package:privacy_gui/page/advanced_settings/static_routing/providers/static_routing_rule_state.dart'; void main() { group('StaticRoutingRuleNotifier', () { @@ -17,7 +16,6 @@ void main() { }); test('builds with default initial state', () { - final notifier = container.read(staticRoutingRuleProvider.notifier); final state = container.read(staticRoutingRuleProvider); expect(state.routerIp, '192.168.1.1'); diff --git a/test/page/advanced_settings/static_routing/providers/static_routing_state_test.dart b/test/page/advanced_settings/static_routing/providers/static_routing_state_test.dart index decd5cbbc..7b37cf86a 100644 --- a/test/page/advanced_settings/static_routing/providers/static_routing_state_test.dart +++ b/test/page/advanced_settings/static_routing/providers/static_routing_state_test.dart @@ -1,7 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:privacy_gui/page/advanced_settings/static_routing/models/static_route_entry_ui_model.dart'; import 'package:privacy_gui/page/advanced_settings/static_routing/providers/static_routing_state.dart'; -import 'dart:convert'; void main() { group('StaticRouteEntryUI - Model Tests', () { @@ -150,7 +149,7 @@ void main() { final settings = StaticRoutingSettings( isNATEnabled: true, isDynamicRoutingEnabled: false, - entries: [], + entries: const [], ); // Assert @@ -164,7 +163,7 @@ void main() { final original = StaticRoutingSettings( isNATEnabled: true, isDynamicRoutingEnabled: false, - entries: [], + entries: const [], ); // Act @@ -181,17 +180,17 @@ void main() { final settings1 = StaticRoutingSettings( isNATEnabled: true, isDynamicRoutingEnabled: false, - entries: [], + entries: const [], ); final settings2 = StaticRoutingSettings( isNATEnabled: true, isDynamicRoutingEnabled: false, - entries: [], + entries: const [], ); final settings3 = StaticRoutingSettings( isNATEnabled: false, isDynamicRoutingEnabled: false, - entries: [], + entries: const [], ); // Assert @@ -246,7 +245,7 @@ void main() { final original = StaticRoutingSettings( isNATEnabled: true, isDynamicRoutingEnabled: false, - entries: [], + entries: const [], ); // Act diff --git a/test/page/advanced_settings/static_routing/services/static_routing_service_test.dart b/test/page/advanced_settings/static_routing/services/static_routing_service_test.dart index baddc6422..5d484d787 100644 --- a/test/page/advanced_settings/static_routing/services/static_routing_service_test.dart +++ b/test/page/advanced_settings/static_routing/services/static_routing_service_test.dart @@ -5,7 +5,6 @@ import 'package:privacy_gui/core/jnap/result/jnap_result.dart'; import 'package:privacy_gui/core/jnap/router_repository.dart'; import 'package:privacy_gui/page/advanced_settings/static_routing/models/static_route_entry_ui_model.dart'; import 'package:privacy_gui/page/advanced_settings/static_routing/services/static_routing_service.dart'; -import 'package:privacy_gui/page/advanced_settings/static_routing/providers/static_routing_state.dart'; import '../../../../mocks/test_data/static_routing_test_data.dart'; class MockRouterRepository extends Mock implements RouterRepository {} diff --git a/test/page/components/localizations/snack_bar_test.dart b/test/page/components/localizations/snack_bar_test.dart index dc3d59892..a311eb785 100644 --- a/test/page/components/localizations/snack_bar_test.dart +++ b/test/page/components/localizations/snack_bar_test.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:privacy_gui/route/route_model.dart'; import 'package:ui_kit_library/ui_kit.dart'; @@ -108,7 +107,7 @@ void main() { 'Failed: Unknown error: _ErrorUnexpected', ]; - final startIndex = 6; // Success buttons (0-5) take up first 6 slots + const startIndex = 6; // Success buttons (0-5) take up first 6 slots for (var i = 0; i < failedButtons.length; i++) { final label = failedButtons[i]; diff --git a/test/page/dashboard/views/components/loading_tile_test.dart b/test/page/dashboard/views/components/loading_tile_test.dart index ca9a47078..4b9df57b0 100644 --- a/test/page/dashboard/views/components/loading_tile_test.dart +++ b/test/page/dashboard/views/components/loading_tile_test.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:privacy_gui/page/dashboard/views/components/loading_tile.dart'; import 'package:ui_kit_library/ui_kit.dart'; -import 'package:mockito/mockito.dart'; void main() { // Use a simple test wrapper that provides the AppDesignTheme diff --git a/test/page/health_check/providers/health_check_provider_test.dart b/test/page/health_check/providers/health_check_provider_test.dart index d8ac8529e..ef2b23098 100644 --- a/test/page/health_check/providers/health_check_provider_test.dart +++ b/test/page/health_check/providers/health_check_provider_test.dart @@ -252,7 +252,7 @@ void main() { expect(state.result, partialResult); expect(state.step, HealthCheckStep.uploadBandwidth); // Meter value should have changed from 0.0 (initial) to a predictable non-zero value - final expectedRandomValue = (0.5 * (15 - (-3)) + (-3)) * 1024; + const expectedRandomValue = (0.5 * (15 - (-3)) + (-3)) * 1024; expect(state.meterValue, expectedRandomValue); }); diff --git a/test/page/instant_admin/providers/manual_firmware_update_provider_test.dart b/test/page/instant_admin/providers/manual_firmware_update_provider_test.dart index 8582b209b..a008a2b98 100644 --- a/test/page/instant_admin/providers/manual_firmware_update_provider_test.dart +++ b/test/page/instant_admin/providers/manual_firmware_update_provider_test.dart @@ -49,7 +49,7 @@ void main() { test('setFile updates the state with file info', () { final notifier = container.read(manualFirmwareUpdateProvider.notifier); - final fileName = 'test.img'; + const fileName = 'test.img'; final fileBytes = Uint8List.fromList([1, 2, 3]); notifier.setFile(fileName, fileBytes); @@ -93,7 +93,7 @@ void main() { test('manualFirmwareUpdate handles null localPassword', () async { final notifier = container.read(manualFirmwareUpdateProvider.notifier); - final fileName = 'firmware.img'; + const fileName = 'firmware.img'; final bytes = Uint8List.fromList([1, 2, 3]); notifier.setFile(fileName, bytes); @@ -115,7 +115,7 @@ void main() { test('manualFirmwareUpdate calls pollingProvider.notifier.stopPolling', () async { final notifier = container.read(manualFirmwareUpdateProvider.notifier); - final fileName = 'firmware.img'; + const fileName = 'firmware.img'; final bytes = Uint8List.fromList([1, 2, 3]); notifier.setFile(fileName, bytes); @@ -131,7 +131,7 @@ void main() { test('manualFirmwareUpdate sets status to installing on service success', () async { final notifier = container.read(manualFirmwareUpdateProvider.notifier); - final fileName = 'firmware.img'; + const fileName = 'firmware.img'; final bytes = Uint8List.fromList([1, 2, 3]); notifier.setFile(fileName, bytes); @@ -149,7 +149,7 @@ void main() { test('manualFirmwareUpdate sets status to null on service failure', () async { final notifier = container.read(manualFirmwareUpdateProvider.notifier); - final fileName = 'firmware.img'; + const fileName = 'firmware.img'; final bytes = Uint8List.fromList([1, 2, 3]); notifier.setFile(fileName, bytes); diff --git a/test/page/instant_admin/providers/timezone_state_test.dart b/test/page/instant_admin/providers/timezone_state_test.dart index 3dd86e5bb..d449cdcb0 100644 --- a/test/page/instant_admin/providers/timezone_state_test.dart +++ b/test/page/instant_admin/providers/timezone_state_test.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; import 'package:privacy_gui/core/jnap/models/timezone.dart'; diff --git a/test/page/instant_admin/services/router_password_service_test.dart b/test/page/instant_admin/services/router_password_service_test.dart index 9e7df356d..f1cc13935 100644 --- a/test/page/instant_admin/services/router_password_service_test.dart +++ b/test/page/instant_admin/services/router_password_service_test.dart @@ -4,7 +4,6 @@ import 'package:mocktail/mocktail.dart'; import 'package:privacy_gui/constants/_constants.dart'; import 'package:privacy_gui/core/jnap/actions/better_action.dart'; import 'package:privacy_gui/core/jnap/actions/jnap_transaction.dart'; -import 'package:privacy_gui/core/jnap/result/jnap_result.dart'; import 'package:privacy_gui/core/errors/service_error.dart'; import 'package:privacy_gui/core/jnap/router_repository.dart'; import 'package:privacy_gui/page/instant_admin/services/router_password_service.dart'; diff --git a/test/page/instant_admin/services/timezone_service_test.dart b/test/page/instant_admin/services/timezone_service_test.dart index e429b6010..c31437e6c 100644 --- a/test/page/instant_admin/services/timezone_service_test.dart +++ b/test/page/instant_admin/services/timezone_service_test.dart @@ -121,7 +121,7 @@ void main() { .thenAnswer( (_) async => InstantAdminTestData.createSetTimeSettingsSuccess()); - final settings = const TimezoneSettings( + const settings = TimezoneSettings( timezoneId: 'PST8', isDaylightSaving: true, ); @@ -162,7 +162,7 @@ void main() { (_) async => InstantAdminTestData.createSetTimeSettingsSuccess()); // Timezone that does NOT observe DST - final settings = const TimezoneSettings( + const settings = TimezoneSettings( timezoneId: 'JST-9', isDaylightSaving: true, // User selected DST, but timezone doesn't support it @@ -201,7 +201,7 @@ void main() { auth: true, )).thenThrow(InstantAdminTestData.createGenericError()); - final settings = const TimezoneSettings( + const settings = TimezoneSettings( timezoneId: 'PST8', isDaylightSaving: true, ); diff --git a/test/page/instant_privacy/providers/instant_privacy_state_test.dart b/test/page/instant_privacy/providers/instant_privacy_state_test.dart index 97ac81dd4..2d0ce47b9 100644 --- a/test/page/instant_privacy/providers/instant_privacy_state_test.dart +++ b/test/page/instant_privacy/providers/instant_privacy_state_test.dart @@ -62,7 +62,7 @@ void main() { }); test('copyWith creates new instance with updated mode', () { - final original = const InstantPrivacyStatus(mode: MacFilterMode.disabled); + const original = InstantPrivacyStatus(mode: MacFilterMode.disabled); final copied = original.copyWith(mode: MacFilterMode.allow); expect(copied.mode, MacFilterMode.allow); @@ -70,7 +70,7 @@ void main() { }); test('copyWith retains original value when not specified', () { - final original = const InstantPrivacyStatus(mode: MacFilterMode.allow); + const original = InstantPrivacyStatus(mode: MacFilterMode.allow); final copied = original.copyWith(); expect(copied.mode, MacFilterMode.allow); diff --git a/test/page/instant_safety/services/instant_safety_service_test.dart b/test/page/instant_safety/services/instant_safety_service_test.dart index 3dad4d43f..6883802a6 100644 --- a/test/page/instant_safety/services/instant_safety_service_test.dart +++ b/test/page/instant_safety/services/instant_safety_service_test.dart @@ -169,7 +169,7 @@ void main() { auth: any(named: 'auth'), cacheLevel: any(named: 'cacheLevel'), data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'OK', output: {})); + )).thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const {})); // Fetch first to cache settings await service.fetchSettings(deviceInfo: null, forceRemote: false); @@ -205,7 +205,7 @@ void main() { auth: any(named: 'auth'), cacheLevel: any(named: 'cacheLevel'), data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'OK', output: {})); + )).thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const {})); await service.fetchSettings(deviceInfo: null, forceRemote: false); @@ -241,7 +241,7 @@ void main() { auth: any(named: 'auth'), cacheLevel: any(named: 'cacheLevel'), data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'OK', output: {})); + )).thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const {})); await service.fetchSettings(deviceInfo: null, forceRemote: false); diff --git a/test/page/instant_setup/pnp_step_state_test.dart b/test/page/instant_setup/pnp_step_state_test.dart index ebd53214f..845cbab41 100644 --- a/test/page/instant_setup/pnp_step_state_test.dart +++ b/test/page/instant_setup/pnp_step_state_test.dart @@ -92,7 +92,7 @@ void main() { final newStepState = PnpStepState( status: StepViewStatus.error, - data: {'ssid': 'NewWiFi', 'password': 'newpassword'}, + data: const {'ssid': 'NewWiFi', 'password': 'newpassword'}, error: Exception('New error'), ); pnpNotifier.setStepState(stepId, newStepState); diff --git a/test/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider_test.dart b/test/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider_test.dart index d712727d3..66181d371 100644 --- a/test/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider_test.dart +++ b/test/page/instant_setup/troubleshooter/providers/pnp_isp_settings_provider_test.dart @@ -1,7 +1,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; -import 'package:privacy_gui/page/advanced_settings/internet_settings/models/internet_settings_enums.dart'; import 'package:privacy_gui/page/advanced_settings/internet_settings/providers/_providers.dart'; import 'package:privacy_gui/page/instant_setup/services/pnp_service.dart'; import 'package:privacy_gui/page/instant_setup/troubleshooter/providers/_providers.dart'; diff --git a/test/page/instant_setup/troubleshooter/services/pnp_isp_service_test.dart b/test/page/instant_setup/troubleshooter/services/pnp_isp_service_test.dart index 92380add2..ec4263b58 100644 --- a/test/page/instant_setup/troubleshooter/services/pnp_isp_service_test.dart +++ b/test/page/instant_setup/troubleshooter/services/pnp_isp_service_test.dart @@ -15,7 +15,7 @@ void main() { late PnpIspService pnpIspService; // Helper for common mock output - Map _baseWanStatusOutput({ + Map baseWanStatusOutput({ String wanStatus = 'Connecting', String ipAddress = '0.0.0.0', bool includeWanConnection = false, @@ -55,7 +55,7 @@ void main() { // ARRANGE final successResult = JNAPSuccess( result: jnapResultOk, - output: _baseWanStatusOutput(wanStatus: 'Connected'), + output: baseWanStatusOutput(wanStatus: 'Connected'), ); when(mockRouterRepository.scheduledCommand( @@ -80,7 +80,7 @@ void main() { // ARRANGE final successResult = JNAPSuccess( result: jnapResultOk, - output: _baseWanStatusOutput( + output: baseWanStatusOutput( wanStatus: 'Connected', // PPPoE also needs to be 'Connected' ipAddress: '123.45.67.89', includeWanConnection: true, @@ -110,7 +110,7 @@ void main() { final nonMatchingResult = JNAPSuccess( result: jnapResultOk, output: - _baseWanStatusOutput(wanStatus: 'Connecting'), // Not 'Connected' + baseWanStatusOutput(wanStatus: 'Connecting'), // Not 'Connected' ); when(mockRouterRepository.scheduledCommand( @@ -145,7 +145,7 @@ void main() { // ARRANGE final nonMatchingResult = JNAPSuccess( result: jnapResultOk, - output: _baseWanStatusOutput( + output: baseWanStatusOutput( wanStatus: 'Connected', // Status is connected, but IP is invalid ipAddress: '0.0.0.0', includeWanConnection: true, diff --git a/test/page/instant_verify/models/instant_verify_ui_models_test.dart b/test/page/instant_verify/models/instant_verify_ui_models_test.dart index 6ab2a0785..daf75e9cf 100644 --- a/test/page/instant_verify/models/instant_verify_ui_models_test.dart +++ b/test/page/instant_verify/models/instant_verify_ui_models_test.dart @@ -204,7 +204,7 @@ void main() { test('fromJnap creates correct model from JNAP GetRadioInfo', () { final jnapModel = GetRadioInfo( isBandSteeringSupported: true, - radios: [ + radios: const [ RouterRadio( radioID: 'RADIO_2.4GHz', physicalRadioID: 'phy0', @@ -266,9 +266,9 @@ void main() { physicalRadioID: 'phy0', bssid: '00:11:22:33:44:55', band: '2.4GHz', - supportedModes: ['802.11bgn'], - supportedChannelsForChannelWidths: [], - supportedSecurityTypes: ['WPA2-Personal'], + supportedModes: const ['802.11bgn'], + supportedChannelsForChannelWidths: const [], + supportedSecurityTypes: const ['WPA2-Personal'], maxRadiusSharedKeyLength: 64, settings: RouterRadioSettings( isEnabled: false, diff --git a/test/page/instant_verify/providers/instant_verify_provider_test.dart b/test/page/instant_verify/providers/instant_verify_provider_test.dart index 816e14c3a..3cfcf5c77 100644 --- a/test/page/instant_verify/providers/instant_verify_provider_test.dart +++ b/test/page/instant_verify/providers/instant_verify_provider_test.dart @@ -213,7 +213,7 @@ void main() { .thenReturn(RadioInfoUIModel.initial()); when(() => mockService.parseGuestRadioSettings(any())) .thenReturn(GuestRadioSettingsUIModel.initial()); - when(() => mockService.stopTraceroute()).thenAnswer((_) async => null); + when(() => mockService.stopTraceroute()).thenAnswer((_) async {}); container = createContainer(); final notifier = container.read(instantVerifyProvider.notifier); diff --git a/test/page/instant_verify/providers/instant_verify_state_test.dart b/test/page/instant_verify/providers/instant_verify_state_test.dart index 0b989ec19..306eefb7a 100644 --- a/test/page/instant_verify/providers/instant_verify_state_test.dart +++ b/test/page/instant_verify/providers/instant_verify_state_test.dart @@ -58,7 +58,7 @@ void main() { ), radioInfo: RadioInfoUIModel( isBandSteeringSupported: true, - radios: [ + radios: const [ RouterRadioUIModel( radioID: 'RADIO_2.4GHz', band: '2.4GHz', @@ -73,7 +73,7 @@ void main() { guestRadioSettings: GuestRadioSettingsUIModel( isGuestNetworkACaptivePortal: false, isGuestNetworkEnabled: true, - radios: [ + radios: const [ GuestRadioUIModel( radioID: 'RADIO_2.4GHz', isEnabled: true, diff --git a/test/page/wifi_settings/providers/wifi_advanced_state_test.dart b/test/page/wifi_settings/providers/wifi_advanced_state_test.dart index 05c8786f2..79a9f99eb 100644 --- a/test/page/wifi_settings/providers/wifi_advanced_state_test.dart +++ b/test/page/wifi_settings/providers/wifi_advanced_state_test.dart @@ -68,7 +68,7 @@ void main() { }); test('fromMap handles null values', () { - final state = WifiAdvancedSettingsState.fromMap({}); + final state = WifiAdvancedSettingsState.fromMap(const {}); expect(state.isIptvEnabled, isNull); expect(state.isMLOEnabled, isNull); }); diff --git a/test/page/wifi_settings/providers/wifi_state_test.dart b/test/page/wifi_settings/providers/wifi_state_test.dart index fcbad73cd..9d5ec80e4 100644 --- a/test/page/wifi_settings/providers/wifi_state_test.dart +++ b/test/page/wifi_settings/providers/wifi_state_test.dart @@ -67,12 +67,12 @@ void main() { test('equality comparison works', () { final s1 = WiFiListSettings( - mainWiFi: [], + mainWiFi: const [], guestWiFi: createGuestItem(), simpleModeWifi: createWifiItem(), ); final s2 = WiFiListSettings( - mainWiFi: [], + mainWiFi: const [], guestWiFi: createGuestItem(), simpleModeWifi: createWifiItem(), ); diff --git a/test/page/wifi_settings/services/channel_finder_service_test.dart b/test/page/wifi_settings/services/channel_finder_service_test.dart index ff7d41c90..4c549a00e 100644 --- a/test/page/wifi_settings/services/channel_finder_service_test.dart +++ b/test/page/wifi_settings/services/channel_finder_service_test.dart @@ -1,10 +1,8 @@ -import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:privacy_gui/core/jnap/actions/better_action.dart'; import 'package:privacy_gui/core/jnap/result/jnap_result.dart'; import 'package:privacy_gui/core/jnap/router_repository.dart'; -import 'package:privacy_gui/page/wifi_settings/providers/channelfinder_info.dart'; import 'package:privacy_gui/page/wifi_settings/services/channel_finder_service.dart'; class MockRouterRepository extends Mock implements RouterRepository {} @@ -26,7 +24,7 @@ void main() { group('getSelectedChannels', () { test('returns empty list when no channels', () async { when(() => mockRepo.send(any(), cacheLevel: any(named: 'cacheLevel'))) - .thenAnswer((_) async => JNAPSuccess(result: 'OK', output: { + .thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const { 'isRunning': false, 'selectedChannels': [], })); @@ -38,7 +36,7 @@ void main() { test('returns selected channels when available', () async { when(() => mockRepo.send(any(), cacheLevel: any(named: 'cacheLevel'))) - .thenAnswer((_) async => JNAPSuccess(result: 'OK', output: { + .thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const { 'isRunning': false, 'selectedChannels': [ { @@ -59,7 +57,7 @@ void main() { test('throws error when already running', () async { when(() => mockRepo.send(any(), cacheLevel: any(named: 'cacheLevel'))) - .thenAnswer((_) async => JNAPSuccess(result: 'OK', output: { + .thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const { 'isRunning': true, })); diff --git a/test/validator_rules/input_validators_test.dart b/test/validator_rules/input_validators_test.dart index 67e7548dc..7241bbbb6 100644 --- a/test/validator_rules/input_validators_test.dart +++ b/test/validator_rules/input_validators_test.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'package:privacy_gui/validator_rules/input_validators.dart'; import 'package:privacy_gui/validator_rules/rules.dart'; import 'package:test/test.dart'; @@ -993,14 +995,14 @@ void main() { }); // Test result tracking - final Map> _testResults = {}; + final Map> testResults = {}; // Helper to track test results - void _trackTestResult(String group, String testName, bool passed, + void trackTestResult(String group, String testName, bool passed, String address, String? expectedType, {String? description}) { - if (!_testResults.containsKey(group)) { - _testResults[group] = { + if (!testResults.containsKey(group)) { + testResults[group] = { 'total': 0, 'passed': 0, 'failed': 0, @@ -1016,24 +1018,24 @@ void main() { if (description != null) 'description': description, }; - _testResults[group]!['total']++; + testResults[group]!['total']++; if (passed) { - _testResults[group]!['passed']++; + testResults[group]!['passed']++; } else { - _testResults[group]!['failed']++; + testResults[group]!['failed']++; } - _testResults[group]!['details'].add(result); + testResults[group]!['details'].add(result); } // Print test summary - void _printTestSummary() { + void printTestSummary() { print('\n\n=== IPv6 Validation Test Summary ===\n'); int totalTests = 0; int totalPassed = 0; int totalFailed = 0; - _testResults.forEach((group, data) { + testResults.forEach((group, data) { print('\n=== $group ==='); print( 'Total: ${data['total']} | Passed: ${data['passed']} | Failed: ${data['failed']}'); @@ -1083,18 +1085,18 @@ void main() { group('IPv6WithReservedRule', () { // Add teardown to print summary after all tests tearDownAll(() { - _printTestSummary(); + printTestSummary(); }); // Helper function to run multiple invalid test cases - void _runInvalidTestCases(List addresses, String description) { + void runInvalidTestCases(List addresses, String description) { for (var address in addresses) { test('should reject $description: $address', () { final rule = IPv6WithReservedRule(); final isValid = rule.validate(address); final testName = 'Reject $description: $address'; final passed = isValid == false; - _trackTestResult('Invalid Address: $description', testName, passed, + trackTestResult('Invalid Address: $description', testName, passed, address, 'Should be rejected as $description', description: description); expect(isValid, isFalse, @@ -1134,7 +1136,7 @@ void main() { final isValid = rule.validate(address); final testName = 'Valid Global Unicast: $address'; final passed = isValid == true; - _trackTestResult('Valid Global Unicast', testName, passed, address, + trackTestResult('Valid Global Unicast', testName, passed, address, 'Valid Global Unicast', description: 'Should be accepted as a valid global unicast IPv6 address'); @@ -1153,7 +1155,7 @@ void main() { '::1', '0:0:0:0:0:0:0:1', ]; - _runInvalidTestCases(testCases, 'loopback'); + runInvalidTestCases(testCases, 'loopback'); }); // Link-local addresses (fe80::/10) @@ -1164,7 +1166,7 @@ void main() { 'fe80:0000:0000:0000:0000:0000:0000:0001', 'febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff', // End of fe80::/10 ]; - _runInvalidTestCases(testCases, 'link-local'); + runInvalidTestCases(testCases, 'link-local'); }); // Unique Local Addresses (fc00::/7) @@ -1175,7 +1177,7 @@ void main() { 'fd12:3456:789a:1::1', 'fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', // End of fd00::/8 ]; - _runInvalidTestCases(testCases, 'ULA'); + runInvalidTestCases(testCases, 'ULA'); }); // Multicast addresses (ff00::/8) @@ -1185,7 +1187,7 @@ void main() { 'ff02::1', 'ff0f:ffff:ffff:ffff:ffff:ffff:ffff:ffff', // End of ff00::/8 ]; - _runInvalidTestCases(testCases, 'multicast'); + runInvalidTestCases(testCases, 'multicast'); }); // Unspecified/undefined addresses (::/128 and 0::/96) @@ -1198,7 +1200,7 @@ void main() { '0::0', '0:0:0:0:0:0:0:0:0', ]; - _runInvalidTestCases(testCases, 'unspecified/undefined'); + runInvalidTestCases(testCases, 'unspecified/undefined'); }); // Unallocated address space (e.g., ffff::/16) @@ -1217,7 +1219,7 @@ void main() { '5f00::', '5fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', ]; - _runInvalidTestCases(testCases, 'unallocated/reserved'); + runInvalidTestCases(testCases, 'unallocated/reserved'); }); // IPv4-mapped and IPv4-compatible addresses @@ -1228,7 +1230,7 @@ void main() { '::ffff:0:192.168.1.1', '::ffff:c0a8:0101', // Same as ::ffff:192.168.1.1 ]; - _runInvalidTestCases(testCases, 'IPv4-mapped/compatible'); + runInvalidTestCases(testCases, 'IPv4-mapped/compatible'); }); // Invalid formats and non-IPv6 addresses @@ -1243,7 +1245,7 @@ void main() { '2001:db8:1:2:3:4:5:6:7', // Too many segments '2001:db8:1:2:3', // Too few segments ]; - _runInvalidTestCases(testCases, 'invalid format'); + runInvalidTestCases(testCases, 'invalid format'); }); }); diff --git a/test_scripts/test_result_parser.dart b/test_scripts/test_result_parser.dart index f2018615c..697687f94 100644 --- a/test_scripts/test_result_parser.dart +++ b/test_scripts/test_result_parser.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'dart:convert'; import 'dart:io'; diff --git a/tools/generate_screenshot_test_cases_report.dart b/tools/generate_screenshot_test_cases_report.dart index 93407c79a..e4549c663 100644 --- a/tools/generate_screenshot_test_cases_report.dart +++ b/tools/generate_screenshot_test_cases_report.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'dart:io'; import 'package:path/path.dart' as p; @@ -210,9 +212,10 @@ Future> _parseTestFile(File file, bool debugMode) async { } if (mainDescription == null) { - if (debugMode) + if (debugMode) { print( ' No main description found for Test ID: $baseId in file ${file.path}, skipping test case.'); + } continue; // Skip if no description found } @@ -238,9 +241,10 @@ Future> _parseTestFile(File file, bool debugMode) async { } if (goldenFiles.isEmpty) { - if (debugMode) + if (debugMode) { print( ' No golden files found for Test ID: $baseId in file ${file.path}, skipping test case.'); + } continue; } diff --git a/tools/remove_unused_strings.dart b/tools/remove_unused_strings.dart index b5e5d4839..249f84bfb 100644 --- a/tools/remove_unused_strings.dart +++ b/tools/remove_unused_strings.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'dart:convert'; import 'dart:io'; import 'package:args/args.dart'; diff --git a/tools/run_screenshot_tests.dart b/tools/run_screenshot_tests.dart index 68aa4272a..92bd55bbe 100644 --- a/tools/run_screenshot_tests.dart +++ b/tools/run_screenshot_tests.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'dart:io'; import 'package:path/path.dart' as p; import 'package:args/args.dart'; // Import the args package From 5fb98fe38a047c18e32486078fc7a19da8668f6f Mon Sep 17 00:00:00 2001 From: Austin Chang Date: Tue, 6 Jan 2026 13:08:12 +0800 Subject: [PATCH 2/5] refactor: Move agent env config and fix lints - Move env.template to assets/agents/env.template - Update dotenv loading paths in main.dart and main_demo.dart - Fix type definition in IdleChecker - Fix lints in tests --- .github/workflows/ci.yml | 2 +- env.template => assets/agents/env.template | 0 lib/main.dart | 2 +- lib/main_demo.dart | 2 +- lib/page/components/layouts/idle_checker.dart | 2 +- pubspec.yaml | 3 +-- test/common/utils.dart | 1 - test/utils_test.dart | 2 ++ test_scripts/combine_results.dart | 2 ++ 9 files changed, 9 insertions(+), 7 deletions(-) rename env.template => assets/agents/env.template (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e688d9d6..bac5006d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,7 +101,7 @@ jobs: run: git config --global url."git@github.com:".insteadOf "https://github.com/" - name: 📋 Setup Environment File - run: cp env.template assets/.env + run: cp assets/agents/env.template assets/agents/.env - name: Install Dependencies run: flutter pub get diff --git a/env.template b/assets/agents/env.template similarity index 100% rename from env.template rename to assets/agents/env.template diff --git a/lib/main.dart b/lib/main.dart index a0da31581..afcda654e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -49,7 +49,7 @@ void main() async { // Load environment variables for FAQ Agent (AWS Bedrock) // Create assets/.env with AWS credentials (copy from gen_ui_client) try { - await dotenv.load(fileName: 'env.template'); + await dotenv.load(fileName: 'assets/agents/.env'); debugPrint('FAQ Agent: .env loaded successfully'); } catch (e) { debugPrint('Warning: Could not load .env file for FAQ Agent: $e'); diff --git a/lib/main_demo.dart b/lib/main_demo.dart index 2883781c5..f5efb49f4 100644 --- a/lib/main_demo.dart +++ b/lib/main_demo.dart @@ -38,7 +38,7 @@ void main() async { // Load environment variables (for AWS credentials) try { - await dotenv.load(fileName: 'env.template'); + await dotenv.load(fileName: 'assets/agents/.env'); } catch (e) { debugPrint('No .env file found, using defaults'); } diff --git a/lib/page/components/layouts/idle_checker.dart b/lib/page/components/layouts/idle_checker.dart index c98da3032..bd27b235d 100644 --- a/lib/page/components/layouts/idle_checker.dart +++ b/lib/page/components/layouts/idle_checker.dart @@ -17,7 +17,7 @@ class IdleChecker extends StatefulWidget { }); @override - _IdleCheckerState createState() => _IdleCheckerState(); + State createState() => _IdleCheckerState(); } class _IdleCheckerState extends State { diff --git a/pubspec.yaml b/pubspec.yaml index 330a04a80..2905c0f47 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -129,8 +129,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - - assets/.env - - env.template + - assets/agents/ - assets/icons/ - assets/resources/ # An image asset can refer to one or more resolution-specific "variants", see diff --git a/test/common/utils.dart b/test/common/utils.dart index 86a808406..77db005e9 100644 --- a/test/common/utils.dart +++ b/test/common/utils.dart @@ -26,7 +26,6 @@ void fireOnTap(Finder finder, String text) { final RenderParagraph paragraph = element.renderObject as RenderParagraph; // The children are the individual TextSpans which have GestureRecognizers paragraph.text.visitChildren((dynamic span) { - print(span); if (span.text != text) return true; // continue iterating. (span.recognizer as TapGestureRecognizer).onTap?.call(); diff --git a/test/utils_test.dart b/test/utils_test.dart index 98a6b6917..86a2a2241 100644 --- a/test/utils_test.dart +++ b/test/utils_test.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'package:privacy_gui/utils.dart'; import 'package:test/test.dart'; import 'package:privacy_gui/core/utils/fernet_manager.dart'; diff --git a/test_scripts/combine_results.dart b/test_scripts/combine_results.dart index 7f8d9a246..614a7fe7a 100644 --- a/test_scripts/combine_results.dart +++ b/test_scripts/combine_results.dart @@ -1,3 +1,5 @@ +// ignore_for_file: avoid_print + import 'dart:convert'; import 'dart:io'; From a956be5672e5688fff004d851993d26c6ff260e0 Mon Sep 17 00:00:00 2001 From: Austin Chang Date: Tue, 6 Jan 2026 13:36:03 +0800 Subject: [PATCH 3/5] fix: Resolve mock signature warnings and fix node detail test - Update Notifier mock signatures in test/mocks/ to correctly extend AsyncNotifier/Notifier and mixin Mock - Fix node_detail_view_test.dart by stubbing missing node light status - Update CI workflow env setup --- .github/workflows/ci.yml | 2 +- test/mocks/auth_notifier_mocks.dart | 4 ++- test/mocks/dashboard_home_notifier_mocks.dart | 3 +- .../dashboard_manager_notifier_mocks.dart | 4 ++- test/mocks/device_manager_notifier_mocks.dart | 3 +- .../internet_settings_notifier_mocks.dart | 4 ++- test/mocks/node_detail_notifier_mocks.dart | 3 +- .../node_light_settings_notifier_mocks.dart | 30 ++++++++++++------- test/mocks/polling_notifier_mocks.dart | 4 ++- .../localizations/node_detail_view_test.dart | 2 ++ 10 files changed, 41 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bac5006d1..255544eae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: run: git config --global url."git@github.com:".insteadOf "https://github.com/" - name: 📋 Setup Environment File - run: cp env.template assets/.env + run: cp assets/agents/env.template assets/agents/.env - name: Install Dependencies run: flutter pub get diff --git a/test/mocks/auth_notifier_mocks.dart b/test/mocks/auth_notifier_mocks.dart index 38c3f1edb..c440bf089 100644 --- a/test/mocks/auth_notifier_mocks.dart +++ b/test/mocks/auth_notifier_mocks.dart @@ -63,7 +63,9 @@ class _FakeAuthState_2 extends _i1.SmartFake implements _i3.AuthState { /// A class which mocks [AuthNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockAuthNotifier extends _i1.Mock implements _i4.AuthNotifier { +class MockAuthNotifier extends _i2.AsyncNotifier<_i3.AuthState> + with _i1.Mock + implements _i4.AuthNotifier { @override _i2.AsyncNotifierProviderRef<_i3.AuthState> get ref => (super.noSuchMethod( Invocation.getter(#ref), diff --git a/test/mocks/dashboard_home_notifier_mocks.dart b/test/mocks/dashboard_home_notifier_mocks.dart index 7eebd7f09..2cb4aded4 100644 --- a/test/mocks/dashboard_home_notifier_mocks.dart +++ b/test/mocks/dashboard_home_notifier_mocks.dart @@ -50,7 +50,8 @@ class _FakeDashboardHomeState_1 extends _i1.SmartFake /// A class which mocks [DashboardHomeNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockDashboardHomeNotifier extends _i1.Mock +class MockDashboardHomeNotifier extends _i2.Notifier<_i3.DashboardHomeState> + with _i1.Mock implements _i4.DashboardHomeNotifier { @override _i2.NotifierProviderRef<_i3.DashboardHomeState> get ref => diff --git a/test/mocks/dashboard_manager_notifier_mocks.dart b/test/mocks/dashboard_manager_notifier_mocks.dart index bbc025fbe..579a191d6 100644 --- a/test/mocks/dashboard_manager_notifier_mocks.dart +++ b/test/mocks/dashboard_manager_notifier_mocks.dart @@ -64,7 +64,9 @@ class _FakeNodeDeviceInfo_2 extends _i1.SmartFake /// A class which mocks [DashboardManagerNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockDashboardManagerNotifier extends _i1.Mock +class MockDashboardManagerNotifier + extends _i2.Notifier<_i3.DashboardManagerState> + with _i1.Mock implements _i5.DashboardManagerNotifier { @override _i2.NotifierProviderRef<_i3.DashboardManagerState> get ref => diff --git a/test/mocks/device_manager_notifier_mocks.dart b/test/mocks/device_manager_notifier_mocks.dart index b4434d77e..8d4c034e5 100644 --- a/test/mocks/device_manager_notifier_mocks.dart +++ b/test/mocks/device_manager_notifier_mocks.dart @@ -54,7 +54,8 @@ class _FakeDeviceManagerState_1 extends _i1.SmartFake /// A class which mocks [DeviceManagerNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockDeviceManagerNotifier extends _i1.Mock +class MockDeviceManagerNotifier extends _i2.Notifier<_i3.DeviceManagerState> + with _i1.Mock implements _i4.DeviceManagerNotifier { @override _i2.NotifierProviderRef<_i3.DeviceManagerState> get ref => diff --git a/test/mocks/internet_settings_notifier_mocks.dart b/test/mocks/internet_settings_notifier_mocks.dart index a7683706c..ddf458a3d 100644 --- a/test/mocks/internet_settings_notifier_mocks.dart +++ b/test/mocks/internet_settings_notifier_mocks.dart @@ -52,7 +52,9 @@ class _FakeInternetSettingsState_1 extends _i1.SmartFake /// A class which mocks [InternetSettingsNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockInternetSettingsNotifier extends _i1.Mock +class MockInternetSettingsNotifier + extends _i2.Notifier<_i3.InternetSettingsState> + with _i1.Mock implements _i4.InternetSettingsNotifier { @override _i2.NotifierProviderRef<_i3.InternetSettingsState> get ref => diff --git a/test/mocks/node_detail_notifier_mocks.dart b/test/mocks/node_detail_notifier_mocks.dart index 33d6d8499..b22ee486e 100644 --- a/test/mocks/node_detail_notifier_mocks.dart +++ b/test/mocks/node_detail_notifier_mocks.dart @@ -51,7 +51,8 @@ class _FakeNodeDetailState_1 extends _i1.SmartFake /// A class which mocks [NodeDetailNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockNodeDetailNotifier extends _i1.Mock +class MockNodeDetailNotifier extends _i2.Notifier<_i3.NodeDetailState> + with _i1.Mock implements _i3.NodeDetailNotifier { @override _i2.NotifierProviderRef<_i3.NodeDetailState> get ref => (super.noSuchMethod( diff --git a/test/mocks/node_light_settings_notifier_mocks.dart b/test/mocks/node_light_settings_notifier_mocks.dart index 3ac226fad..921c74d3c 100644 --- a/test/mocks/node_light_settings_notifier_mocks.dart +++ b/test/mocks/node_light_settings_notifier_mocks.dart @@ -1,15 +1,16 @@ -// Mocks generated by Mockito 5.4.4 from annotations +// Mocks generated by Mockito 5.4.6 from annotations // in privacy_gui/test/mocks/mockito_specs/node_light_settings_notifier_spec.dart. // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i5; +import 'dart:async' as _i6; import 'package:flutter_riverpod/flutter_riverpod.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; import 'package:privacy_gui/core/jnap/models/node_light_settings.dart' as _i3; import 'package:privacy_gui/core/jnap/providers/node_light_settings_provider.dart' as _i4; +import 'package:privacy_gui/page/nodes/providers/node_detail_state.dart' as _i5; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -19,10 +20,12 @@ import 'package:privacy_gui/core/jnap/providers/node_light_settings_provider.dar // ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeNotifierProviderRef_0 extends _i1.SmartFake implements _i2.NotifierProviderRef { @@ -53,6 +56,13 @@ class MockNodeLightSettingsNotifier extends _i2.Notifier<_i3.NodeLightSettings> with _i1.Mock implements _i4.NodeLightSettingsNotifier { @override + _i5.NodeLightStatus get currentStatus => (super.noSuchMethod( + Invocation.getter(#currentStatus), + returnValue: _i5.NodeLightStatus.on, + returnValueForMissingStub: _i5.NodeLightStatus.on, + ) as _i5.NodeLightStatus); + + @override _i2.NotifierProviderRef<_i3.NodeLightSettings> get ref => (super.noSuchMethod( Invocation.getter(#ref), returnValue: _FakeNotifierProviderRef_0<_i3.NodeLightSettings>( @@ -111,14 +121,14 @@ class MockNodeLightSettingsNotifier extends _i2.Notifier<_i3.NodeLightSettings> ) as _i3.NodeLightSettings); @override - _i5.Future<_i3.NodeLightSettings> fetch([bool? forceRemote = false]) => + _i6.Future<_i3.NodeLightSettings> fetch([bool? forceRemote = false]) => (super.noSuchMethod( Invocation.method( #fetch, [forceRemote], ), returnValue: - _i5.Future<_i3.NodeLightSettings>.value(_FakeNodeLightSettings_1( + _i6.Future<_i3.NodeLightSettings>.value(_FakeNodeLightSettings_1( this, Invocation.method( #fetch, @@ -126,23 +136,23 @@ class MockNodeLightSettingsNotifier extends _i2.Notifier<_i3.NodeLightSettings> ), )), returnValueForMissingStub: - _i5.Future<_i3.NodeLightSettings>.value(_FakeNodeLightSettings_1( + _i6.Future<_i3.NodeLightSettings>.value(_FakeNodeLightSettings_1( this, Invocation.method( #fetch, [forceRemote], ), )), - ) as _i5.Future<_i3.NodeLightSettings>); + ) as _i6.Future<_i3.NodeLightSettings>); @override - _i5.Future<_i3.NodeLightSettings> save() => (super.noSuchMethod( + _i6.Future<_i3.NodeLightSettings> save() => (super.noSuchMethod( Invocation.method( #save, [], ), returnValue: - _i5.Future<_i3.NodeLightSettings>.value(_FakeNodeLightSettings_1( + _i6.Future<_i3.NodeLightSettings>.value(_FakeNodeLightSettings_1( this, Invocation.method( #save, @@ -150,14 +160,14 @@ class MockNodeLightSettingsNotifier extends _i2.Notifier<_i3.NodeLightSettings> ), )), returnValueForMissingStub: - _i5.Future<_i3.NodeLightSettings>.value(_FakeNodeLightSettings_1( + _i6.Future<_i3.NodeLightSettings>.value(_FakeNodeLightSettings_1( this, Invocation.method( #save, [], ), )), - ) as _i5.Future<_i3.NodeLightSettings>); + ) as _i6.Future<_i3.NodeLightSettings>); @override void setSettings(_i3.NodeLightSettings? settings) => super.noSuchMethod( diff --git a/test/mocks/polling_notifier_mocks.dart b/test/mocks/polling_notifier_mocks.dart index 4a9ddae04..e1fcb84cf 100644 --- a/test/mocks/polling_notifier_mocks.dart +++ b/test/mocks/polling_notifier_mocks.dart @@ -59,7 +59,9 @@ class _FakeCoreTransactionData_2 extends _i1.SmartFake /// A class which mocks [PollingNotifier]. /// /// See the documentation for Mockito's code generation for more information. -class MockPollingNotifier extends _i1.Mock implements _i3.PollingNotifier { +class MockPollingNotifier extends _i2.AsyncNotifier<_i3.CoreTransactionData> + with _i1.Mock + implements _i3.PollingNotifier { @override bool get paused => (super.noSuchMethod( Invocation.getter(#paused), diff --git a/test/page/nodes/localizations/node_detail_view_test.dart b/test/page/nodes/localizations/node_detail_view_test.dart index 7a154a582..6df7e2c50 100644 --- a/test/page/nodes/localizations/node_detail_view_test.dart +++ b/test/page/nodes/localizations/node_detail_view_test.dart @@ -212,6 +212,8 @@ void main() { allDayOff: false, ), ); + when(testHelper.mockNodeLightSettingsNotifier.currentStatus) + .thenReturn(NodeLightStatus.night); final context = await pumpNodeDetailView(tester, screen); final loc = testHelper.loc(context); From 818b963b18cf447e2b35fbe96f8892be89a33cc5 Mon Sep 17 00:00:00 2001 From: Austin Chang Date: Tue, 6 Jan 2026 13:39:42 +0800 Subject: [PATCH 4/5] style: Format code with dart format --- .../firmware_update_service_test.dart | 4 +-- .../services/dmz_settings_service_test.dart | 28 +++++++++------- .../ipv6_port_service_list_service_test.dart | 3 +- .../dhcp_reservations_provider_test.dart | 4 +-- .../providers/timezone_state_test.dart | 1 - .../services/instant_safety_service_test.dart | 33 ++++++++++--------- .../services/pnp_isp_service_test.dart | 3 +- .../providers/wifi_advanced_state_test.dart | 3 +- 8 files changed, 42 insertions(+), 37 deletions(-) diff --git a/test/core/jnap/services/firmware_update_service_test.dart b/test/core/jnap/services/firmware_update_service_test.dart index 0e94a6c75..4f3983529 100644 --- a/test/core/jnap/services/firmware_update_service_test.dart +++ b/test/core/jnap/services/firmware_update_service_test.dart @@ -838,8 +838,8 @@ void main() { onCompleted: anyNamed('onCompleted'), requestTimeoutOverride: anyNamed('requestTimeoutOverride'), auth: anyNamed('auth'))) - .thenAnswer((_) => Stream.value( - JNAPSuccess(result: 'OK', output: const {'firmwareUpdateStatus': []}))); + .thenAnswer((_) => Stream.value(JNAPSuccess( + result: 'OK', output: const {'firmwareUpdateStatus': []}))); final resultStream = service.fetchFirmwareUpdateStream( force: true, retry: 2, currentNodesStatus: nodesStatus); diff --git a/test/page/advanced_settings/dmz/services/dmz_settings_service_test.dart b/test/page/advanced_settings/dmz/services/dmz_settings_service_test.dart index 29fe8a362..65bc80f7d 100644 --- a/test/page/advanced_settings/dmz/services/dmz_settings_service_test.dart +++ b/test/page/advanced_settings/dmz/services/dmz_settings_service_test.dart @@ -208,12 +208,14 @@ void main() { ); when(() => mockRepository.send( - any(), - fetchRemote: any(named: 'fetchRemote'), - cacheLevel: any(named: 'cacheLevel'), - auth: any(named: 'auth'), - data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'ok', output: const {})); + any(), + fetchRemote: any(named: 'fetchRemote'), + cacheLevel: any(named: 'cacheLevel'), + auth: any(named: 'auth'), + data: any(named: 'data'), + )) + .thenAnswer( + (_) async => JNAPSuccess(result: 'ok', output: const {})); final mockRef = UnitTestHelper.createMockRef( routerRepository: mockRepository, @@ -275,12 +277,14 @@ void main() { ); when(() => mockRepository.send( - any(), - fetchRemote: any(named: 'fetchRemote'), - cacheLevel: any(named: 'cacheLevel'), - auth: any(named: 'auth'), - data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'ok', output: const {})); + any(), + fetchRemote: any(named: 'fetchRemote'), + cacheLevel: any(named: 'cacheLevel'), + auth: any(named: 'auth'), + data: any(named: 'data'), + )) + .thenAnswer( + (_) async => JNAPSuccess(result: 'ok', output: const {})); final mockRef = UnitTestHelper.createMockRef( routerRepository: mockRepository, diff --git a/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test.dart b/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test.dart index 40a441ab6..6465fcc68 100644 --- a/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test.dart +++ b/test/page/advanced_settings/firewall/services/ipv6_port_service_list_service_test.dart @@ -118,8 +118,7 @@ void main() { description: 'Both Rule', ipv6Address: '2001:db8::3', portRanges: const [ - PortRange( - protocol: 'Both', firstPort: 5000, lastPort: 6000), + PortRange(protocol: 'Both', firstPort: 5000, lastPort: 6000), ], ), ]; diff --git a/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_provider_test.dart b/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_provider_test.dart index 050170077..3ca4bf5ba 100644 --- a/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_provider_test.dart +++ b/test/page/advanced_settings/local_network_settings/providers/dhcp_reservations_provider_test.dart @@ -310,8 +310,8 @@ void main() { description: 'Device2', ), ); - notifier - .updateSettings(DHCPReservationsSettings(reservations: const [newItem])); + notifier.updateSettings( + DHCPReservationsSettings(reservations: const [newItem])); final state = container.read(dhcpReservationProvider); expect(state.settings.current.reservations, hasLength(1)); diff --git a/test/page/instant_admin/providers/timezone_state_test.dart b/test/page/instant_admin/providers/timezone_state_test.dart index d449cdcb0..44ae26564 100644 --- a/test/page/instant_admin/providers/timezone_state_test.dart +++ b/test/page/instant_admin/providers/timezone_state_test.dart @@ -1,4 +1,3 @@ - import 'package:flutter_test/flutter_test.dart'; import 'package:privacy_gui/core/jnap/models/timezone.dart'; import 'package:privacy_gui/page/instant_admin/providers/timezone_state.dart'; diff --git a/test/page/instant_safety/services/instant_safety_service_test.dart b/test/page/instant_safety/services/instant_safety_service_test.dart index 6883802a6..0a7fc28cf 100644 --- a/test/page/instant_safety/services/instant_safety_service_test.dart +++ b/test/page/instant_safety/services/instant_safety_service_test.dart @@ -165,11 +165,12 @@ void main() { ); when(() => mockRouterRepository.send( - JNAPAction.setLANSettings, - auth: any(named: 'auth'), - cacheLevel: any(named: 'cacheLevel'), - data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const {})); + JNAPAction.setLANSettings, + auth: any(named: 'auth'), + cacheLevel: any(named: 'cacheLevel'), + data: any(named: 'data'), + )) + .thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const {})); // Fetch first to cache settings await service.fetchSettings(deviceInfo: null, forceRemote: false); @@ -201,11 +202,12 @@ void main() { ); when(() => mockRouterRepository.send( - JNAPAction.setLANSettings, - auth: any(named: 'auth'), - cacheLevel: any(named: 'cacheLevel'), - data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const {})); + JNAPAction.setLANSettings, + auth: any(named: 'auth'), + cacheLevel: any(named: 'cacheLevel'), + data: any(named: 'data'), + )) + .thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const {})); await service.fetchSettings(deviceInfo: null, forceRemote: false); @@ -237,11 +239,12 @@ void main() { ); when(() => mockRouterRepository.send( - JNAPAction.setLANSettings, - auth: any(named: 'auth'), - cacheLevel: any(named: 'cacheLevel'), - data: any(named: 'data'), - )).thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const {})); + JNAPAction.setLANSettings, + auth: any(named: 'auth'), + cacheLevel: any(named: 'cacheLevel'), + data: any(named: 'data'), + )) + .thenAnswer((_) async => JNAPSuccess(result: 'OK', output: const {})); await service.fetchSettings(deviceInfo: null, forceRemote: false); diff --git a/test/page/instant_setup/troubleshooter/services/pnp_isp_service_test.dart b/test/page/instant_setup/troubleshooter/services/pnp_isp_service_test.dart index ec4263b58..6da968e41 100644 --- a/test/page/instant_setup/troubleshooter/services/pnp_isp_service_test.dart +++ b/test/page/instant_setup/troubleshooter/services/pnp_isp_service_test.dart @@ -109,8 +109,7 @@ void main() { // ARRANGE final nonMatchingResult = JNAPSuccess( result: jnapResultOk, - output: - baseWanStatusOutput(wanStatus: 'Connecting'), // Not 'Connected' + output: baseWanStatusOutput(wanStatus: 'Connecting'), // Not 'Connected' ); when(mockRouterRepository.scheduledCommand( diff --git a/test/page/wifi_settings/providers/wifi_advanced_state_test.dart b/test/page/wifi_settings/providers/wifi_advanced_state_test.dart index 79a9f99eb..48e83d73a 100644 --- a/test/page/wifi_settings/providers/wifi_advanced_state_test.dart +++ b/test/page/wifi_settings/providers/wifi_advanced_state_test.dart @@ -68,7 +68,8 @@ void main() { }); test('fromMap handles null values', () { - final state = WifiAdvancedSettingsState.fromMap(const {}); + final state = + WifiAdvancedSettingsState.fromMap(const {}); expect(state.isIptvEnabled, isNull); expect(state.isMLOEnabled, isNull); }); From 4b2f5886f729e4732d971c4d7d0614154fa69b25 Mon Sep 17 00:00:00 2001 From: Austin Chang Date: Tue, 6 Jan 2026 14:16:44 +0800 Subject: [PATCH 5/5] chore: Restore polling_provider and cleanup obsolete mocks --- lib/core/jnap/providers/polling_provider.dart | 211 ++++++++++++++++++ test/mocks/dashboard_home_notifier_mocks.dart | 4 - 2 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 lib/core/jnap/providers/polling_provider.dart diff --git a/lib/core/jnap/providers/polling_provider.dart b/lib/core/jnap/providers/polling_provider.dart new file mode 100644 index 000000000..37adc4f08 --- /dev/null +++ b/lib/core/jnap/providers/polling_provider.dart @@ -0,0 +1,211 @@ +import 'dart:async'; +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:privacy_gui/constants/build_config.dart'; +import 'package:privacy_gui/core/cache/linksys_cache_manager.dart'; +import 'package:privacy_gui/core/data/services/polling_service.dart'; +import 'package:privacy_gui/core/jnap/actions/better_action.dart'; +import 'package:privacy_gui/core/jnap/actions/jnap_service_supported.dart'; +import 'package:privacy_gui/core/jnap/result/jnap_result.dart'; +import 'package:privacy_gui/core/utils/bench_mark.dart'; +import 'package:privacy_gui/core/utils/logger.dart'; +import 'package:privacy_gui/page/health_check/providers/health_check_provider.dart'; +import 'package:privacy_gui/page/nodes/providers/node_light_settings_provider.dart'; +import 'package:privacy_gui/page/vpn/providers/vpn_notifier.dart'; +import 'package:privacy_gui/providers/auth/_auth.dart'; +import 'package:privacy_gui/page/instant_privacy/providers/instant_privacy_provider.dart'; + +const int pollFirstDelayInSec = 1; + +final pollingProvider = + AsyncNotifierProvider( + () => PollingNotifier()); + +class CoreTransactionData extends Equatable { + final int lastUpdate; + final bool isReady; + final Map data; + + const CoreTransactionData({ + required this.lastUpdate, + required this.isReady, + required this.data, + }); + + @override + List get props => [lastUpdate, isReady, data]; + + CoreTransactionData copyWith({ + int? lastUpdate, + bool? isReady, + Map? data, + }) { + return CoreTransactionData( + lastUpdate: lastUpdate ?? this.lastUpdate, + isReady: isReady ?? this.isReady, + data: data ?? this.data, + ); + } +} + +class PollingNotifier extends AsyncNotifier { + static Timer? _timer; + bool _paused = false; + + /// Service for polling operations + PollingService get _service => ref.read(pollingServiceProvider); + + set paused(bool value) { + _paused = value; + if (_paused) { + _timer?.cancel(); + } else { + checkAndStartPolling(); + } + } + + bool get paused => _paused; + + List>> _coreTransactions = []; + + @override + FutureOr build() { + return const CoreTransactionData(lastUpdate: 0, isReady: false, data: {}); + } + + init() { + state = AsyncValue.data( + const CoreTransactionData(lastUpdate: 0, isReady: false, data: {})); + } + + fetchFirstLaunchedCacheData() { + final cache = ref.read(linksysCacheManagerProvider).data; + + // Delegate cache parsing to Service + final cacheDataMap = _service.parseCacheData( + cache: cache, + commands: _coreTransactions, + ); + + // Cache incomplete - skip + if (cacheDataMap == null) return; + + // Delegate Fernet key update to Service + _service.updateFernetKeyFromResult(cacheDataMap); + + final previousSnapshot = state.value; + state = AsyncValue.data(CoreTransactionData( + lastUpdate: 0, + isReady: previousSnapshot?.isReady ?? false, + data: cacheDataMap)); + } + + Future _polling({bool force = false}) async { + final benchMark = BenchMarkLogger(name: 'Polling provider'); + benchMark.start(); + final previousSnapshot = state.value; + state = const AsyncValue.loading(); + final fetchFuture = _service + .executeTransaction(_coreTransactions, force: force) + .then((successWrap) => successWrap.data) + .then((data) => CoreTransactionData( + lastUpdate: DateTime.now().millisecondsSinceEpoch, + isReady: previousSnapshot?.isReady ?? false, + data: Map.fromEntries(data), + )) + .onError((error, stackTrace) { + logger.e('Polling error: $error, $stackTrace'); + logger.f('[Auth]: Force to log out because of failed polling'); + ref.read(authProvider.notifier).logout(); + + throw error ?? ''; + }); + + state = await AsyncValue.guard( + () => fetchFuture.then( + (result) async { + // Delegate Fernet key update to Service + _service.updateFernetKeyFromResult(result.data); + + await _additionalPolling(); + return result.copyWith(isReady: true); + }, + ).onError((e, stackTrace) { + logger.e('Polling error: $e, $stackTrace'); + throw e ?? ''; + }), + ); + + benchMark.end(); + } + + Future _additionalPolling() async { + if (serviceHelper.isSupportLedMode()) { + await ref.read(nodeLightSettingsProvider.notifier).fetch(); + } + if (serviceHelper.isSupportVPN()) { + await ref.read(vpnProvider.notifier).fetch(false, true); + } + + if (serviceHelper.isSupportHealthCheck()) { + await ref.read(healthCheckProvider.notifier).loadData(); + } + + await ref + .read(instantPrivacyProvider.notifier) + .fetch(updateStatusOnly: true); + } + + Future forcePolling() { + return _polling(force: true).then((_) => _setTimePeriod()); + } + + void checkAndStartPolling([bool force = false]) { + final loginType = ref.read(authProvider).value?.loginType; + if (loginType == LoginType.none) { + return; + } + if (!force && (_timer?.isActive ?? false)) { + return; + } else { + _paused = false; + stopPolling(); + startPolling(); + } + } + + startPolling() { + if (_paused) { + return; + } + logger.d('prepare start polling data'); + _service.checkDeviceMode().then((mode) { + _coreTransactions = _service.buildCoreTransactions(mode: mode); + fetchFirstLaunchedCacheData(); + }).then( + (value) => + Future.delayed(const Duration(seconds: pollFirstDelayInSec), () { + _polling(); + }).then( + (_) { + _setTimePeriod(); + }, + ), + ); + } + + stopPolling() { + logger.d('stop polling data'); + if ((_timer?.isActive ?? false)) { + _timer?.cancel(); + } + } + + _setTimePeriod() { + _timer?.cancel(); + _timer = Timer.periodic( + const Duration(seconds: BuildConfig.refreshTimeInterval), (timer) { + _polling(); + }); + } +} diff --git a/test/mocks/dashboard_home_notifier_mocks.dart b/test/mocks/dashboard_home_notifier_mocks.dart index af2862d25..2cb4aded4 100644 --- a/test/mocks/dashboard_home_notifier_mocks.dart +++ b/test/mocks/dashboard_home_notifier_mocks.dart @@ -5,10 +5,6 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'package:flutter_riverpod/flutter_riverpod.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; -import 'package:privacy_gui/core/data/providers/dashboard_manager_state.dart' - as _i5; -import 'package:privacy_gui/core/data/providers/device_manager_state.dart' - as _i6; import 'package:privacy_gui/page/dashboard/providers/dashboard_home_provider.dart' as _i4; import 'package:privacy_gui/page/dashboard/providers/dashboard_home_state.dart'