Bug 25/26: geleerte Felder blieben bestehen, Route-Bearbeiten scheiterte an nur-lesbarem Feld
Beide Bugs in ExpertViewModel.pendingCommand, betreffen Experte-Tab direkt (nicht nur den neuen Übersicht-Bearbeiten-Weg): - Bug 25: ein geleertes Textfeld (z.B. Kommentar löschen) wurde beim Speichern aus den Argumenten gefiltert statt explizit als "" gesendet — RouterOS' `set` ändert nur übergebene Parameter, ein weggelassener bleibt unangetastet statt geleert. Fix: Feld bleibt im Argument-Set, wenn es vorher einen Wert hatte; RouterOSCommand's SSH-Zeilen-Rendering gibt einen leeren Wert jetzt als `""` statt als nacktes `feld=` aus. - Bug 26: eine Route bearbeiten (z.B. nur Kommentar ändern) scheiterte mit "bad parameter immediate-gw" — dieses von RouterOS mitgelieferte, nur lesbare/berechnete Feld landete unkuratiert in den freien "Weiteren Parametern" und wurde bei jedem Speichern blind mitgeschickt. Fix: ein unkuratiertes Feld wird nur noch gesendet, wenn sein Wert sich gegenüber dem ursprünglich geladenen Item tatsächlich geändert hat. 54 Unit-Tests grün (neue ExpertViewModelTests + eine Ergänzung in RouterOSCommandBuilderTests). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDmUd93KxsYGr2kLTotWnG
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import XCTest
|
||||
@testable import RouterOSAssistant
|
||||
|
||||
@MainActor
|
||||
final class ExpertViewModelTests: XCTestCase {
|
||||
private func makeSchema() -> RouterOSMenuSchema {
|
||||
RouterOSMenuSchema(
|
||||
menuPath: "/ip route", restPath: "ip/route", category: .routing,
|
||||
displayName: "Test", summary: "", explanation: "",
|
||||
fields: [
|
||||
RouterOSFieldSchema(key: "comment", label: "Kommentar", kind: .text, help: "")
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
func testClearingACuratedFieldSendsExplicitEmptyValue() {
|
||||
let viewModel = ExpertViewModel(connectionService: ConnectionService())
|
||||
viewModel.selectedSchema = makeSchema()
|
||||
viewModel.startEditing(RouterOSMenuItem(id: "*1", fields: ["comment": "bridge"]))
|
||||
viewModel.formValues["comment"] = ""
|
||||
|
||||
XCTAssertEqual(viewModel.pendingCommand?.arguments["comment"], "")
|
||||
}
|
||||
|
||||
func testUnchangedUncuratedFieldIsNotResent() {
|
||||
let viewModel = ExpertViewModel(connectionService: ConnectionService())
|
||||
viewModel.selectedSchema = makeSchema()
|
||||
viewModel.startEditing(RouterOSMenuItem(id: "*1", fields: ["comment": "", "immediate-gw": "192.168.88.1"]))
|
||||
viewModel.formValues["comment"] = "bridge"
|
||||
|
||||
XCTAssertNil(viewModel.pendingCommand?.arguments["immediate-gw"])
|
||||
XCTAssertEqual(viewModel.pendingCommand?.arguments["comment"], "bridge")
|
||||
}
|
||||
|
||||
func testChangedUncuratedFieldIsSent() {
|
||||
let viewModel = ExpertViewModel(connectionService: ConnectionService())
|
||||
viewModel.selectedSchema = makeSchema()
|
||||
viewModel.startEditing(RouterOSMenuItem(id: "*1", fields: ["comment": "", "note": "old"]))
|
||||
viewModel.extraFields = [.init(key: "note", value: "new")]
|
||||
|
||||
XCTAssertEqual(viewModel.pendingCommand?.arguments["note"], "new")
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,19 @@ final class RouterOSCommandBuilderTests: XCTestCase {
|
||||
XCTAssertEqual(commands[1].menuPath, "/ip address")
|
||||
}
|
||||
|
||||
func testCliLineRendersEmptyValueAsExplicitEmptyQuotes() {
|
||||
let command = RouterOSCommand.set(
|
||||
menuPath: "/ip route",
|
||||
restPath: "ip/route",
|
||||
matchField: ".id",
|
||||
matchValue: "*1",
|
||||
arguments: ["comment": ""],
|
||||
summary: "test"
|
||||
)
|
||||
|
||||
XCTAssertEqual(command.cliLine, "/ip route set [find .id=*1] comment=\"\"")
|
||||
}
|
||||
|
||||
func testCliLineRendersSortedQuotedArgumentsForAdd() {
|
||||
let command = RouterOSCommand.add(
|
||||
menuPath: "/interface pppoe-client",
|
||||
|
||||
Reference in New Issue
Block a user