5 // Ankit Jain (jankit@novell.com)
7 // Copyright 2009 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using Microsoft.Build.BuildEngine;
31 using NUnit.Framework;
33 using System.Threading;
34 using Microsoft.Build.Tasks;
35 using Microsoft.Build.Framework;
36 using Microsoft.Build.Utilities;
38 namespace MonoTests.Microsoft.Build.Tasks {
41 public class CopyTest {
42 string source_path, target_path;
45 public void CreateDir ()
47 source_path = Path.Combine (Path.Combine ("Test", "resources"), "Copy");
48 Directory.CreateDirectory (source_path);
49 target_path = Path.Combine (Path.Combine ("Test", "resources"), "Target");
50 Directory.CreateDirectory (target_path);
54 public void RemoveDirectories ()
56 Directory.Delete (source_path, true);
57 Directory.Delete (target_path, true);
61 public void TestCopy_MissingSourceFile ()
63 Copy copy = new Copy ();
64 copy.BuildEngine = new TestEngine ();
65 copy.SourceFiles = new ITaskItem [1];
66 copy.SourceFiles [0] = new TaskItem ("SourceDoesNotExist");
67 copy.DestinationFiles = new ITaskItem [1];
68 copy.DestinationFiles [0] = new TaskItem ("DestDoesNotExist");
69 Assert.IsFalse (copy.Execute ());
73 public void TestCopy1 ()
77 string file_path = Path.Combine (source_path, "copy.txt");
78 string target_file = Path.Combine (target_path, "copy.txt");
80 using (File.CreateText (file_path)) { }
82 string documentString = @"
83 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
84 <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
86 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
87 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
90 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' SkipUnchangedFiles='true' >
91 <Output TaskParameter='CopiedFiles' ItemName='I0'/>
92 <Output TaskParameter='DestinationFiles' ItemName='I1'/>
94 <Message Text=""I0 : @(I0), I1: @(I1)""/>
99 engine = new Engine (Consts.BinPath);
100 project = engine.CreateNewProject ();
102 TestMessageLogger testLogger = new TestMessageLogger ();
103 engine.RegisterLogger (testLogger);
105 project.LoadXml (documentString);
107 if (!project.Build ("1")) {
108 var sb = new StringBuilder ();
109 testLogger.DumpMessages (sb);
110 Assert.Fail ("Build failed " + sb.ToString ());
112 Assert.IsTrue (File.Exists (target_file), "A2");
114 BuildItemGroup big = project.GetEvaluatedItemsByName ("I0");
115 Assert.AreEqual (1, big.Count, "A3");
116 BuildItem bi = big [0];
117 Assert.AreEqual (target_file, bi.FinalItemSpec, "A4");
118 Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A4");
119 Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A5");
121 big = project.GetEvaluatedItemsByName ("I1");
122 Assert.AreEqual (1, big.Count, "A10");
124 Assert.AreEqual (target_file, bi.FinalItemSpec, "A11");
125 Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A12");
126 Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A13");
128 // build again, this time files won't get copied because
129 // of SkipUnchangedFiles=true
130 if (!project.Build ("1")) {
131 testLogger.DumpMessages ();
132 Assert.Fail ("Build failed #2");
134 Assert.IsTrue (File.Exists (target_file), "A20");
136 big = project.GetEvaluatedItemsByName ("I0");
137 Assert.AreEqual (1, big.Count, "A21");
139 Assert.AreEqual (target_file, bi.FinalItemSpec, "A22");
140 Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A23");
141 Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A24");
143 big = project.GetEvaluatedItemsByName ("I1");
144 Assert.AreEqual (1, big.Count, "A25");
146 Assert.AreEqual (target_file, bi.FinalItemSpec, "A26");
147 Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A27");
148 Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A28");
152 public void TestCopy2 ()
156 string [] file_paths = new string [] {
157 Path.Combine (source_path, "copy1.txt"),
158 Path.Combine (source_path, "copy2.txt")
161 using (File.CreateText (file_paths[0])) { }
162 using (File.CreateText (file_paths[1])) { }
164 string documentString = @"
165 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
166 <PropertyGroup><TargetPath>" + target_path + @"</TargetPath></PropertyGroup>
168 <SFiles Include='" + file_paths [0] + @"'><Md>1</Md></SFiles>
169 <SFiles Include='" + file_paths [1] + @"'><Md>2</Md></SFiles>
172 <Copy SourceFiles='@(SFiles)' DestinationFolder='$(TargetPath)' SkipUnchangedFiles='true' >
173 <Output TaskParameter='CopiedFiles' ItemName='I0'/>
174 <Output TaskParameter='DestinationFiles' ItemName='I1'/>
179 engine = new Engine (Consts.BinPath);
180 project = engine.CreateNewProject ();
182 TestMessageLogger testLogger = new TestMessageLogger ();
183 engine.RegisterLogger (testLogger);
185 project.LoadXml (documentString);
187 if (!project.Build ("1")) {
188 testLogger.DumpMessages ();
189 Assert.Fail ("Build failed");
192 CheckCopyBuildItems (project, file_paths, target_path, "A1");
194 // build again, this time files won't get copied because
195 // of SkipUnchangedFiles=true
196 if (!project.Build ("1")) {
197 testLogger.DumpMessages ();
198 Assert.Fail ("Build failed #2");
200 CheckCopyBuildItems (project, file_paths, target_path, "A2");
204 public void TestCopy_EmptySources () {
208 string documentString = @"
209 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
211 <Copy SourceFiles='@(NonExistantSourceFiles)' DestinationFolder='$(TargetPath)' SkipUnchangedFiles='true' >
212 <Output TaskParameter='CopiedFiles' ItemName='I0'/>
213 <Output TaskParameter='DestinationFiles' ItemName='I1'/>
218 engine = new Engine (Consts.BinPath);
219 project = engine.CreateNewProject ();
221 TestMessageLogger testLogger = new TestMessageLogger ();
222 engine.RegisterLogger (testLogger);
224 project.LoadXml (documentString);
227 if (!project.Build ("1")) {
228 testLogger.DumpMessages ();
229 Assert.Fail ("Build failed");
234 public void TestCopy_EmptyDestFolder () {
238 string documentString = @"
239 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
241 <SFiles Include='foo.txt'><Md>1</Md></SFiles>
244 <Copy SourceFiles='@(SFiles)' DestinationFolder='@(NonExistant)' DestinationFiles='@(NonExistant)' SkipUnchangedFiles='true' >
245 <Output TaskParameter='CopiedFiles' ItemName='I0'/>
246 <Output TaskParameter='DestinationFiles' ItemName='I1'/>
251 engine = new Engine (Consts.BinPath);
252 project = engine.CreateNewProject ();
254 TestMessageLogger testLogger = new TestMessageLogger ();
255 engine.RegisterLogger (testLogger);
257 project.LoadXml (documentString);
258 if (project.Build ("1")) {
259 testLogger.DumpMessages ();
260 Assert.Fail ("Build should have failed");
265 public void TestCopy_ReadOnlyUpdate ()
269 string file_path = Path.Combine (source_path, "copyro.txt");
270 string target_file = Path.Combine (target_path, "copyro.txt");
272 using (File.CreateText (file_path)) { }
274 string documentString = @"
275 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
276 <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
278 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
279 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
282 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' >
283 <Output TaskParameter='CopiedFiles' ItemName='I0'/>
284 <Output TaskParameter='DestinationFiles' ItemName='I1'/>
286 <Message Text=""I0 : @(I0), I1: @(I1)""/>
291 engine = new Engine (Consts.BinPath);
292 project = engine.CreateNewProject ();
294 TestMessageLogger testLogger = new TestMessageLogger ();
295 engine.RegisterLogger (testLogger);
297 project.LoadXml (documentString);
299 if (!project.Build ("1")) {
300 testLogger.DumpMessages ();
301 Assert.Fail ("Build failed");
303 Assert.IsTrue (File.Exists (target_file), "A2");
304 if (Environment.OSVersion.Platform == PlatformID.Unix)
305 Assert.AreEqual (FileAttributes.Normal, File.GetAttributes (target_file), "A3");
307 // On Windows the Archive attribute will be set, not the Normal attribute.
308 Assert.AreEqual (FileAttributes.Archive, File.GetAttributes (target_file), "A3");
312 public void TestCopy_OverwriteReadOnlyTrue ()
316 string file_path = Path.Combine (source_path, "copyro1.txt");
317 string target_file = Path.Combine (target_path, "copyro1.txt");
319 using (File.CreateText (file_path)) { }
320 using (File.CreateText (target_file)) { }
322 File.SetAttributes (target_file, FileAttributes.ReadOnly);
323 Assert.AreEqual (FileAttributes.ReadOnly, File.GetAttributes (target_file), "A1");
325 string documentString = @"
326 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
327 <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
329 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
330 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
333 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' OverwriteReadOnlyFiles='true'>
334 <Output TaskParameter='CopiedFiles' ItemName='I0'/>
335 <Output TaskParameter='DestinationFiles' ItemName='I1'/>
337 <Message Text=""I0 : @(I0), I1: @(I1)""/>
342 engine = new Engine (Consts.BinPath);
343 project = engine.CreateNewProject ();
345 TestMessageLogger testLogger = new TestMessageLogger ();
346 engine.RegisterLogger (testLogger);
348 project.LoadXml (documentString);
350 if (!project.Build ("1")) {
351 var sb = new StringBuilder ();
352 testLogger.DumpMessages (sb);
353 Assert.Fail ("Build failed " + sb.ToString ());
355 Assert.IsTrue (File.Exists (target_file), "A2");
356 var target_file_attrs = File.GetAttributes (target_file);
357 if (Environment.OSVersion.Platform == PlatformID.Unix)
358 Assert.AreEqual (FileAttributes.Normal, File.GetAttributes (target_file), "A3");
360 // On Windows the Archive attribute will be set, not the Normal attribute.
361 Assert.AreEqual (FileAttributes.Archive, File.GetAttributes (target_file), "A3");
365 public void TestCopy_OverwriteReadOnlyFalse ()
369 string file_path = Path.Combine (source_path, "copyro2.txt");
370 string target_file = Path.Combine (target_path, "copyro2.txt");
372 using (File.CreateText (file_path)) { }
373 using (File.CreateText (target_file)) { }
375 File.SetAttributes (target_file, FileAttributes.ReadOnly);
376 Assert.AreEqual (FileAttributes.ReadOnly, File.GetAttributes (target_file), "A1");
378 string documentString = @"
379 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
380 <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
382 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
383 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
386 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)'>
387 <Output TaskParameter='CopiedFiles' ItemName='I0'/>
388 <Output TaskParameter='DestinationFiles' ItemName='I1'/>
390 <Message Text=""I0 : @(I0), I1: @(I1)""/>
395 engine = new Engine (Consts.BinPath);
396 project = engine.CreateNewProject ();
398 TestMessageLogger testLogger = new TestMessageLogger ();
399 engine.RegisterLogger (testLogger);
401 project.LoadXml (documentString);
403 // build should fail because of the readonly target file
404 Assert.IsFalse (project.Build ("1"));
406 File.SetAttributes (target_file, FileAttributes.Normal);
410 public void TestCopy_Retries ()
414 string file_path = Path.Combine (source_path, "copyretries.txt");
415 string target_file = Path.Combine (target_path, "copyretries.txt");
417 using (File.CreateText (file_path)) { }
418 using (File.CreateText (target_file)) { }
420 File.SetAttributes (target_file, FileAttributes.ReadOnly);
421 Assert.AreEqual (FileAttributes.ReadOnly, File.GetAttributes (target_file), "A1");
423 string documentString = @"
424 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
425 <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
427 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
428 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
431 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' Retries='3' RetryDelayMilliseconds='2000'>
432 <Output TaskParameter='CopiedFiles' ItemName='I0'/>
433 <Output TaskParameter='DestinationFiles' ItemName='I1'/>
435 <Message Text=""I0 : @(I0), I1: @(I1)""/>
440 engine = new Engine (Consts.BinPath);
441 project = engine.CreateNewProject ();
443 TestMessageLogger testLogger = new TestMessageLogger ();
444 engine.RegisterLogger (testLogger);
446 project.LoadXml (documentString);
448 // remove the read-only flag from the file after a few secs,
449 // so copying works after retries
452 File.SetAttributes (target_file, FileAttributes.Normal);
455 if (!project.Build ("1")) {
456 var sb = new StringBuilder ();
457 testLogger.DumpMessages (sb);
458 Assert.Fail ("Build failed " + sb.ToString ());
461 testLogger.CheckLoggedAny ("Copying failed. Retries left: 3.", MessageImportance.Normal, "A2");
464 void CheckCopyBuildItems (Project project, string [] source_files, string destination_folder, string prefix)
466 int num = source_files.Length;
467 for (int i = 0; i < num; i ++)
468 Assert.IsTrue (File.Exists (source_files [i]), prefix + " C1");
470 BuildItemGroup big = project.GetEvaluatedItemsByName ("I0");
472 Assert.AreEqual (num, big.Count, prefix + " C2");
473 for (int i = 0; i < num; i++) {
474 string suffix = (i + 1).ToString ();
475 BuildItem bi = big [i];
476 Assert.AreEqual (Path.Combine (destination_folder, Path.GetFileName (source_files [i])),
477 bi.FinalItemSpec, prefix + " C3 #" + suffix);
479 Assert.AreEqual (suffix, bi.GetMetadata ("Md"), prefix + " C4 #" + suffix);
482 big = project.GetEvaluatedItemsByName ("I1");
483 Assert.AreEqual (num, big.Count, prefix + " C6");
484 for (int i = 0; i < num; i++) {
485 string suffix = (i + 1).ToString ();
486 BuildItem bi = big [i];
487 Assert.AreEqual (Path.Combine (destination_folder, Path.GetFileName (source_files [i])),
488 bi.FinalItemSpec, prefix + " C7 #" + suffix);
489 Assert.AreEqual (suffix, bi.GetMetadata ("Md"), prefix + " C8 #" + suffix);