55namespace Cobalt . Tui . Tests . App ;
66
77/// <summary>
8- /// The COBALT_DRIVER escape hatch: forces a specific Terminal.Gui driver (needed under
9- /// terminal multiplexers like zellij/tmux, where TG's default Win32-console 'windows'
10- /// driver drops keystrokes and mishandles the editor suspend/resume). Unset = TG default.
8+ /// Driver selection (ADR 0016): an explicit COBALT_DRIVER wins; a multiplexer/RDP session
9+ /// selects 'dotnet'; otherwise the platform default is pinned explicitly ('windows' on
10+ /// Windows, 'dotnet' elsewhere) — never Terminal.Gui's auto-detect, whose 2.4.17 pick (the
11+ /// new 'ansi' driver) drops every other keypress.
1112/// </summary>
1213public class DriverResolutionTests
1314{
@@ -29,33 +30,49 @@ public class DriverResolutionTests
2930 } ;
3031
3132 [ Fact ]
32- public void Unset_Resolves_To_Null_Default ( )
33+ public void Unset_Pins_The_Windows_Driver_On_Windows ( )
3334 {
34- Assert . Null ( CobaltTuiApp . ResolveDriver ( Env ( null ) , Known ) ) ;
35+ // Never null: null would hand selection to TG auto-detect, which picks 'ansi' in
36+ // 2.4.17 — and the ansi driver eats every other keypress (the j/k double-press bug).
37+ Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( Env ( null ) , Known , isWindows : true ) ) ;
3538 }
3639
3740 [ Fact ]
38- public void Blank_Resolves_To_Null_Default ( )
41+ public void Unset_Pins_The_Dotnet_Driver_Off_Windows ( )
3942 {
40- Assert . Null ( CobaltTuiApp . ResolveDriver ( Env ( " " ) , Known ) ) ;
43+ Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( Env ( null ) , Known , isWindows : false ) ) ;
44+ }
45+
46+ [ Fact ]
47+ public void Blank_Pins_The_Platform_Default ( )
48+ {
49+ Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( Env ( " " ) , Known , isWindows : true ) ) ;
4150 }
4251
4352 [ Fact ]
4453 public void Valid_Value_Resolves_And_Trims ( )
4554 {
46- Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( Env ( " dotnet " ) , Known ) ) ;
55+ Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( Env ( " dotnet " ) , Known , isWindows : true ) ) ;
4756 }
4857
4958 [ Fact ]
5059 public void Value_Is_Case_Insensitive_And_Canonicalized ( )
5160 {
52- Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( Env ( "DotNet" ) , Known ) ) ;
61+ Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( Env ( "DotNet" ) , Known , isWindows : true ) ) ;
62+ }
63+
64+ [ Fact ]
65+ public void Explicit_Ansi_Is_Still_Honoured ( )
66+ {
67+ // The pin only governs the default; an explicit COBALT_DRIVER=ansi is a deliberate
68+ // user choice (e.g. to retest the upstream bug) and passes through.
69+ Assert . Equal ( "ansi" , CobaltTuiApp . ResolveDriver ( Env ( "ansi" ) , Known , isWindows : true ) ) ;
5370 }
5471
5572 [ Fact ]
5673 public void Unknown_Value_Throws_With_Actionable_Message ( )
5774 {
58- var ex = Assert . Throws < ConfigException > ( ( ) => CobaltTuiApp . ResolveDriver ( Env ( "dotnett" ) , Known ) ) ;
75+ var ex = Assert . Throws < ConfigException > ( ( ) => CobaltTuiApp . ResolveDriver ( Env ( "dotnett" ) , Known , isWindows : true ) ) ;
5976 Assert . Contains ( "dotnett" , ex . Message ) ;
6077 Assert . Contains ( "windows" , ex . Message ) ;
6178 Assert . Contains ( "dotnet" , ex . Message ) ;
@@ -64,34 +81,42 @@ public void Unknown_Value_Throws_With_Actionable_Message()
6481 [ Fact ]
6582 public void Zellij_Selects_The_Dotnet_Driver ( )
6683 {
67- Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( EnvVars ( zellij : "0" ) , Known ) ) ;
84+ Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( EnvVars ( zellij : "0" ) , Known , isWindows : true ) ) ;
6885 }
6986
7087 [ Fact ]
7188 public void Tmux_Selects_The_Dotnet_Driver ( )
7289 {
73- Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( EnvVars ( tmux : "/tmp/tmux-1000/default,1234,0" ) , Known ) ) ;
90+ Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( EnvVars ( tmux : "/tmp/tmux-1000/default,1234,0" ) , Known , isWindows : true ) ) ;
91+ }
92+
93+ [ Fact ]
94+ public void Multiplexer_Without_A_Dotnet_Driver_Falls_Back_To_The_Platform_Pin ( )
95+ {
96+ // Defensive: if a future Terminal.Gui drops/renames the 'dotnet' driver, degrade to
97+ // the deterministic platform pin — never to TG auto-detect.
98+ Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( EnvVars ( zellij : "0" ) , [ "windows" , "ansi" ] , isWindows : true ) ) ;
7499 }
75100
76101 [ Fact ]
77- public void Multiplexer_Without_A_Dotnet_Driver_Falls_Back_To_Null ( )
102+ public void Platform_Pin_Missing_From_The_Registry_Falls_Back_To_Null ( )
78103 {
79- // Defensive: if a future Terminal.Gui drops/renames the 'dotnet' driver, auto-detect
80- // degrades to TG's default rather than throwing (which would hit the crash boundary) .
81- Assert . Null ( CobaltTuiApp . ResolveDriver ( EnvVars ( zellij : "0" ) , [ "windows" , " ansi"] ) ) ;
104+ // Last resort only: with even the pinned driver unregistered, null lets TG pick
105+ // rather than throwing into the crash boundary.
106+ Assert . Null ( CobaltTuiApp . ResolveDriver ( EnvVars ( ) , [ "ansi" ] , isWindows : true ) ) ;
82107 }
83108
84109 [ Fact ]
85110 public void Explicit_Value_Overrides_Multiplexer_Detection ( )
86111 {
87112 // COBALT_DRIVER=windows forces the Win32 driver even inside a multiplexer.
88- Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( EnvVars ( cobaltDriver : "windows" , zellij : "0" ) , Known ) ) ;
113+ Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( EnvVars ( cobaltDriver : "windows" , zellij : "0" ) , Known , isWindows : true ) ) ;
89114 }
90115
91116 [ Fact ]
92- public void No_Override_And_No_Multiplexer_Is_Null ( )
117+ public void No_Override_And_No_Multiplexer_Pins_The_Platform_Default ( )
93118 {
94- Assert . Null ( CobaltTuiApp . ResolveDriver ( EnvVars ( ) , Known ) ) ;
119+ Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( EnvVars ( ) , Known , isWindows : true ) ) ;
95120 }
96121
97122 [ Theory ]
@@ -103,27 +128,28 @@ public void Rdp_Session_Selects_The_Dotnet_Driver(string sessionName)
103128 // A remote/RDP session (e.g. a Windows 365 Cloud PC) paints through ConPTY's
104129 // console-buffer translation on the Win32 'windows' driver — expensive over a
105130 // latency link on a GPU-less host. The stdio/ANSI 'dotnet' driver skips it.
106- Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( EnvVars ( sessionName : sessionName ) , Known ) ) ;
131+ Assert . Equal ( "dotnet" , CobaltTuiApp . ResolveDriver ( EnvVars ( sessionName : sessionName ) , Known , isWindows : true ) ) ;
107132 }
108133
109134 [ Fact ]
110- public void Console_Session_Stays_On_The_Default_Driver ( )
135+ public void Console_Session_Pins_The_Windows_Driver ( )
111136 {
112- // A physical console (SESSIONNAME=Console) is unchanged: null → TG picks 'windows'.
113- Assert . Null ( CobaltTuiApp . ResolveDriver ( EnvVars ( sessionName : "Console" ) , Known ) ) ;
137+ // A physical console (SESSIONNAME=Console) gets the same explicit pin as any
138+ // non-multiplexed Windows terminal.
139+ Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( EnvVars ( sessionName : "Console" ) , Known , isWindows : true ) ) ;
114140 }
115141
116142 [ Fact ]
117143 public void Explicit_Value_Overrides_Rdp_Detection ( )
118144 {
119145 // COBALT_DRIVER=windows forces the Win32 driver even in a remote session.
120- Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( EnvVars ( cobaltDriver : "windows" , sessionName : "RDP-Tcp#0" ) , Known ) ) ;
146+ Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( EnvVars ( cobaltDriver : "windows" , sessionName : "RDP-Tcp#0" ) , Known , isWindows : true ) ) ;
121147 }
122148
123149 [ Fact ]
124- public void Rdp_Session_Without_A_Dotnet_Driver_Falls_Back_To_Null ( )
150+ public void Rdp_Session_Without_A_Dotnet_Driver_Falls_Back_To_The_Platform_Pin ( )
125151 {
126- Assert . Null ( CobaltTuiApp . ResolveDriver ( EnvVars ( sessionName : "RDP-Tcp#0" ) , [ "windows" , "ansi" ] ) ) ;
152+ Assert . Equal ( "windows" , CobaltTuiApp . ResolveDriver ( EnvVars ( sessionName : "RDP-Tcp#0" ) , [ "windows" , "ansi" ] , isWindows : true ) ) ;
127153 }
128154
129155 [ Fact ]
0 commit comments