mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-09-11 11:45:27 +02:00
Resolves the active operator profile before the chat controller is built and passes its two file names on, so preferences, layout and worked data follow the profile. The resolution is deliberately quiet for existing installations. With no registry or exactly one profile nothing is asked and nothing is written, so a single operator start is unchanged. Only from two profiles on does a small picker appear with the last used profile preselected, where Enter or a double click starts immediately. A "--profile" argument, or the equivalent system property, skips the picker; an unknown name warns and falls back to the normal selection instead of refusing to start. The startup decision itself lives in OperatorProfileBootstrap and contains no user interface code, so it is covered by headless tests. The window title gains the profile name only when a second profile exists. Command line parsing happens in init() and is kept in a process wide holder, because JavaFX only knows the parameters of the instance it launched itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hpa6bjie5qkeNG62y6FmXm
162 lines
6.2 KiB
Java
162 lines
6.2 KiB
Java
package kst4contest.view;
|
|
|
|
import kst4contest.controller.OperatorProfilePaths;
|
|
import kst4contest.controller.OperatorProfileStore;
|
|
import kst4contest.model.OperatorProfile;
|
|
import kst4contest.model.OperatorProfileSelection;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.io.TempDir;
|
|
|
|
import java.nio.file.Path;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
class OperatorProfileBootstrapTest {
|
|
|
|
@TempDir
|
|
Path temporaryDirectory;
|
|
|
|
@Test
|
|
void installationWithoutRegistryStartsSilentlyOnTheHistoricLayout() {
|
|
|
|
AtomicInteger pickerInvocations = new AtomicInteger();
|
|
OperatorProfileStore store = storeAt();
|
|
|
|
OperatorProfileSelection resolved = new OperatorProfileBootstrap().resolveAtStartup(
|
|
store, new CommandLineOptions(null), countingPicker(pickerInvocations, null));
|
|
|
|
assertNotNull(resolved);
|
|
assertEquals("preferences.xml", resolved.getPreferencesRelativeFileName());
|
|
assertEquals("praktiKST.db", resolved.getWorkedDatabaseRelativeFileName());
|
|
|
|
// Nothing may be asked, and nothing may be written.
|
|
assertEquals(0, pickerInvocations.get());
|
|
assertTrue(store.loadProfiles().isEmpty());
|
|
}
|
|
|
|
@Test
|
|
void singleProfileStartsWithoutAskingAnything() {
|
|
|
|
AtomicInteger pickerInvocations = new AtomicInteger();
|
|
OperatorProfileStore store = storeAt();
|
|
store.saveProfiles(List.of(OperatorProfilePaths.buildRootProfile("Default")), "default");
|
|
|
|
OperatorProfileSelection resolved = new OperatorProfileBootstrap().resolveAtStartup(
|
|
store, new CommandLineOptions(null), countingPicker(pickerInvocations, null));
|
|
|
|
assertNotNull(resolved);
|
|
assertEquals(0, pickerInvocations.get());
|
|
}
|
|
|
|
@Test
|
|
void twoProfilesAskTheOperatorAndPreselectTheLastUsedOne() {
|
|
|
|
OperatorProfileStore store = storeAt();
|
|
OperatorProfile secondProfile = new OperatorProfile("OP2", "DN9APW", false, false);
|
|
store.saveProfiles(
|
|
List.of(OperatorProfilePaths.buildRootProfile("Default"), secondProfile), "OP2");
|
|
|
|
AtomicInteger pickerInvocations = new AtomicInteger();
|
|
String[] observedPreselection = new String[1];
|
|
|
|
OperatorProfileSelection resolved = new OperatorProfileBootstrap().resolveAtStartup(
|
|
store,
|
|
new CommandLineOptions(null),
|
|
(profiles, preselectedProfileId) -> {
|
|
pickerInvocations.incrementAndGet();
|
|
observedPreselection[0] = preselectedProfileId;
|
|
return Optional.of(profiles.get(1));
|
|
});
|
|
|
|
assertEquals(1, pickerInvocations.get());
|
|
assertEquals("OP2", observedPreselection[0]);
|
|
assertNotNull(resolved);
|
|
assertEquals("profiles/OP2/praktiKST.db", resolved.getWorkedDatabaseRelativeFileName());
|
|
}
|
|
|
|
@Test
|
|
void aValidProfileArgumentSkipsThePicker() {
|
|
|
|
OperatorProfileStore store = storeAt();
|
|
store.saveProfiles(
|
|
List.of(OperatorProfilePaths.buildRootProfile("Default"),
|
|
new OperatorProfile("OP2", "DN9APW", false, false)),
|
|
"default");
|
|
|
|
AtomicInteger pickerInvocations = new AtomicInteger();
|
|
OperatorProfileBootstrap bootstrap = new OperatorProfileBootstrap();
|
|
|
|
OperatorProfileSelection byId = bootstrap.resolveAtStartup(
|
|
store, new CommandLineOptions("op2"), countingPicker(pickerInvocations, null));
|
|
|
|
assertEquals(0, pickerInvocations.get());
|
|
assertEquals("profiles/OP2/preferences.xml", byId.getPreferencesRelativeFileName());
|
|
assertNull(bootstrap.getStartupWarning());
|
|
|
|
OperatorProfileSelection byDisplayName = bootstrap.resolveAtStartup(
|
|
store, new CommandLineOptions("DN9APW"), countingPicker(pickerInvocations, null));
|
|
|
|
assertEquals(0, pickerInvocations.get());
|
|
assertEquals("profiles/OP2/preferences.xml", byDisplayName.getPreferencesRelativeFileName());
|
|
}
|
|
|
|
@Test
|
|
void anUnknownProfileArgumentWarnsAndFallsBackToTheNormalSelection() {
|
|
|
|
OperatorProfileStore store = storeAt();
|
|
store.saveProfiles(
|
|
List.of(OperatorProfilePaths.buildRootProfile("Default"),
|
|
new OperatorProfile("OP2", "DN9APW", false, false)),
|
|
"default");
|
|
|
|
AtomicInteger pickerInvocations = new AtomicInteger();
|
|
OperatorProfileBootstrap bootstrap = new OperatorProfileBootstrap();
|
|
|
|
OperatorProfileSelection resolved = bootstrap.resolveAtStartup(
|
|
store, new CommandLineOptions("NOPE"), countingPicker(pickerInvocations, 0));
|
|
|
|
assertEquals(1, pickerInvocations.get());
|
|
assertNotNull(resolved);
|
|
assertNotNull(bootstrap.getStartupWarning());
|
|
assertTrue(bootstrap.getStartupWarning().contains("NOPE"));
|
|
}
|
|
|
|
@Test
|
|
void quittingInThePickerYieldsNoSelection() {
|
|
|
|
OperatorProfileStore store = storeAt();
|
|
store.saveProfiles(
|
|
List.of(OperatorProfilePaths.buildRootProfile("Default"),
|
|
new OperatorProfile("OP2", "DN9APW", false, false)),
|
|
"default");
|
|
|
|
OperatorProfileSelection resolved = new OperatorProfileBootstrap().resolveAtStartup(
|
|
store, new CommandLineOptions(null), (profiles, preselected) -> Optional.empty());
|
|
|
|
assertNull(resolved);
|
|
}
|
|
|
|
private OperatorProfileChoiceRequester countingPicker(final AtomicInteger invocationCounter,
|
|
final Integer profileIndexToChoose) {
|
|
return (profiles, preselectedProfileId) -> {
|
|
invocationCounter.incrementAndGet();
|
|
|
|
if (profileIndexToChoose == null) {
|
|
return Optional.of(profiles.get(0));
|
|
}
|
|
|
|
return Optional.of(profiles.get(profileIndexToChoose));
|
|
};
|
|
}
|
|
|
|
private OperatorProfileStore storeAt() {
|
|
return new OperatorProfileStore(temporaryDirectory.resolve("profiles.xml").toString());
|
|
}
|
|
}
|