MsBuildFileSetFactoryTest.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. using Microsoft.DotNet.Watcher.Internal;
  4. using Microsoft.Extensions.Tools.Internal;
  5. namespace Microsoft.DotNet.Watcher.Tools
  6. {
  7. public class MsBuildFileSetFactoryTest
  8. {
  9. private readonly IReporter _reporter;
  10. private readonly TestAssetsManager _testAssets;
  11. private readonly string _muxerPath;
  12. public MsBuildFileSetFactoryTest(ITestOutputHelper output)
  13. {
  14. _reporter = new TestReporter(output);
  15. _testAssets = new TestAssetsManager(output);
  16. _muxerPath = TestContext.Current.ToolsetUnderTest.DotNetHostPath;
  17. }
  18. [Fact]
  19. public async Task FindsCustomWatchItems()
  20. {
  21. var project = _testAssets.CreateTestProject(new TestProject("Project1")
  22. {
  23. TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
  24. });
  25. project.WithProjectChanges(d => d.Root.Add(XElement.Parse(
  26. @"<ItemGroup>
  27. <Watch Include=""*.js"" Exclude=""gulpfile.js"" />
  28. </ItemGroup>")));
  29. WriteFile(project, "Program.cs");
  30. WriteFile(project, "app.js");
  31. WriteFile(project, "gulpfile.js");
  32. var fileset = await GetFileSet(project);
  33. AssertEx.EqualFileList(
  34. GetTestProjectDirectory(project),
  35. new[]
  36. {
  37. "Project1.csproj",
  38. "Project1.cs",
  39. "Program.cs",
  40. "app.js"
  41. },
  42. fileset
  43. );
  44. }
  45. [Fact]
  46. public async Task ExcludesDefaultItemsWithWatchFalseMetadata()
  47. {
  48. var project = _testAssets.CreateTestProject(new TestProject("Project1")
  49. {
  50. TargetFrameworks = "net40",
  51. AdditionalProperties =
  52. {
  53. ["EnableDefaultEmbeddedResourceItems"] = "false",
  54. },
  55. });
  56. project.WithProjectChanges(d => d.Root.Add(XElement.Parse(
  57. @"<ItemGroup>
  58. <EmbeddedResource Include=""*.resx"" Watch=""false"" />
  59. </ItemGroup>")));
  60. WriteFile(project, "Program.cs");
  61. WriteFile(project, "Strings.resx");
  62. var fileset = await GetFileSet(project);
  63. AssertEx.EqualFileList(
  64. GetTestProjectDirectory(project),
  65. new[]
  66. {
  67. "Project1.csproj",
  68. "Project1.cs",
  69. "Program.cs",
  70. },
  71. fileset
  72. );
  73. }
  74. [Fact]
  75. public async Task SingleTfm()
  76. {
  77. var project = _testAssets.CreateTestProject(new TestProject("Project1")
  78. {
  79. TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
  80. AdditionalProperties =
  81. {
  82. ["BaseIntermediateOutputPath"] = "obj",
  83. },
  84. });
  85. WriteFile(project, "Program.cs");
  86. WriteFile(project, "Class1.cs");
  87. WriteFile(project, Path.Combine("obj", "Class1.cs"));
  88. WriteFile(project, Path.Combine("Properties", "Strings.resx"));
  89. var fileset = await GetFileSet(project);
  90. AssertEx.EqualFileList(
  91. GetTestProjectDirectory(project),
  92. new[]
  93. {
  94. "Project1.csproj",
  95. "Project1.cs",
  96. "Program.cs",
  97. "Class1.cs",
  98. "Properties/Strings.resx",
  99. },
  100. fileset
  101. );
  102. }
  103. [Fact]
  104. public async Task MultiTfm()
  105. {
  106. var project = _testAssets.CreateTestProject(new TestProject("Project1")
  107. {
  108. TargetFrameworks = $"{ToolsetInfo.CurrentTargetFramework};net462",
  109. AdditionalProperties =
  110. {
  111. ["EnableDefaultCompileItems"] = "false",
  112. },
  113. });
  114. project.WithProjectChanges(d => d.Root.Add(XElement.Parse(
  115. $@"<ItemGroup>
  116. <Compile Include=""Class1.netcore.cs"" Condition=""'$(TargetFramework)'=='{ToolsetInfo.CurrentTargetFramework}'"" />
  117. <Compile Include=""Class1.desktop.cs"" Condition=""'$(TargetFramework)'=='net462'"" />
  118. </ItemGroup>")));
  119. WriteFile(project, "Class1.netcore.cs");
  120. WriteFile(project, "Class1.desktop.cs");
  121. WriteFile(project, "Class1.notincluded.cs");
  122. var fileset = await GetFileSet(project);
  123. AssertEx.EqualFileList(
  124. GetTestProjectDirectory(project),
  125. new[]
  126. {
  127. "Project1.csproj",
  128. "Class1.netcore.cs",
  129. "Class1.desktop.cs",
  130. },
  131. fileset
  132. );
  133. }
  134. [Fact]
  135. public async Task IncludesContentFiles()
  136. {
  137. var testDir = _testAssets.CreateTestDirectory();
  138. var project = WriteFile(testDir, Path.Combine("Project1.csproj"),
  139. @"<Project Sdk=""Microsoft.NET.Sdk.Web"">
  140. <PropertyGroup>
  141. <TargetFramework>netstandard2.1</TargetFramework>
  142. </PropertyGroup>
  143. </Project>");
  144. WriteFile(testDir, Path.Combine("Program.cs"));
  145. WriteFile(testDir, Path.Combine("wwwroot", "css", "app.css"));
  146. WriteFile(testDir, Path.Combine("wwwroot", "js", "site.js"));
  147. WriteFile(testDir, Path.Combine("wwwroot", "favicon.ico"));
  148. var fileset = await GetFileSet(project);
  149. AssertEx.EqualFileList(
  150. testDir.Path,
  151. new[]
  152. {
  153. "Project1.csproj",
  154. "Program.cs",
  155. "wwwroot/css/app.css",
  156. "wwwroot/js/site.js",
  157. "wwwroot/favicon.ico",
  158. },
  159. fileset
  160. );
  161. }
  162. [Fact]
  163. public async Task IncludesContentFilesFromRCL()
  164. {
  165. var testDir = _testAssets.CreateTestDirectory();
  166. WriteFile(testDir, Path.Combine("RCL1", "RCL1.csproj"),
  167. @"<Project Sdk=""Microsoft.NET.Sdk.Razor"">
  168. <PropertyGroup>
  169. <TargetFramework>netcoreapp5.0</TargetFramework>
  170. </PropertyGroup>
  171. </Project>
  172. ");
  173. WriteFile(testDir, Path.Combine("RCL1", "wwwroot", "css", "app.css"));
  174. WriteFile(testDir, Path.Combine("RCL1", "wwwroot", "js", "site.js"));
  175. WriteFile(testDir, Path.Combine("RCL1", "wwwroot", "favicon.ico"));
  176. var projectPath = WriteFile(testDir, Path.Combine("Project1", "Project1.csproj"),
  177. @"<Project Sdk=""Microsoft.NET.Sdk.Web"">
  178. <PropertyGroup>
  179. <TargetFramework>netstandard2.1</TargetFramework>
  180. </PropertyGroup>
  181. <ItemGroup>
  182. <ProjectReference Include=""..\RCL1\RCL1.csproj"" />
  183. </ItemGroup>
  184. </Project>");
  185. WriteFile(testDir, Path.Combine("Project1", "Program.cs"));
  186. var fileset = await GetFileSet(projectPath);
  187. AssertEx.EqualFileList(
  188. testDir.Path,
  189. new[]
  190. {
  191. "Project1/Project1.csproj",
  192. "Project1/Program.cs",
  193. "RCL1/RCL1.csproj",
  194. "RCL1/wwwroot/css/app.css",
  195. "RCL1/wwwroot/js/site.js",
  196. "RCL1/wwwroot/favicon.ico",
  197. },
  198. fileset
  199. );
  200. }
  201. [Fact]
  202. public async Task ProjectReferences_OneLevel()
  203. {
  204. var project2 = _testAssets.CreateTestProject(new TestProject("Project2")
  205. {
  206. TargetFrameworks = "netstandard2.1",
  207. });
  208. var project1 = _testAssets.CreateTestProject(new TestProject("Project1")
  209. {
  210. TargetFrameworks = $"{ToolsetInfo.CurrentTargetFramework};net462",
  211. ReferencedProjects = { project2.TestProject, },
  212. });
  213. var fileset = await GetFileSet(project1);
  214. AssertEx.EqualFileList(
  215. project1.TestRoot,
  216. new[]
  217. {
  218. "Project2/Project2.csproj",
  219. "Project2/Project2.cs",
  220. "Project1/Project1.csproj",
  221. "Project1/Project1.cs",
  222. },
  223. fileset
  224. );
  225. }
  226. [Fact]
  227. public async Task TransitiveProjectReferences_TwoLevels()
  228. {
  229. var project3 = _testAssets.CreateTestProject(new TestProject("Project3")
  230. {
  231. TargetFrameworks = "netstandard2.1",
  232. });
  233. var project2 = _testAssets.CreateTestProject(new TestProject("Project2")
  234. {
  235. TargetFrameworks = "netstandard2.1",
  236. ReferencedProjects = { project3.TestProject, },
  237. });
  238. var project1 = _testAssets.CreateTestProject(new TestProject("Project1")
  239. {
  240. TargetFrameworks = $"{ToolsetInfo.CurrentTargetFramework};net462",
  241. ReferencedProjects = { project2.TestProject, },
  242. });
  243. var fileset = await GetFileSet(project1);
  244. AssertEx.EqualFileList(
  245. project1.TestRoot,
  246. new[]
  247. {
  248. "Project3/Project3.csproj",
  249. "Project3/Project3.cs",
  250. "Project2/Project2.csproj",
  251. "Project2/Project2.cs",
  252. "Project1/Project1.csproj",
  253. "Project1/Project1.cs",
  254. },
  255. fileset
  256. );
  257. Assert.All(fileset, f => Assert.False(f.IsStaticFile, $"File {f.FilePath} should not be a static file."));
  258. }
  259. [Fact]
  260. public async Task ProjectReferences_Graph()
  261. {
  262. // A->B,F,W(Watch=False)
  263. // B->C,E
  264. // C->D
  265. // D->E
  266. // F->E,G
  267. // G->E
  268. // W->U
  269. // Y->B,F,Z
  270. var testDirectory = _testAssets.CopyTestAsset("ProjectReferences_Graph")
  271. .WithSource()
  272. .Path;
  273. var projectA = Path.Combine(testDirectory, "A", "A.csproj");
  274. var output = new OutputSink();
  275. var options = new EnvironmentOptions(
  276. MuxerPath: _muxerPath,
  277. WorkingDirectory: testDirectory);
  278. var filesetFactory = new MsBuildFileSetFactory(options, _reporter, projectA, targetFramework: null, buildProperties: null, output, trace: true);
  279. var result = await filesetFactory.TryCreateAsync(CancellationToken.None);
  280. Assert.NotNull(result);
  281. _reporter.Output(string.Join(
  282. Environment.NewLine,
  283. output.Current.Lines.Select(l => "Sink output: " + l)));
  284. var includedProjects = new[] { "A", "B", "C", "D", "E", "F", "G" };
  285. AssertEx.EqualFileList(
  286. testDirectory,
  287. includedProjects
  288. .Select(p => $"{p}/{p}.csproj"),
  289. result.Value.files
  290. );
  291. // ensure each project is only visited once for collecting watch items
  292. Assert.All(includedProjects,
  293. projectName =>
  294. Assert.Single(output.Current.Lines,
  295. line => line.Contains($"Collecting watch items from '{projectName}'"))
  296. );
  297. }
  298. private Task<FileSet> GetFileSet(TestAsset target)
  299. {
  300. var projectPath = GetTestProjectPath(target);
  301. return GetFileSet(projectPath);
  302. }
  303. private async Task<FileSet> GetFileSet(string projectPath)
  304. {
  305. var options = new EnvironmentOptions(
  306. MuxerPath: _muxerPath,
  307. WorkingDirectory: Path.GetDirectoryName(projectPath));
  308. var factory = new MsBuildFileSetFactory(options, _reporter, projectPath, targetFramework: null, buildProperties: null, new OutputSink(), trace: false);
  309. var result = await factory.TryCreateAsync(CancellationToken.None);
  310. return result.Value.files;
  311. }
  312. private static string GetTestProjectPath(TestAsset target) => Path.Combine(GetTestProjectDirectory(target), target.TestProject.Name + ".csproj");
  313. private static string WriteFile(TestAsset testAsset, string name, string contents = "")
  314. {
  315. var path = Path.Combine(GetTestProjectDirectory(testAsset), name);
  316. Directory.CreateDirectory(Path.GetDirectoryName(path));
  317. File.WriteAllText(path, contents);
  318. return path;
  319. }
  320. private static string WriteFile(TestDirectory testAsset, string name, string contents = "")
  321. {
  322. var path = Path.Combine(testAsset.Path, name);
  323. Directory.CreateDirectory(Path.GetDirectoryName(path));
  324. File.WriteAllText(path, contents);
  325. return path;
  326. }
  327. private static string GetTestProjectDirectory(TestAsset testAsset)
  328. => Path.Combine(testAsset.Path, testAsset.TestProject.Name);
  329. }
  330. }