// Author: cirakg & claude ai // Summary: Helpers for the settings tests: a form store with every default, form builders and a job runner (fake data only). import Toybox.Application; import Toybox.Lang; import Toybox.Test; (:test) module SettingsFixtures { function vault() as Vault { return new Vault(new MemoryBackend(), new FakeTime()); } // A store holding every form field at its default (as properties.xml). function store() as Forms.MemoryStore { var s = new Forms.MemoryStore(); copy(s, OtpForm.defaults() as Dictionary); copy(s, CodeForm.defaults() as Dictionary); copy(s, ManageForm.defaults() as Dictionary); for (var i = 1; i <= SettingsJob.IMPORT_TEXT_FIELDS; i++) { s.set("impText" + i, ""); } s.set("impMode", 0); s.set("impLocked", false); var off = ["otpAdd", "codeAdd", "mgApply", "impApply"]; for (var i = 0; i < off.size(); i++) { s.set(off[i] as String, false); } return s; } function copy(s as Forms.MemoryStore, values as Dictionary) as Void { var keys = values.keys(); for (var i = 0; i < keys.size(); i++) { s.set(keys[i], values[keys[i]] as Application.Properties.ValueType); } } // Fill in Add OTP and turn its switch on. function otp(s as Forms.Store, type as Number, issuer as String, account as String, secret as String) as Void { s.set("otpType", type); s.set("otpIssuer", issuer); s.set("otpAccount", account); s.set("otpSecret", secret); s.set(OtpForm.SWITCH, true); } function code(s as Forms.Store, symbology as Number, name as String, payload as String) as Void { s.set("codeName", name); s.set("codeSymbology", symbology); s.set("codePayload", payload); s.set(CodeForm.SWITCH, true); } function manage(s as Forms.Store, id as String, action as Number) as Void { s.set("mgId", id); s.set("mgAction", action); s.set(ManageForm.SWITCH, true); } // Run every form to the end, as the app's timer would. function run(v as Vault, s as Forms.Store) as SettingsJob { var job = new SettingsJob(v, s, 1800000000l); Jobs.runToCompletion(job, 1); return job; } function text(s as Forms.Store, key as String) as String { var v = s.get(key); return v instanceof String ? v : ""; } // True when the field's text contains `part`; logs it otherwise. function contains(logger as Test.Logger, s as Forms.Store, key as String, part as String) as Boolean { var value = text(s, key); if (value.find(part) != null) { return true; } logger.error(key + " = '" + value + "', expected to contain '" + part + "'"); return false; } // True when some line starts with `prefix`. function hasLine(lines as Array, prefix as String) as Boolean { for (var i = 0; i < lines.size(); i++) { if (lines[i].find(prefix) == 0) { return true; } } return false; } // A string of n copies of `unit`. function repeat(unit as String, n as Number) as String { var out = ""; for (var i = 0; i < n; i++) { out += unit; } return out; } // The secret of an entry, as text (the fixtures use ASCII keys). function secretOf(v as Vault, id as String) as String { var e = v.open(id); var text = Bytes.toUtf8(e.kind == Entry.KIND_OTP ? e.secret as ByteArray : e.payload as ByteArray); e.wipeSecrets(); return text != null ? text : ""; } }