Stufe 4c (#764): Bezeichner auf Englisch - Typen, Methoden, Felder, Parameter, Locals, Testnamen

Mit Roslyn umbenannt (Verweise folgen, Zeichenketten bleiben unberuehrt).
Nicht umbenannt, weil gespeichert oder ueber die API gebunden (Stufe 4e):
Properties, Record-Parameter, Enum-Member sowie die Parameter der
Endpunkt-Handler (Routen-/Query-Bindung ueber den Namen). Die JSON-Felder
anonymer Objekte bleiben ausdruecklich benannt (JsonFilter: pfad).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-10-04 13:18:43 +02:00
co-authored by Claude Opus 5.5
parent 837a634a22
commit 77062facc9
190 changed files with 4813 additions and 4813 deletions
@@ -9,7 +9,7 @@ namespace ClawdDotNet.Web.Tests;
public sealed class AgentCommunicationTests
{
[Fact]
public void AgentCommunicationDto_speichert_Felder_korrekt()
public void AgentCommunicationDto_stores_fields_correctly()
{
var now = DateTime.UtcNow;
var dto = new AgentCommunicationDto(
@@ -37,7 +37,7 @@ public sealed class InstanceSocketTests : IDisposable
catch { /* A leftover test folder does not turn a run red. */ }
}
private AppHost NeuerHost(bool mitWeboberflaeche, int port = 0)
private AppHost NewHost(bool withWebUi, int port = 0)
{
var instancesDir = Path.Combine(_root, "Instances");
var instancePath = Path.Combine(instancesDir, "Test");
@@ -51,9 +51,9 @@ public sealed class InstanceSocketTests : IDisposable
{
InstanceName = "Test",
WorkingDirectory = instancePath,
WebUiEnabled = mitWeboberflaeche,
WebUiEnabled = withWebUi,
WebUiBinding = "loopback",
WebUiToken = mitWeboberflaeche ? Token : "",
WebUiToken = withWebUi ? Token : "",
WebServerPort = port
},
InstancePath = instancePath,
@@ -63,7 +63,7 @@ public sealed class InstanceSocketTests : IDisposable
};
}
private static int FreierPort()
private static int FreePort()
{
using var probe = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
probe.Start();
@@ -75,27 +75,27 @@ public sealed class InstanceSocketTests : IDisposable
// ─── The socket holds ───
[Fact]
public async Task Der_Socket_antwortet_auch_ohne_Weboberflaeche()
public async Task The_socket_answers_even_without_web_UI()
{
// The default: webUiEnabled is off. Formerly nothing ran at all then, and the
// instance was not addressable from outside.
await using var host = NeuerHost(mitWeboberflaeche: false);
await using var host = NewHost(withWebUi: false);
await using var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
web.ShouldNotBeNull();
web!.Url.ShouldBeNull();
using var client = InstanceEndpoint.CreateClient(host.InstancePath);
var antwort = await client.GetAsync("/api/info");
var answer = await client.GetAsync("/api/info");
antwort.EnsureSuccessStatusCode();
(await antwort.Content.ReadAsStringAsync()).ShouldContain("Test");
answer.EnsureSuccessStatusCode();
(await answer.Content.ReadAsStringAsync()).ShouldContain("Test");
}
[Fact]
public async Task Ueber_den_Socket_braucht_es_kein_Token()
public async Task Over_the_socket_no_token_is_needed()
{
await using var host = NeuerHost(mitWeboberflaeche: true, port: FreierPort());
await using var host = NewHost(withWebUi: true, port: FreePort());
await using var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
web.ShouldNotBeNull();
@@ -108,11 +108,11 @@ public sealed class InstanceSocketTests : IDisposable
// ─── The port stays guarded ───
[Fact]
public async Task Ueber_TCP_gilt_die_Token_Pflicht_weiter()
public async Task Over_TCP_the_token_requirement_still_applies()
{
var port = FreierPort();
var port = FreePort();
await using var host = NeuerHost(mitWeboberflaeche: true, port: port);
await using var host = NewHost(withWebUi: true, port: port);
await using var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
web.ShouldNotBeNull();
@@ -130,7 +130,7 @@ public sealed class InstanceSocketTests : IDisposable
// ─── Addresses ───
[Fact]
public void Zwei_Instanzen_bekommen_zwei_Adressen()
public void Two_instances_get_two_addresses()
{
var a = Path.Combine(_root, "Instances", "Eins");
var b = Path.Combine(_root, "Instances", "Zwei");
@@ -140,7 +140,7 @@ public sealed class InstanceSocketTests : IDisposable
}
[Fact]
public void Dieselbe_Instanz_bekommt_dieselbe_Adresse()
public void The_same_instance_gets_the_same_address()
{
// The manager computes the address from the path it knows itself — so it
// must come out the same from every spelling of the same directory.
@@ -161,12 +161,12 @@ public sealed class InstanceSocketTests : IDisposable
/// <c>EADDRINUSE</c> from a process that no longer exists.</para>
/// </summary>
[SocketFileFact]
public async Task Eine_liegengebliebene_Socketdatei_haelt_den_Start_nicht_auf()
public async Task A_leftover_socket_file_does_not_hold_up_the_start()
{
await using var host = NeuerHost(mitWeboberflaeche: false);
await using var host = NewHost(withWebUi: false);
var leiche = InstanceEndpoint.SocketPath(host.InstancePath);
File.WriteAllText(leiche, "Rest eines abgestuerzten Prozesses");
var corpse = InstanceEndpoint.SocketPath(host.InstancePath);
File.WriteAllText(corpse, "Rest eines abgestuerzten Prozesses");
await using var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
web.ShouldNotBeNull();
@@ -176,9 +176,9 @@ public sealed class InstanceSocketTests : IDisposable
}
[SocketFileFact]
public async Task Beim_Beenden_bleibt_keine_Socketdatei_liegen()
public async Task Shutdown_leaves_no_socket_file_behind()
{
await using var host = NeuerHost(mitWeboberflaeche: false);
await using var host = NewHost(withWebUi: false);
var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
web.ShouldNotBeNull();
@@ -212,7 +212,7 @@ public sealed class InstanceControlTests : IDisposable
catch { /* A leftover test folder does not turn a run red. */ }
}
private AppHost NeuerHost(int port)
private AppHost NewHost(int port)
{
var instancesDir = Path.Combine(_root, "Instances");
var instancePath = Path.Combine(instancesDir, "Test");
@@ -238,7 +238,7 @@ public sealed class InstanceControlTests : IDisposable
};
}
private static int FreierPort()
private static int FreePort()
{
using var probe = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
probe.Start();
@@ -248,18 +248,18 @@ public sealed class InstanceControlTests : IDisposable
}
[Fact]
public async Task Ueber_TCP_gibt_es_die_Steuerung_nicht()
public async Task Over_TCP_there_is_no_control()
{
var port = FreierPort();
var port = FreePort();
await using var host = NeuerHost(port);
await using var host = NewHost(port);
await using var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
web.ShouldNotBeNull();
web!.Url.ShouldNotBeNull();
var gebeten = false;
web.Control.ShutdownRequested += () => gebeten = true;
var requested = false;
web.Control.ShutdownRequested += () => requested = true;
using var client = new HttpClient { BaseAddress = new Uri($"http://127.0.0.1:{port}") };
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {Token}");
@@ -268,6 +268,6 @@ public sealed class InstanceControlTests : IDisposable
(await client.PostAsync("/api/instanz/beenden", content: null)).StatusCode
.ShouldBe(System.Net.HttpStatusCode.NotFound);
gebeten.ShouldBeFalse();
requested.ShouldBeFalse();
}
}
@@ -15,16 +15,16 @@ namespace ClawdDotNet.Web.Tests;
public sealed class SecretMaskingTests
{
[Fact]
public void Ein_Passwort_kommt_nicht_heraus()
public void A_password_does_not_come_out()
{
var einstellungen = new Dictionary<string, object?>
var settings = new Dictionary<string, object?>
{
["host"] = "mail.example",
["port"] = 993,
["password"] = "sehr-geheim"
};
var dto = Mapping.ToDto("Mail", einstellungen);
var dto = Mapping.ToDto("Mail", settings);
// Keys.ShouldContain instead of ShouldContainKey: the DTOs hand out
// IReadOnlyDictionary, and Shouldly's dictionary extensions sit
@@ -39,7 +39,7 @@ public sealed class SecretMaskingTests
}
[Fact]
public void Ein_leeres_Geheimnis_gilt_als_nicht_gesetzt()
public void An_empty_secret_counts_as_not_set()
{
var dto = Mapping.ToDto("Mail", new Dictionary<string, object?>
{
@@ -63,25 +63,25 @@ public sealed class SecretMaskingTests
[InlineData("connectionString")]
[InlineData("apiHash")]
[InlineData("webUiToken")]
public void Jeder_bekannte_Geheimnisname_wird_maskiert(string schluessel)
public void Every_known_secret_name_is_masked(string key)
{
// The list comes from ConfigSecrets and not from a second one here: a
// second would be the one forgotten with the next new tool.
ConfigSecrets.IsSecretKey(schluessel).ShouldBeTrue();
ConfigSecrets.IsSecretKey(key).ShouldBeTrue();
Mapping.ToDto("X", new Dictionary<string, object?> { [schluessel] = "geheim" })
.Values.Keys.ShouldNotContain(schluessel);
Mapping.ToDto("X", new Dictionary<string, object?> { [key] = "geheim" })
.Values.Keys.ShouldNotContain(key);
}
[Fact]
public void Die_Schreibweise_des_Schluessels_spielt_keine_Rolle()
public void The_spelling_of_the_key_does_not_matter()
{
Mapping.ToDto("X", new Dictionary<string, object?> { ["PASSWORD"] = "geheim" })
.Values.ShouldBeEmpty();
}
[Fact]
public void Ein_serialisiertes_DTO_enthaelt_das_Geheimnis_nicht()
public void A_serialised_DTO_does_not_contain_the_secret()
{
// The test that really counts: not the structure, but what goes over the
// line.
+24 -24
View File
@@ -35,9 +35,9 @@ public sealed class ShutdownTests : IDisposable
/// seconds). If the test stays below two, the promise is kept without a
/// slow build server turning it red.
/// </summary>
private static readonly TimeSpan Grenze = TimeSpan.FromSeconds(2);
private static readonly TimeSpan Limit = TimeSpan.FromSeconds(2);
private AppHost NeuerHost(int port)
private AppHost NewHost(int port)
{
var instancesDir = Path.Combine(_root, "Instances");
var instancePath = Path.Combine(instancesDir, "Test");
@@ -66,7 +66,7 @@ public sealed class ShutdownTests : IDisposable
/// A free port from the operating system. A fixed number would let two test runs
/// fail side by side — and those are exactly the errors you search for the longest.
/// </summary>
private static int FreierPort()
private static int FreePort()
{
using var probe = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
probe.Start();
@@ -76,10 +76,10 @@ public sealed class ShutdownTests : IDisposable
}
[Fact]
public async Task Beenden_wartet_nicht_auf_einen_offenen_Ereignisstrom()
public async Task Shutdown_does_not_wait_for_an_open_event_stream()
{
var port = FreierPort();
await using var host = NeuerHost(port);
var port = FreePort();
await using var host = NewHost(port);
var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
web.ShouldNotBeNull();
@@ -89,39 +89,39 @@ public sealed class ShutdownTests : IDisposable
// Really open the stream and wait for the first line: only then does
// Kestrel hold the request, and only then does the test check what it wants to check.
using var antwort = await client.GetAsync(
using var answer = await client.GetAsync(
$"http://127.0.0.1:{port}/events?token={Token}",
HttpCompletionOption.ResponseHeadersRead);
antwort.EnsureSuccessStatusCode();
answer.EnsureSuccessStatusCode();
await using var strom = await antwort.Content.ReadAsStreamAsync();
using var leser = new StreamReader(strom);
(await leser.ReadLineAsync()).ShouldBe(": bereit");
await using var stream = await answer.Content.ReadAsStreamAsync();
using var reader = new StreamReader(stream);
(await reader.ReadLineAsync()).ShouldBe(": bereit");
var uhr = Stopwatch.StartNew();
var clock = Stopwatch.StartNew();
await web!.DisposeAsync();
uhr.Stop();
clock.Stop();
uhr.Elapsed.ShouldBeLessThan(Grenze,
$"Das Beenden dauerte {uhr.Elapsed.TotalSeconds:0.0}s — der Ereignisstrom "
clock.Elapsed.ShouldBeLessThan(Limit,
$"Das Beenden dauerte {clock.Elapsed.TotalSeconds:0.0}s — der Ereignisstrom "
+ "hat das Herunterfahren nicht bemerkt.");
}
[Fact]
public async Task Beenden_geht_auch_ohne_offene_Verbindung_zuegig()
public async Task Shutdown_is_quick_even_without_an_open_connection()
{
var port = FreierPort();
await using var host = NeuerHost(port);
var port = FreePort();
await using var host = NewHost(port);
var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
web.ShouldNotBeNull();
var uhr = Stopwatch.StartNew();
var clock = Stopwatch.StartNew();
await web!.DisposeAsync();
uhr.Stop();
clock.Stop();
uhr.Elapsed.ShouldBeLessThan(Grenze);
clock.Elapsed.ShouldBeLessThan(Limit);
}
/// <summary>
@@ -135,14 +135,14 @@ public sealed class ShutdownTests : IDisposable
/// exists for.</para>
/// </summary>
[Fact]
public async Task Ein_belegter_Port_kostet_nur_die_Weboberflaeche()
public async Task An_occupied_port_only_costs_the_web_UI()
{
var port = FreierPort();
var port = FreePort();
using var blockierer = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, port);
blockierer.Start();
await using var host = NeuerHost(port);
await using var host = NewHost(port);
await using var web = InstanceHttpHost.TryStart(host, NullLoggerFactory.Instance);
@@ -11,40 +11,40 @@ namespace ClawdDotNet.Web.Tests;
/// Findings from reviewing the web UI in test operation (#572): #591 (field names) and
/// #536 (direction of the A2A answers).
/// </summary>
public sealed class TestbetriebWebTests
public sealed class TestOperationWebTests
{
// ─── #591 event stream and transfer types ───
[Fact]
public void Protokollzeilen_im_Ereignisstrom_kommen_in_camelCase()
public void Log_lines_in_the_event_stream_come_in_camelCase()
{
var ereignis = EventEndpoints.Format("log", new LogLineDto("Startup", "INF", "ClawdDotNet startet"));
var evt = EventEndpoints.Format("log", new LogLineDto("Startup", "INF", "ClawdDotNet startet"));
ereignis.ShouldStartWith("event: log\n");
ereignis.ShouldContain("\"module\":\"Startup\"");
ereignis.ShouldContain("\"level\":\"INF\"");
ereignis.ShouldContain("\"text\":\"ClawdDotNet startet\"");
ereignis.ShouldNotContain("\"Text\"", Case.Sensitive);
evt.ShouldStartWith("event: log\n");
evt.ShouldContain("\"module\":\"Startup\"");
evt.ShouldContain("\"level\":\"INF\"");
evt.ShouldContain("\"text\":\"ClawdDotNet startet\"");
evt.ShouldNotContain("\"Text\"", Case.Sensitive);
}
[Fact]
public void Freigabe_traegt_ihren_Zeitpunkt()
public void Approval_carries_its_time()
{
var angelegt = new DateTime(2026, 9, 14, 10, 18, 53, DateTimeKind.Utc);
var created = new DateTime(2026, 9, 14, 10, 18, 53, DateTimeKind.Utc);
var dto = new StagedCall
{
Id = 1, AgentId = "hausmeister", Tool = "FileRW", Action = "delete",
ArgumentsJson = "{\"path\":\"betrieb/probe-loeschung.txt\"}", CreatedAt = angelegt
ArgumentsJson = "{\"path\":\"betrieb/probe-loeschung.txt\"}", CreatedAt = created
}.ToDto();
dto.CreatedAt.ShouldBe(angelegt);
dto.CreatedAt.ShouldBe(created);
dto.Tool.ShouldBe("FileRW");
dto.Action.ShouldBe("delete");
}
[Fact]
public void Aufgabe_traegt_ihren_Termin()
public void Task_carries_its_schedule()
{
var dto = new TaskItem
{
@@ -60,47 +60,47 @@ public sealed class TestbetriebWebTests
}
[Fact]
public void Einmalige_Aufgabe_hat_keinen_Termin()
public void One_off_task_has_no_schedule()
=> new TaskItem { Id = "t-1", Title = "Einrichtung" }.ToDto().When.ShouldBeNull();
// ─── #536 sender and recipient ───
private static ChatEntry Anfrage(string vonName, string vonId, string text, int minute)
=> new("user", $"[Nachricht von Agent \"{vonName}\" ({vonId})]\n\n{text}",
private static ChatEntry Request(string fromName, string fromId, string text, int minute)
=> new("user", $"[Nachricht von Agent \"{fromName}\" ({fromId})]\n\n{text}",
new DateTime(2026, 9, 14, 12, minute, 0), ChatSource.AgentComm);
private static ChatEntry Antwort(string text, int minute)
private static ChatEntry Answer(string text, int minute)
=> new("assistant", text, new DateTime(2026, 9, 14, 12, minute, 30), ChatSource.AgentComm);
[Fact]
public void Antwort_geht_vom_Antwortenden_an_den_Fragenden()
public void Answer_goes_from_the_responder_to_the_asker()
{
var liste = AgentCommunicationBuilder.Build(
var list = AgentCommunicationBuilder.Build(
[
("redaktion", "Redaktion", (IEnumerable<ChatEntry>)
[
Anfrage("Hausmeister", "hausmeister", "Testnachricht", 48),
Antwort("Empfang bestaetigt", 48)
Request("Hausmeister", "hausmeister", "Testnachricht", 48),
Answer("Empfang bestaetigt", 48)
])
]);
liste.Count.ShouldBe(2);
list.Count.ShouldBe(2);
var anfrage = liste[0];
anfrage.SourceAgentId.ShouldBe("hausmeister");
anfrage.TargetAgentId.ShouldBe("redaktion");
anfrage.Content.ShouldBe("Testnachricht");
var request = list[0];
request.SourceAgentId.ShouldBe("hausmeister");
request.TargetAgentId.ShouldBe("redaktion");
request.Content.ShouldBe("Testnachricht");
var antwort = liste[1];
antwort.SourceAgentId.ShouldBe("redaktion");
antwort.TargetAgentId.ShouldBe("hausmeister", "vorher stand hier der Antwortende selbst");
antwort.TargetAgentName.ShouldBe("Hausmeister");
var answer = list[1];
answer.SourceAgentId.ShouldBe("redaktion");
answer.TargetAgentId.ShouldBe("hausmeister", "vorher stand hier der Antwortende selbst");
answer.TargetAgentName.ShouldBe("Hausmeister");
}
[Fact]
public void Nur_Agentenkommunikation_wird_aufgenommen()
public void Only_agent_communication_is_recorded()
{
var liste = AgentCommunicationBuilder.Build(
var list = AgentCommunicationBuilder.Build(
[
("hausmeister", "Hausmeister", (IEnumerable<ChatEntry>)
[
@@ -109,20 +109,20 @@ public sealed class TestbetriebWebTests
])
]);
liste.ShouldBeEmpty();
list.ShouldBeEmpty();
}
[Theory]
[InlineData("[Nachricht von Agent \"Hausmeister\" ohne Klammer]\n\nText")]
[InlineData("[Nachricht von Agent \"Bo\"b\" (bob)]\n\nText")]
[InlineData("[Nachricht von Agent \"")]
public void Absender_lesen_wirft_bei_unerwarteter_Form_nicht(string inhalt)
=> Should.NotThrow(() => AgentCommunicationBuilder.LeseAbsender(inhalt));
public void Reading_the_sender_does_not_throw_on_unexpected_form(string content)
=> Should.NotThrow(() => AgentCommunicationBuilder.ReadSender(content));
[Fact]
public void Absender_lesen_liefert_Kennung_Name_und_Text()
public void Reading_the_sender_returns_id_name_and_text()
{
var (id, name, text) = AgentCommunicationBuilder.LeseAbsender(
var (id, name, text) = AgentCommunicationBuilder.ReadSender(
"[Nachricht von Agent \"Hausmeister\" (hausmeister)]\n\nHallo Redaktion!");
id.ShouldBe("hausmeister");
@@ -11,7 +11,7 @@ namespace ClawdDotNet.Web.Tests;
/// </summary>
public sealed class WebUiOptionsTests
{
private static InstanceConfig Instanz(
private static InstanceConfig Instance(
bool enabled = true,
string binding = "loopback",
string token = "ein-hinreichend-langes-token",
@@ -25,7 +25,7 @@ public sealed class WebUiOptionsTests
};
[Fact]
public void Sie_ist_in_der_Vorbelegung_aus()
public void It_is_off_by_default()
{
// Whoever wants a network service switches it on. Not the other way round.
new InstanceConfig().WebUiEnabled.ShouldBeFalse();
@@ -34,25 +34,25 @@ public sealed class WebUiOptionsTests
}
[Fact]
public void Abgeschaltet_ist_kein_Fehler()
public void Switched_off_is_not_an_error()
{
WebUiOptions.TryCreate(Instanz(enabled: false), out var problem).ShouldBeNull();
WebUiOptions.TryCreate(Instance(enabled: false), out var problem).ShouldBeNull();
problem.ShouldBeNull();
}
[Fact]
public void Ohne_Token_startet_sie_nicht_einmal_auf_Loopback()
public void Without_token_it_does_not_start_even_on_loopback()
{
// On a machine on which agents operate browser tools,
// "localhost" is no trust boundary.
WebUiOptions.TryCreate(Instanz(token: ""), out var problem).ShouldBeNull();
WebUiOptions.TryCreate(Instance(token: ""), out var problem).ShouldBeNull();
problem.ShouldNotBeNull();
}
[Fact]
public void Alle_Adressen_ohne_Token_werden_abgelehnt_und_nicht_bemaengelt()
public void All_addresses_without_token_are_rejected_and_not_flagged()
{
var options = WebUiOptions.TryCreate(Instanz(binding: "any", token: ""), out var problem);
var options = WebUiOptions.TryCreate(Instance(binding: "any", token: ""), out var problem);
options.ShouldBeNull();
problem.ShouldNotBeNull();
@@ -60,16 +60,16 @@ public sealed class WebUiOptionsTests
}
[Fact]
public void Ein_zu_kurzes_Token_zaehlt_nicht()
public void A_too_short_token_does_not_count()
{
WebUiOptions.TryCreate(Instanz(token: "kurz"), out var problem).ShouldBeNull();
WebUiOptions.TryCreate(Instance(token: "kurz"), out var problem).ShouldBeNull();
problem.ShouldNotBeNull();
}
[Fact]
public void Loopback_bindet_an_127_0_0_1()
public void Loopback_binds_to_127_0_0_1()
{
var options = WebUiOptions.TryCreate(Instanz(port: 9001), out _);
var options = WebUiOptions.TryCreate(Instance(port: 9001), out _);
options.ShouldNotBeNull();
options!.Url.ShouldBe("http://127.0.0.1:9001");
@@ -77,17 +77,17 @@ public sealed class WebUiOptionsTests
}
[Fact]
public void Alles_ausser_any_bleibt_Loopback()
public void Everything_except_any_stays_loopback()
{
// A typo in the instance file must not put the user interface onto the network.
WebUiOptions.TryCreate(Instanz(binding: "alle"), out _)!.LoopbackOnly.ShouldBeTrue();
WebUiOptions.TryCreate(Instanz(binding: ""), out _)!.LoopbackOnly.ShouldBeTrue();
WebUiOptions.TryCreate(Instance(binding: "alle"), out _)!.LoopbackOnly.ShouldBeTrue();
WebUiOptions.TryCreate(Instance(binding: ""), out _)!.LoopbackOnly.ShouldBeTrue();
}
[Fact]
public void Mit_Token_darf_sie_an_alle_Adressen()
public void With_token_it_may_reach_all_addresses()
{
var options = WebUiOptions.TryCreate(Instanz(binding: "ANY"), out _);
var options = WebUiOptions.TryCreate(Instance(binding: "ANY"), out _);
options.ShouldNotBeNull();
options!.LoopbackOnly.ShouldBeFalse();
@@ -98,20 +98,20 @@ public sealed class WebUiOptionsTests
[InlineData(0)]
[InlineData(-1)]
[InlineData(70000)]
public void Ein_unmoeglicher_Port_wird_abgelehnt(int port)
public void An_impossible_port_is_rejected(int port)
{
WebUiOptions.TryCreate(Instanz(port: port), out var problem).ShouldBeNull();
WebUiOptions.TryCreate(Instance(port: port), out var problem).ShouldBeNull();
problem.ShouldNotBeNull();
}
[Fact]
public void Das_Token_steht_geschuetzt_in_der_Instanzdatei()
public void The_token_is_stored_protected_in_the_instance_file()
{
// Without the entry in ConfigSecrets it would be in plain text next to the
// protected OpenRouter key.
Core.Security.ConfigSecrets.IsSecretKey("webUiToken").ShouldBeTrue();
var config = Instanz(token: "ein-hinreichend-langes-token");
var config = Instance(token: "ein-hinreichend-langes-token");
Core.Security.ConfigSecrets.Protect(config);
config.WebUiToken.ShouldNotBe("ein-hinreichend-langes-token");