@@ -207,6 +207,72 @@ Describe 'Coverage for remaining manifest, JSON, and help-locale helpers' {
207207 }
208208 }
209209
210+ It ' Get-NovaModulePsDataValue returns null for null PSData and reads object properties when present' {
211+ InModuleScope $script :moduleName {
212+ $nullPsDataModule = [pscustomobject ]@ {
213+ PrivateData = [pscustomobject ]@ {PSData = $null }
214+ }
215+ $objectPsDataModule = [pscustomobject ]@ {
216+ PrivateData = [pscustomobject ]@ {
217+ PSData = [pscustomobject ]@ {
218+ Prerelease = ' preview'
219+ }
220+ }
221+ }
222+
223+ Get-NovaModulePsDataValue - Name ' Prerelease' - Module $nullPsDataModule | Should - BeNullOrEmpty
224+ Get-NovaModulePsDataValue - Name ' Prerelease' - Module $objectPsDataModule | Should - Be ' preview'
225+ Get-NovaModulePsDataValue - Name ' ReleaseNotes' - Module $objectPsDataModule | Should - BeNullOrEmpty
226+ }
227+ }
228+
229+ It ' Get-NovaResolvedProjectManifestSettings returns a copy for manifest hashtables and an empty ordered table otherwise' {
230+ InModuleScope $script :moduleName {
231+ $projectDataWithManifest = @ {
232+ Manifest = [ordered ]@ {
233+ Author = ' Nova Author'
234+ Description = ' Manifest description'
235+ }
236+ }
237+ $resolvedManifest = Get-NovaResolvedProjectManifestSettings - ProjectData $projectDataWithManifest
238+
239+ $resolvedManifest [' Author' ] | Should - Be ' Nova Author'
240+ $resolvedManifest [' Description' ] | Should - Be ' Manifest description'
241+ $resolvedManifest.GetType ().Name | Should - Be ' OrderedDictionary'
242+
243+ $resolvedManifest [' Author' ] = ' Changed'
244+ $projectDataWithManifest.Manifest.Author | Should - Be ' Nova Author'
245+
246+ (Get-NovaResolvedProjectManifestSettings - ProjectData @ {}).Count | Should - Be 0
247+ (Get-NovaResolvedProjectManifestSettings - ProjectData @ {Manifest = ' invalid' }).Count | Should - Be 0
248+ }
249+ }
250+
251+ It ' Get-NovaProjectPackageOutputDirectorySettingsTable returns dictionary copies and wraps scalar paths' {
252+ InModuleScope $script :moduleName {
253+ $dictionarySettings = [ordered ]@ {
254+ OutputDirectory = [ordered ]@ {
255+ Path = ' artifacts/packages'
256+ Clean = $true
257+ }
258+ }
259+ $resolvedDictionarySettings = Get-NovaProjectPackageOutputDirectorySettingsTable - PackageSettings $dictionarySettings
260+
261+ $resolvedDictionarySettings.Path | Should - Be ' artifacts/packages'
262+ $resolvedDictionarySettings.Clean | Should - BeTrue
263+ $resolvedDictionarySettings.GetType ().Name | Should - Be ' OrderedDictionary'
264+
265+ $resolvedDictionarySettings [' Path' ] = ' changed'
266+ $dictionarySettings.OutputDirectory.Path | Should - Be ' artifacts/packages'
267+
268+ $resolvedStringSettings = Get-NovaProjectPackageOutputDirectorySettingsTable - PackageSettings @ {OutputDirectory = ' dist/packages' }
269+ $resolvedStringSettings.Path | Should - Be ' dist/packages'
270+
271+ $resolvedMissingSettings = Get-NovaProjectPackageOutputDirectorySettingsTable - PackageSettings @ {}
272+ $resolvedMissingSettings.Path | Should - BeNullOrEmpty
273+ }
274+ }
275+
210276 It ' Test-ProjectSchema validates the Build schema' {
211277 InModuleScope $script :moduleName {
212278 Mock Get-ResourceFilePath {
@@ -385,11 +451,20 @@ Describe 'Coverage for remaining manifest, JSON, and help-locale helpers' {
385451 It ' Get-NovaPackageAuthorList normalizes string and enumerable author values' {
386452 InModuleScope $script :moduleName {
387453 @ (Get-NovaPackageAuthorList - AuthorValue $null ) | Should - Be @ ()
454+ @ (Get-NovaPackageAuthorList - AuthorValue ' ' ) | Should - Be @ ()
388455 @ (Get-NovaPackageAuthorList - AuthorValue ' Nova Author ' ) | Should - Be @ (' Nova Author' )
389456 @ (Get-NovaPackageAuthorList - AuthorValue @ (' Author A ' , ' Author B' , ' Author A' , ' ' )) | Should - Be @ (' Author A' , ' Author B' )
390457 }
391458 }
392459
460+ It ' Get-NovaManifestValue reads dictionaries, objects, and returns null for missing object properties' {
461+ InModuleScope $script :moduleName {
462+ Get-NovaManifestValue - Manifest @ {Author = ' Dictionary Author' } - Name ' Author' | Should - Be ' Dictionary Author'
463+ Get-NovaManifestValue - Manifest ([pscustomobject ]@ {Author = ' Object Author' }) - Name ' Author' | Should - Be ' Object Author'
464+ Get-NovaManifestValue - Manifest ([pscustomobject ]@ {Author = ' Object Author' }) - Name ' Tags' | Should - BeNullOrEmpty
465+ }
466+ }
467+
393468 It ' Get-NovaPackageAuthorList rejects unsupported author value types' {
394469 InModuleScope $script :moduleName {
395470 $thrown = $null
@@ -575,7 +650,7 @@ Describe 'Coverage for remaining manifest, JSON, and help-locale helpers' {
575650 Get-NovaPackageArtifactType - PackagePath ' /tmp/Nova.Package.nupkg' | Should - Be ' NuGet'
576651 Get-NovaPackageArtifactType - PackagePath ' /tmp/Nova.Package.zip' | Should - Be ' Zip'
577652
578- foreach ($packagePath in @ (' /tmp/Nova.Package' , ' /tmp/Nova.Package.tar.gz' )) {
653+ foreach ($packagePath in @ (' /tmp/package ' , ' /tmp/ Nova.Package' , ' /tmp/Nova.Package.tar.gz' )) {
579654 $thrown = $null
580655 try {
581656 Get-NovaPackageArtifactType - PackagePath $packagePath
@@ -590,6 +665,21 @@ Describe 'Coverage for remaining manifest, JSON, and help-locale helpers' {
590665 }
591666 }
592667
668+ It ' New-NovaPackageArtifacts returns an empty list when no package metadata was requested' {
669+ InModuleScope $script :moduleName {
670+ Mock Assert-NovaPackageMetadata {}
671+ Mock Initialize-NovaPackageOutputDirectory {}
672+ Mock New-NovaPackageArtifact {}
673+
674+ $result = @ (New-NovaPackageArtifacts - ProjectInfo ([pscustomobject ]@ {ProjectName = ' NovaModuleTools' }) - PackageMetadataList @ ())
675+
676+ $result | Should - Be @ ()
677+ Assert-MockCalled Assert-NovaPackageMetadata - Times 0
678+ Assert-MockCalled Initialize-NovaPackageOutputDirectory - Times 0
679+ Assert-MockCalled New-NovaPackageArtifact - Times 0
680+ }
681+ }
682+
593683 It ' Get-NovaPackageOutputDirectory returns rooted paths unchanged and resolves relative paths from the project root' {
594684 InModuleScope $script :moduleName {
595685 $relativeProject = [pscustomobject ]@ {ProjectRoot = ' /tmp/project' ; Package = [pscustomobject ]@ {OutputDirectory = [pscustomobject ]@ {Path = ' artifacts/packages' }}}
0 commit comments