Skip to content

Commit e03dce0

Browse files
committed
Add support for @(InternalsVisibleTo) items that turn into assembly attributes
Given that `InternalsVisibleTo` (IVT) is such a common assembly-level attribute, this adds support for specifying it directly via simple items, such as: ``` <ItemGroup> <InternalsVisibleTo Include="MyLibrary.Tests" /> </ItemGroup> ``` Optionally, a `Key` metadata can be specified to provide a strong-named IVT: ``` <ItemGroup> <InternalsVisibleTo Include="MyLibrary.Tests" Key="PUBLIC_KEY" /> </ItemGroup> ``` The targets will also use automatically a `$(PublicKey)` if available and no `%(Key)` metadata override is found. Otherwise, it will default to an IVT without a key. This also avoids having to learn the `_Parameter1` syntax in `AssemblyAttribute` elements, and is more similar to the way other higher-level properties like `AssemblyTitle` or `Product` are also turned into assembly attributes. To turn off this feature, set `$(GenerateInternalsVisibleToAttributes)` to `false`. Partially fixes #3166
1 parent b07b215 commit e03dce0

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.GenerateAssemblyInfo.targets

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Copyright (c) .NET Foundation. All rights reserved.
3434
<GenerateAssemblyVersionAttribute Condition="'$(GenerateAssemblyVersionAttribute)' == ''">true</GenerateAssemblyVersionAttribute>
3535
<GenerateNeutralResourcesLanguageAttribute Condition="'$(GenerateNeutralResourcesLanguageAttribute)' == ''">true</GenerateNeutralResourcesLanguageAttribute>
3636
<IncludeSourceRevisionInInformationalVersion Condition="'$(IncludeSourceRevisionInInformationalVersion)' == ''">true</IncludeSourceRevisionInInformationalVersion>
37+
<GenerateInternalsVisibleToAttributes Condition="'$(GenerateInternalsVisibleToAttributes)' == ''">true</GenerateInternalsVisibleToAttributes>
3738
</PropertyGroup>
3839

3940
<!--
@@ -94,6 +95,11 @@ Copyright (c) .NET Foundation. All rights reserved.
9495
<AssemblyAttribute Include="System.Resources.NeutralResourcesLanguageAttribute" Condition="'$(NeutralLanguage)' != '' and '$(GenerateNeutralResourcesLanguageAttribute)' == 'true'">
9596
<_Parameter1>$(NeutralLanguage)</_Parameter1>
9697
</AssemblyAttribute>
98+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo" Condition="%(InternalsVisibleTo.Identity) != '' and '$(GenerateInternalsVisibleToAttributes)' == 'true'">
99+
<_Parameter1 Condition="'%(InternalsVisibleTo.Key)' != ''">%(InternalsVisibleTo.Identity), PublicKey=%(InternalsVisibleTo.Key)</_Parameter1>
100+
<_Parameter1 Condition="'%(InternalsVisibleTo.Key)' == '' and '$(PublicKey)' != ''">%(InternalsVisibleTo.Identity), PublicKey=$(PublicKey)</_Parameter1>
101+
<_Parameter1 Condition="'%(InternalsVisibleTo.Key)' == '' and '$(PublicKey)' == ''">%(InternalsVisibleTo.Identity)</_Parameter1>
102+
</AssemblyAttribute>
97103
</ItemGroup>
98104
</Target>
99105

src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToControlGeneratedAssemblyInfo.cs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Xunit.Abstractions;
1414
using Microsoft.NET.TestFramework.ProjectConstruction;
1515
using System.Xml.Linq;
16+
using Xunit.Sdk;
1617

1718
namespace Microsoft.NET.Build.Tests
1819
{
@@ -362,5 +363,118 @@ BuildCommand BuildProject(string buildNumber)
362363
return command;
363364
}
364365
}
366+
367+
[Fact]
368+
public void It_includes_internals_visible_to()
369+
{
370+
var testAsset = _testAssetsManager
371+
.CopyTestAsset("HelloWorld")
372+
.WithSource()
373+
.WithTargetFramework("netstandard2.0")
374+
.WithProjectChanges((path, project) =>
375+
{
376+
var ns = project.Root.Name.Namespace;
377+
378+
project.Root.Add(
379+
new XElement(ns + "ItemGroup",
380+
new XElement(ns + "InternalsVisibleTo",
381+
new XAttribute("Include", "Tests"))));
382+
});
383+
384+
new RestoreCommand(Log, testAsset.TestRoot).Execute().Should().Pass();
385+
386+
var buildCommand = new BuildCommand(Log, testAsset.TestRoot);
387+
buildCommand.Execute().Should().Pass();
388+
389+
var assemblyPath = Path.Combine(buildCommand.GetOutputDirectory("netstandard2.0").FullName, "HelloWorld.dll");
390+
391+
AssemblyInfo.Get(assemblyPath)["InternalsVisibleToAttribute"].Should().Be("Tests");
392+
}
393+
394+
[Fact]
395+
public void It_respects_out_out_of_internals_visible_to()
396+
{
397+
var testAsset = _testAssetsManager
398+
.CopyTestAsset("HelloWorld")
399+
.WithSource()
400+
.WithTargetFramework("netstandard2.0")
401+
.WithProjectChanges((path, project) =>
402+
{
403+
var ns = project.Root.Name.Namespace;
404+
405+
project.Root.Add(
406+
new XElement(ns + "PropertyGroup",
407+
new XElement(ns + "GenerateInternalsVisibleToAttributes", "false")),
408+
new XElement(ns + "ItemGroup",
409+
new XElement(ns + "InternalsVisibleTo",
410+
new XAttribute("Include", "Tests"))));
411+
});
412+
413+
new RestoreCommand(Log, testAsset.TestRoot).Execute().Should().Pass();
414+
415+
var buildCommand = new BuildCommand(Log, testAsset.TestRoot);
416+
buildCommand.Execute().Should().Pass();
417+
418+
var assemblyPath = Path.Combine(buildCommand.GetOutputDirectory("netstandard2.0").FullName, "HelloWorld.dll");
419+
420+
Assert.False(AssemblyInfo.Get(assemblyPath).ContainsKey("InternalsVisibleToAttribute"));
421+
}
422+
423+
[Fact]
424+
public void It_includes_internals_visible_to_with_key()
425+
{
426+
var testAsset = _testAssetsManager
427+
.CopyTestAsset("HelloWorld")
428+
.WithSource()
429+
.WithTargetFramework("netstandard2.0")
430+
.WithProjectChanges((path, project) =>
431+
{
432+
var ns = project.Root.Name.Namespace;
433+
434+
project.Root.Add(
435+
new XElement(ns + "ItemGroup",
436+
new XElement(ns + "InternalsVisibleTo",
437+
new XAttribute("Include", "Tests"),
438+
new XAttribute("Key", "00240000048000009400000006020000002400005253413100040000010001001d3e6bbb36e11ea61ceff6e1022b23dd779fc6230838db2d25a2c7c8433b3fcf86b16c25b281fc3db1027c0675395e7d0548e6add88b6a811962bf958101fa9e243b1618313bee11f5e3b3fefda7b1d1226311b6cc2d07e87ff893ba6890b20082df34a0aac14b605b8be055e81081a626f8c69e9ed4bbaa4eae9f94a35accd2"))));
439+
});
440+
441+
new RestoreCommand(Log, testAsset.TestRoot).Execute().Should().Pass();
442+
443+
var buildCommand = new BuildCommand(Log, testAsset.TestRoot);
444+
buildCommand.Execute().Should().Pass();
445+
446+
var assemblyPath = Path.Combine(buildCommand.GetOutputDirectory("netstandard2.0").FullName, "HelloWorld.dll");
447+
448+
AssemblyInfo.Get(assemblyPath)["InternalsVisibleToAttribute"].Should().Be("Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001001d3e6bbb36e11ea61ceff6e1022b23dd779fc6230838db2d25a2c7c8433b3fcf86b16c25b281fc3db1027c0675395e7d0548e6add88b6a811962bf958101fa9e243b1618313bee11f5e3b3fefda7b1d1226311b6cc2d07e87ff893ba6890b20082df34a0aac14b605b8be055e81081a626f8c69e9ed4bbaa4eae9f94a35accd2");
449+
}
450+
451+
[Fact]
452+
public void It_includes_internals_visible_to_with_project_publickey()
453+
{
454+
var testAsset = _testAssetsManager
455+
.CopyTestAsset("HelloWorld")
456+
.WithSource()
457+
.WithTargetFramework("netstandard2.0")
458+
.WithProjectChanges((path, project) =>
459+
{
460+
var ns = project.Root.Name.Namespace;
461+
462+
project.Root.Add(
463+
new XElement(ns + "PropertyGroup",
464+
new XElement(ns + "PublicKey", "00240000048000009400000006020000002400005253413100040000010001001d3e6bbb36e11ea61ceff6e1022b23dd779fc6230838db2d25a2c7c8433b3fcf86b16c25b281fc3db1027c0675395e7d0548e6add88b6a811962bf958101fa9e243b1618313bee11f5e3b3fefda7b1d1226311b6cc2d07e87ff893ba6890b20082df34a0aac14b605b8be055e81081a626f8c69e9ed4bbaa4eae9f94a35accd2")),
465+
new XElement(ns + "ItemGroup",
466+
new XElement(ns + "InternalsVisibleTo",
467+
new XAttribute("Include", "Tests"))));
468+
});
469+
470+
new RestoreCommand(Log, testAsset.TestRoot).Execute().Should().Pass();
471+
472+
var buildCommand = new BuildCommand(Log, testAsset.TestRoot);
473+
buildCommand.Execute().Should().Pass();
474+
475+
var assemblyPath = Path.Combine(buildCommand.GetOutputDirectory("netstandard2.0").FullName, "HelloWorld.dll");
476+
477+
AssemblyInfo.Get(assemblyPath)["InternalsVisibleToAttribute"].Should().Be("Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001001d3e6bbb36e11ea61ceff6e1022b23dd779fc6230838db2d25a2c7c8433b3fcf86b16c25b281fc3db1027c0675395e7d0548e6add88b6a811962bf958101fa9e243b1618313bee11f5e3b3fefda7b1d1226311b6cc2d07e87ff893ba6890b20082df34a0aac14b605b8be055e81081a626f8c69e9ed4bbaa4eae9f94a35accd2");
478+
}
365479
}
366480
}

0 commit comments

Comments
 (0)