Files
RouterOS/RouterOSAssistantTests/SavedRoutersStoreTests.swift
T
KayandClaude Sonnet 5 31607b7270 M17-M19: Bekannte Router, Live-Traffic-Anzeige, Übersicht-Animation+Drag
M17: "Bekannte Router" im Verbinden-Tab (SavedRouter/SavedRoutersStore),
Standort-Freitextfeld, Scroll-Cap ab 4 Einträgen. Bugfix: Umbenennen-
TextField steckte in einem sich selbst deaktivierenden Button.

M18: Live-Traffic-Punkt an Interfaces (InterfaceTrafficMonitor, eigene
SSH-Verbindung, monitor-traffic-Polling). Dabei zwei reale CLI-Parser-Bugs
gefunden und gefixt: running/disabled-Flags werden als Buchstaben vor dem
ersten Feld codiert, nicht als key=value; monitor-traffic liefert
"50.7kbps" statt einer reinen Zahl.

M19: Übersicht-Tab — animierte Flussrichtung auf allen Verbindungslinien
(TimelineView+dashPhase), frei verschiebbare Knoten mit Live-folgenden
Linien, Zurücksetzen-Button.

Zusätzlich (noch nicht live getestet, nur Build+Unit-Tests grün):
LAN-Port-Konflikt-Prüfung im Einrichten-Assistenten mit doppelter
Sicherheitsbestätigung, "Fertig"-Button nach erfolgreichem Anwenden.

82 Tests grün. HANDOFF.md/README.md/Manual.md/CHATLOG.md aktualisiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
2026-09-15 21:40:46 +02:00

98 lines
4.3 KiB
Swift

import XCTest
@testable import RouterOSAssistant
final class SavedRoutersStoreTests: XCTestCase {
/// A dedicated suite name per test avoids bleeding state between tests / real app defaults.
private func makeStore() -> SavedRoutersStore {
let suiteName = "SavedRoutersStoreTests.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suiteName)!
return SavedRoutersStore(defaults: defaults)
}
func testFirstSuccessfulConnectionAddsEntryWithDefaultName() {
let store = makeStore()
let routers = store.recordSuccessfulConnection(host: "192.168.88.1", username: "admin", defaultName: "hEX")
XCTAssertEqual(routers.count, 1)
XCTAssertEqual(routers[0].host, "192.168.88.1")
XCTAssertEqual(routers[0].username, "admin")
XCTAssertEqual(routers[0].name, "hEX")
XCTAssertEqual(routers[0].location, "")
}
func testUpdateLocationRoundTrip() {
let store = makeStore()
store.recordSuccessfulConnection(host: "192.168.88.1", username: "admin", defaultName: "hEX")
let id = store.load()[0].id
let updated = store.updateLocation(id, to: "Keller, Serverschrank")
XCTAssertEqual(updated.first?.location, "Keller, Serverschrank")
// Renaming afterwards must not clobber the location, and vice versa.
let renamed = store.rename(id, to: "Hauptrouter")
XCTAssertEqual(renamed.first?.name, "Hauptrouter")
XCTAssertEqual(renamed.first?.location, "Keller, Serverschrank")
}
/// A list saved by an earlier app version (before `location` existed) must keep loading
/// instead of the whole list silently vanishing — see `SavedRouter.init(from:)`.
func testDecodingAnEntryWithoutALocationFieldDefaultsToEmpty() {
let suiteName = "SavedRoutersStoreTests.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suiteName)!
let legacyJSON = """
[{"id":"\(UUID().uuidString)","host":"192.168.88.1","username":"admin","name":"hEX","lastConnectedAt":0}]
"""
defaults.set(Data(legacyJSON.utf8), forKey: "RouterOSAssistant.SavedRouters")
let store = SavedRoutersStore(defaults: defaults)
let routers = store.load()
XCTAssertEqual(routers.count, 1)
XCTAssertEqual(routers[0].name, "hEX")
XCTAssertEqual(routers[0].location, "")
}
func testReconnectingToKnownRouterUpdatesRecencyNotName() {
let store = makeStore()
store.recordSuccessfulConnection(host: "192.168.88.1", username: "admin", defaultName: "hEX")
store.rename(store.load()[0].id, to: "Büro-Router")
// A later connection reports a possibly-different board name (e.g. after a hardware
// swap behind the same IP) — the user's own rename must survive regardless.
let routers = store.recordSuccessfulConnection(host: "192.168.88.1", username: "admin", defaultName: "RB750Gr3")
XCTAssertEqual(routers.count, 1)
XCTAssertEqual(routers[0].name, "Büro-Router")
}
func testDifferentUsernameOnSameHostIsATwoEntries() {
let store = makeStore()
store.recordSuccessfulConnection(host: "192.168.88.1", username: "admin", defaultName: "hEX")
let routers = store.recordSuccessfulConnection(host: "192.168.88.1", username: "gast", defaultName: "hEX")
XCTAssertEqual(routers.count, 2)
}
func testRenameAndRemoveRoundTrip() {
let store = makeStore()
store.recordSuccessfulConnection(host: "192.168.88.1", username: "admin", defaultName: "hEX")
let id = store.load()[0].id
let renamed = store.rename(id, to: "Wohnzimmer")
XCTAssertEqual(renamed.first?.name, "Wohnzimmer")
let removed = store.remove(id)
XCTAssertTrue(removed.isEmpty)
XCTAssertTrue(store.load().isEmpty)
}
func testLoadOrdersMostRecentlyConnectedFirst() {
let store = makeStore()
store.recordSuccessfulConnection(host: "10.0.0.1", username: "admin", defaultName: "Router A")
store.recordSuccessfulConnection(host: "10.0.0.2", username: "admin", defaultName: "Router B")
// Reconnecting to the first one should move it back to the front.
let routers = store.recordSuccessfulConnection(host: "10.0.0.1", username: "admin", defaultName: "Router A")
XCTAssertEqual(routers.first?.host, "10.0.0.1")
}
}