1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Xunit;
using Xunit.Abstractions;
namespace ILLink.Tests
{
public class IntegrationTestBase
{
protected readonly ITestOutputHelper output;
protected readonly TestContext context;
public IntegrationTestBase(ITestOutputHelper output)
{
this.output = output;
// This sets up the context with some values specific to
// the setup of the linker repository. A different context
// should be used in order to run tests in a different
// environment.
this.context = TestContext.CreateDefaultContext();
}
protected int Dotnet(string args, string workingDir, string additionalPath = null)
{
return RunCommand(Path.GetFullPath(context.DotnetToolPath), args,
workingDir, additionalPath, out string commandOutput);
}
protected int RunCommand(string command, string args, int timeout = Int32.MaxValue)
{
return RunCommand(command, args, null, null, out string commandOutput, timeout);
}
protected int RunCommand(string command, string args, string workingDir)
{
return RunCommand(command, args, workingDir, null, out string commandOutput);
}
protected int RunCommand(string command, string args, string workingDir, string additionalPath,
out string commandOutput, int timeout = Int32.MaxValue, string terminatingOutput = null)
{
return (new CommandRunner(command, output))
.WithArguments(args)
.WithWorkingDir(workingDir)
.WithAdditionalPath(additionalPath)
.WithTimeout(timeout)
.WithTerminatingOutput(terminatingOutput)
.Run(out commandOutput);
}
/// <summary>
/// Run the linker on the specified project. This assumes
/// that the project already contains a reference to the
/// linker task package.
/// Optionally takes a list of root descriptor files.
/// Returns the path to the built app, either the renamed
/// host for self-contained publish, or the dll containing
/// the entry point.
/// </summary>
public string BuildAndLink(string csproj, List<string> rootFiles = null, Dictionary<string, string> extraPublishArgs = null, bool selfContained = false)
{
string demoRoot = Path.GetDirectoryName(csproj);
string publishArgs = $"publish -c {context.Configuration} /v:n /p:ShowLinkerSizeComparison=true";
if (selfContained) {
publishArgs += $" -r {context.RuntimeIdentifier}";
}
string rootFilesStr;
if (rootFiles != null && rootFiles.Any()) {
rootFilesStr = String.Join(";", rootFiles);
publishArgs += $" /p:LinkerRootDescriptors={rootFilesStr}";
}
if (extraPublishArgs != null) {
foreach (var item in extraPublishArgs) {
publishArgs += $" /p:{item.Key}={item.Value}";
}
}
int ret = Dotnet(publishArgs, demoRoot);
if (ret != 0) {
output.WriteLine("publish failed, returning " + ret);
Assert.True(false);
}
// detect the target framework for which the app was published
string tfmDir = Path.Combine(demoRoot, "bin", context.Configuration);
string tfm = Directory.GetDirectories(tfmDir).Select(p => Path.GetFileName(p)).Single();
string builtApp = Path.Combine(tfmDir, tfm);
if (selfContained) {
builtApp = Path.Combine(builtApp, context.RuntimeIdentifier);
}
builtApp = Path.Combine(builtApp, "publish",
Path.GetFileNameWithoutExtension(csproj));
if (selfContained) {
if (context.RuntimeIdentifier.Contains("win")) {
builtApp += ".exe";
}
} else {
builtApp += ".dll";
}
Assert.True(File.Exists(builtApp));
return builtApp;
}
public int RunApp(string target, out string processOutput, int timeout = Int32.MaxValue,
string terminatingOutput = null, bool selfContained = false)
{
Assert.True(File.Exists(target));
int ret;
if (selfContained) {
ret = RunCommand(
target, null,
Directory.GetParent(target).FullName,
null, out processOutput, timeout, terminatingOutput);
} else {
ret = RunCommand(
Path.GetFullPath(context.DotnetToolPath),
Path.GetFullPath(target),
Directory.GetParent(target).FullName,
null, out processOutput, timeout, terminatingOutput);
}
return ret;
}
protected void AddLinkerReference(string csproj)
{
var xdoc = XDocument.Load(csproj);
var ns = xdoc.Root.GetDefaultNamespace();
bool added = false;
foreach (var el in xdoc.Root.Elements(ns + "ItemGroup")) {
if (el.Elements(ns + "PackageReference").Any()) {
el.Add(new XElement(ns+"PackageReference",
new XAttribute("Include", context.TasksPackageName),
new XAttribute("Version", context.TasksPackageVersion)));
added = true;
break;
}
}
if (!added) {
xdoc.Root.Add(new XElement(ns + "ItemGroup",
new XElement(ns + "PackageReference",
new XAttribute("Include", context.TasksPackageName),
new XAttribute("Version", context.TasksPackageVersion))));
added= true;
}
using (var fs = new FileStream(csproj, FileMode.Create)) {
xdoc.Save(fs);
}
}
static void AddLinkerRoots(string csproj, List<string> rootFiles)
{
var xdoc = XDocument.Load(csproj);
var ns = xdoc.Root.GetDefaultNamespace();
var rootsItemGroup = new XElement(ns+"ItemGroup");
foreach (var rootFile in rootFiles) {
rootsItemGroup.Add(new XElement(ns+"LinkerRootFiles",
new XAttribute("Include", rootFile)));
}
var propertyGroup = xdoc.Root.Elements(ns + "PropertyGroup").First();
propertyGroup.AddAfterSelf(rootsItemGroup);
using (var fs = new FileStream(csproj, FileMode.Create)) {
xdoc.Save(fs);
}
}
}
}
|