@@ -42,6 +42,152 @@ Describe 'DevNav PowerShell module' {
4242 }
4343}
4444
45+ Describe ' DevNav executable and installed version resolution' {
46+ It ' prefers the installed DevNav executable when present' {
47+ $moduleDirectory = Split-Path - Parent $modulePath
48+ $expectedInstalledExecutable = Join-Path $moduleDirectory ' dev.exe'
49+ $expectedDevelopmentExecutable = [System.IO.Path ]::GetFullPath((Join-Path $moduleDirectory ' ..\target\release\dev.exe' ))
50+ $global :DevNavExpectedInstalledExecutable = $expectedInstalledExecutable
51+ $global :DevNavExpectedDevelopmentExecutable = $expectedDevelopmentExecutable
52+ $global :DevNavTestPathRecords = [System.Collections.Generic.List [object ]]::new()
53+ try {
54+ $result = $devModule.Invoke ({
55+ Mock Test-Path {
56+ param ($LiteralPath , $PathType )
57+ [void ] $global :DevNavTestPathRecords.Add ([pscustomobject ]@ { LiteralPath = $LiteralPath ; PathType = $PathType })
58+ $LiteralPath -eq $global :DevNavExpectedInstalledExecutable
59+ }
60+ Get-DevExecutable
61+ })
62+
63+ $result | Should - Be $expectedInstalledExecutable
64+ @ ($global :DevNavTestPathRecords ).Count | Should - Be 2
65+ $global :DevNavTestPathRecords [0 ].LiteralPath | Should - Be $expectedInstalledExecutable
66+ $global :DevNavTestPathRecords [0 ].PathType | Should - Be ' Leaf'
67+ $global :DevNavTestPathRecords [1 ].LiteralPath | Should - Be $expectedInstalledExecutable
68+ $global :DevNavTestPathRecords [1 ].PathType | Should - Be ' Leaf'
69+ }
70+ finally {
71+ Remove-Variable DevNavExpectedInstalledExecutable, DevNavExpectedDevelopmentExecutable, DevNavTestPathRecords - Scope Global - ErrorAction SilentlyContinue
72+ }
73+ }
74+
75+ It ' falls back to the development executable when the installed executable is absent' {
76+ $moduleDirectory = Split-Path - Parent $modulePath
77+ $expectedInstalledExecutable = Join-Path $moduleDirectory ' dev.exe'
78+ $expectedDevelopmentExecutable = [System.IO.Path ]::GetFullPath((Join-Path $moduleDirectory ' ..\target\release\dev.exe' ))
79+ $global :DevNavExpectedInstalledExecutable = $expectedInstalledExecutable
80+ $global :DevNavExpectedDevelopmentExecutable = $expectedDevelopmentExecutable
81+ $global :DevNavTestPathRecords = [System.Collections.Generic.List [object ]]::new()
82+ try {
83+ $result = $devModule.Invoke ({
84+ Mock Test-Path {
85+ param ($LiteralPath , $PathType )
86+ [void ] $global :DevNavTestPathRecords.Add ([pscustomobject ]@ { LiteralPath = $LiteralPath ; PathType = $PathType })
87+ $LiteralPath -eq $global :DevNavExpectedDevelopmentExecutable
88+ }
89+ Get-DevExecutable
90+ })
91+
92+ $result | Should - Be $expectedDevelopmentExecutable
93+ @ ($global :DevNavTestPathRecords ).Count | Should - Be 2
94+ $global :DevNavTestPathRecords [0 ].LiteralPath | Should - Be $expectedInstalledExecutable
95+ $global :DevNavTestPathRecords [0 ].PathType | Should - Be ' Leaf'
96+ $global :DevNavTestPathRecords [1 ].LiteralPath | Should - Be $expectedDevelopmentExecutable
97+ $global :DevNavTestPathRecords [1 ].PathType | Should - Be ' Leaf'
98+ }
99+ finally {
100+ Remove-Variable DevNavExpectedInstalledExecutable, DevNavExpectedDevelopmentExecutable, DevNavTestPathRecords - Scope Global - ErrorAction SilentlyContinue
101+ }
102+ }
103+
104+ It ' reports an English error when no DevNav executable exists' {
105+ $moduleDirectory = Split-Path - Parent $modulePath
106+ $global :DevNavExpectedInstalledExecutable = Join-Path $moduleDirectory ' dev.exe'
107+ $global :DevNavExpectedDevelopmentExecutable = [System.IO.Path ]::GetFullPath((Join-Path $moduleDirectory ' ..\target\release\dev.exe' ))
108+ try {
109+ $devModule.Invoke ({
110+ Mock Test-Path { $false }
111+ Mock Get-DevLanguage { ' en-US' }
112+ { Get-DevExecutable } | Should - Throw ' dev.exe was not found. Run install.ps1 from the DevNav repository root.'
113+ })
114+ }
115+ finally {
116+ Remove-Variable DevNavExpectedInstalledExecutable, DevNavExpectedDevelopmentExecutable - Scope Global - ErrorAction SilentlyContinue
117+ }
118+ }
119+
120+ It ' reports a Spanish error when no DevNav executable exists' {
121+ $moduleDirectory = Split-Path - Parent $modulePath
122+ $global :DevNavExpectedInstalledExecutable = Join-Path $moduleDirectory ' dev.exe'
123+ $global :DevNavExpectedDevelopmentExecutable = [System.IO.Path ]::GetFullPath((Join-Path $moduleDirectory ' ..\target\release\dev.exe' ))
124+ try {
125+ $devModule.Invoke ({
126+ Mock Test-Path { $false }
127+ Mock Get-DevLanguage { ' es-ES' }
128+ { Get-DevExecutable } | Should - Throw ' No se encuentra dev.exe. Ejecuta install.ps1 desde la raíz de DevNav.'
129+ })
130+ }
131+ finally {
132+ Remove-Variable DevNavExpectedInstalledExecutable, DevNavExpectedDevelopmentExecutable - Scope Global - ErrorAction SilentlyContinue
133+ }
134+ }
135+
136+ It ' parses a valid installed DevNav version from a controlled executable' {
137+ $shimPath = Join-Path ([System.IO.Path ]::GetTempPath()) (' devnav-version-' + [guid ]::NewGuid().ToString(' N' ) + ' .cmd' )
138+ $logPath = Join-Path ([System.IO.Path ]::GetTempPath()) (' devnav-version-' + [guid ]::NewGuid().ToString(' N' ) + ' .log' )
139+ $global :DevNavTestVersionShim = $shimPath
140+ try {
141+ @ (" @echo off" , " echo %*>>`" $logPath `" " , ' echo dev-nav 1.2.3' , ' exit /b 0' ) | Set-Content - LiteralPath $shimPath - Encoding ascii
142+ $result = $devModule.Invoke ({
143+ Mock Get-DevExecutable { $global :DevNavTestVersionShim }
144+ Get-DevInstalledVersion
145+ })
146+
147+ $result | Should - Be ([version ]' 1.2.3' )
148+ (Get-Content - LiteralPath $logPath - Raw).Trim() | Should - Be ' --version'
149+ }
150+ finally {
151+ Remove-Item - LiteralPath $shimPath , $logPath - Force - ErrorAction SilentlyContinue
152+ Remove-Variable DevNavTestVersionShim - Scope Global - ErrorAction SilentlyContinue
153+ }
154+ }
155+
156+ It ' rejects invalid installed DevNav version output' {
157+ $shimPath = Join-Path ([System.IO.Path ]::GetTempPath()) (' devnav-version-' + [guid ]::NewGuid().ToString(' N' ) + ' .cmd' )
158+ $global :DevNavTestVersionShim = $shimPath
159+ try {
160+ @ (' @echo off' , ' echo dev-nav invalid' , ' exit /b 0' ) | Set-Content - LiteralPath $shimPath - Encoding ascii
161+ $devModule.Invoke ({
162+ Mock Get-DevExecutable { $global :DevNavTestVersionShim }
163+ Mock Get-DevLanguage { ' en-US' }
164+ { Get-DevInstalledVersion } | Should - Throw ' Unable to determine the installed DevNav version.'
165+ })
166+ }
167+ finally {
168+ Remove-Item - LiteralPath $shimPath - Force - ErrorAction SilentlyContinue
169+ Remove-Variable DevNavTestVersionShim - Scope Global - ErrorAction SilentlyContinue
170+ }
171+ }
172+
173+ It ' rejects a nonzero installed DevNav version command' {
174+ $shimPath = Join-Path ([System.IO.Path ]::GetTempPath()) (' devnav-version-' + [guid ]::NewGuid().ToString(' N' ) + ' .cmd' )
175+ $global :DevNavTestVersionShim = $shimPath
176+ try {
177+ @ (' @echo off' , ' echo dev-nav 1.2.3' , ' exit /b 7' ) | Set-Content - LiteralPath $shimPath - Encoding ascii
178+ $devModule.Invoke ({
179+ Mock Get-DevExecutable { $global :DevNavTestVersionShim }
180+ Mock Get-DevLanguage { ' es-ES' }
181+ { Get-DevInstalledVersion } | Should - Throw ' No se pudo determinar la versión instalada de DevNav.'
182+ })
183+ }
184+ finally {
185+ Remove-Item - LiteralPath $shimPath - Force - ErrorAction SilentlyContinue
186+ Remove-Variable DevNavTestVersionShim - Scope Global - ErrorAction SilentlyContinue
187+ }
188+ }
189+ }
190+
45191Describe ' DevNav updater lifecycle' {
46192 BeforeAll {
47193 $sourceRoot = Join-Path $testLocalAppData ' update-source'
0 commit comments