1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
+ using System . Diagnostics . CodeAnalysis ;
4
5
using System . IO . Compression ;
6
+ using NuGet . Packaging ;
7
+ using NuGet . Packaging . Core ;
5
8
6
9
namespace Microsoft . DotNet . PackageInstall . Tests
7
10
{
@@ -312,35 +315,116 @@ .. expectedRids.Select(rid => $"{toolSettings.ToolPackageId}.{rid}.{toolSettings
312
315
. And . HaveStdOutContaining ( "Hello Tool!" ) ;
313
316
}
314
317
315
- private void EnsurePackageIsFdd ( string packagePath )
318
+ [ Fact ]
319
+ public void StripsPackageTypesFromInnerToolPackages ( )
320
+ {
321
+ var toolSettings = new TestToolBuilder . TestToolSettings ( )
322
+ {
323
+ RidSpecific = true ,
324
+ AdditionalPackageTypes = [ "TestPackageType" ]
325
+ } ;
326
+ string toolPackagesPath = ToolBuilder . CreateTestTool ( Log , toolSettings , collectBinlogs : true ) ;
327
+
328
+ var packages = Directory . GetFiles ( toolPackagesPath , "*.nupkg" ) ;
329
+ var packageIdentifier = toolSettings . ToolPackageId ;
330
+ var expectedRids = ToolsetInfo . LatestRuntimeIdentifiers . Split ( ';' ) ;
331
+
332
+ packages . Length . Should ( ) . Be ( expectedRids . Length + 1 , "There should be one package for the tool-wrapper and one for each RID" ) ;
333
+ foreach ( string rid in expectedRids )
334
+ {
335
+ var packageName = $ "{ toolSettings . ToolPackageId } .{ rid } .{ toolSettings . ToolPackageVersion } ";
336
+ var package = packages . FirstOrDefault ( p => p . EndsWith ( packageName + ".nupkg" ) ) ;
337
+ package . Should ( )
338
+ . NotBeNull ( $ "Package { packageName } should be present in the tool packages directory")
339
+ . And . Satisfy < string > ( EnsurePackageIsAnExecutable )
340
+ . And . Satisfy < string > ( EnsurePackageOnlyHasToolRidPackageType ) ;
341
+ }
342
+
343
+ // top-level package should declare all of the rids
344
+ var topLevelPackage = packages . First ( p => p . EndsWith ( $ "{ packageIdentifier } .{ toolSettings . ToolPackageVersion } .nupkg") ) ;
345
+ topLevelPackage . Should ( ) . NotBeNull ( $ "Package { packageIdentifier } .{ toolSettings . ToolPackageVersion } .nupkg should be present in the tool packages directory")
346
+ . And . Satisfy < string > ( EnsurePackageHasNoRunner )
347
+ . And . Satisfy < string > ( EnsurePackageHasToolPackageTypeAnd ( toolSettings . AdditionalPackageTypes ! ) ) ;
348
+ var foundRids = GetRidsInSettingsFile ( topLevelPackage ) ;
349
+ foundRids . Should ( ) . BeEquivalentTo ( expectedRids , "The top-level package should declare all of the RIDs for the tools it contains" ) ;
350
+ }
351
+
352
+ private Action < string > EnsurePackageHasToolPackageTypeAnd ( string [ ] additionalPackageTypes ) => ( string packagePath ) =>
353
+ {
354
+ var nuspec = GetPackageNuspec ( packagePath ) ;
355
+ var packageTypes = nuspec . GetPackageTypes ( ) ;
356
+ PackageType [ ] expectedPackageTypes = [ new PackageType ( "DotnetTool" , PackageType . EmptyVersion ) , .. additionalPackageTypes . Select ( t => new PackageType ( t , PackageType . EmptyVersion ) ) ] ;
357
+ packageTypes . Should ( ) . NotBeNull ( "The PackageType element should not be null." )
358
+ . And . HaveCount ( 1 + additionalPackageTypes . Length , "The package should have a PackageType element for each additional type." )
359
+ . And . BeEquivalentTo ( expectedPackageTypes , "The PackageType should be 'DotnetTool'." ) ;
360
+ } ;
361
+
362
+ static void EnsurePackageOnlyHasToolRidPackageType ( string packagePath )
363
+ {
364
+ var nuspec = GetPackageNuspec ( packagePath ) ;
365
+ var packageTypes = nuspec . GetPackageTypes ( ) ;
366
+ packageTypes . Should ( ) . NotBeNull ( "The PackageType element should not be null." )
367
+ . And . HaveCount ( 1 , "The package should only have a single PackageType element." )
368
+ . And . Contain ( new PackageType ( "DotnetToolRidPackage" , PackageType . EmptyVersion ) , "The PackageType should be 'DotnetToolRidPackage'." ) ;
369
+ }
370
+
371
+ private static NuspecReader GetPackageNuspec ( string packagePath )
372
+ {
373
+ using var zipArchive = ZipFile . OpenRead ( packagePath ) ;
374
+ var nuspecEntry = zipArchive . Entries . First ( e => e . Name . EndsWith ( "nuspec" ) ! ) ;
375
+ var stream = nuspecEntry . Open ( ) ;
376
+ return new NuspecReader ( stream ) ;
377
+ }
378
+
379
+ static void EnsurePackageIsFdd ( string packagePath )
316
380
{
317
381
var settingsXml = GetToolSettingsFile ( packagePath ) ;
318
382
var runner = GetRunnerFromSettingsFile ( settingsXml ) ;
319
383
runner . Should ( ) . Be ( "dotnet" , "The tool should be packaged as a framework-dependent executable (FDD) with a 'dotnet' runner." ) ;
320
384
}
321
385
322
- private void EnsurePackageIsAnExecutable ( string packagePath )
386
+ static void EnsurePackageHasNoRunner ( string packagePath )
387
+ {
388
+ var settingsXml = GetToolSettingsFile ( packagePath ) ;
389
+ if ( TryGetRunnerFromSettingsFile ( settingsXml , out _ ) )
390
+ {
391
+ throw new Exception ( "The tool settings file should not contain a 'Runner' attribute." ) ;
392
+ }
393
+ }
394
+
395
+ static void EnsurePackageIsAnExecutable ( string packagePath )
323
396
{
324
397
var settingsXml = GetToolSettingsFile ( packagePath ) ;
325
398
var runner = GetRunnerFromSettingsFile ( settingsXml ) ;
326
399
runner . Should ( ) . Be ( "executable" , "The tool should be packaged as a executable with an 'executable' runner." ) ;
327
400
}
328
401
329
- private object GetRunnerFromSettingsFile ( XElement settingsXml )
402
+ static string GetRunnerFromSettingsFile ( XElement settingsXml )
403
+ {
404
+ if ( TryGetRunnerFromSettingsFile ( settingsXml , out string ? runner ) )
405
+ {
406
+ return runner ;
407
+ } else
408
+ {
409
+ throw new InvalidOperationException ( "The tool settings file does not contain a 'Runner' attribute." ) ;
410
+ }
411
+ }
412
+ static bool TryGetRunnerFromSettingsFile ( XElement settingsXml , [ NotNullWhen ( true ) ] out string ? runner )
330
413
{
331
- return settingsXml . Elements ( "Commands" ) . First ( ) . Elements ( "Command" ) . First ( ) . Attribute ( "Runner" ) ? . Value
332
- ?? throw new InvalidOperationException ( "The tool settings file does not contain a 'Runner' attribute." ) ;
414
+ var commandNode = settingsXml . Elements ( "Commands" ) . First ( ) . Elements ( "Command" ) . First ( ) ;
415
+ runner = commandNode . Attributes ( ) . FirstOrDefault ( a => a . Name == "Runner" ) ? . Value ;
416
+ return runner is not null ;
333
417
}
334
418
335
- private string [ ] GetRidsInSettingsFile ( string packagePath )
419
+ static string [ ] GetRidsInSettingsFile ( string packagePath )
336
420
{
337
421
var settingsXml = GetToolSettingsFile ( packagePath ) ;
338
422
var rids = GetRidsInSettingsFile ( settingsXml ) ;
339
423
rids . Should ( ) . NotBeEmpty ( "The tool settings file should contain at least one RuntimeIdentifierPackage element." ) ;
340
424
return rids ;
341
425
}
342
426
343
- private string [ ] GetRidsInSettingsFile ( XElement settingsXml )
427
+ static string [ ] GetRidsInSettingsFile ( XElement settingsXml )
344
428
{
345
429
var nodes = ( settingsXml . Nodes ( )
346
430
. First ( n => n is XElement e && e . Name == "RuntimeIdentifierPackages" ) as XElement ) ! . Nodes ( )
@@ -350,7 +434,7 @@ private string[] GetRidsInSettingsFile(XElement settingsXml)
350
434
return nodes ;
351
435
}
352
436
353
- private XElement GetToolSettingsFile ( string packagePath )
437
+ static XElement GetToolSettingsFile ( string packagePath )
354
438
{
355
439
using var zipArchive = ZipFile . OpenRead ( packagePath ) ;
356
440
var nuspecEntry = zipArchive . Entries . First ( e => e . Name == "DotnetToolSettings.xml" ) ! ;
@@ -363,7 +447,7 @@ private XElement GetToolSettingsFile(string packagePath)
363
447
/// <summary>
364
448
/// Opens the nupkg and verifies that it does not contain a dependency on the given dll.
365
449
/// </summary>
366
- private void EnsurePackageLacksTrimmedDependency ( string packagePath , string dll )
450
+ static void EnsurePackageLacksTrimmedDependency ( string packagePath , string dll )
367
451
{
368
452
using var zipArchive = ZipFile . OpenRead ( packagePath ) ;
369
453
zipArchive . Entries . Should ( ) . NotContain (
0 commit comments