Merge pull request #1542 from ninjarobot/UriTemplateMatchException
[mono.git] / mcs / class / Microsoft.Build.Tasks / Test / Microsoft.Build.Tasks / CopyTest.cs
1 //
2 // CopyTest.cs
3 //  
4 // Author:
5 //   Ankit Jain (jankit@novell.com)
6 //
7 // Copyright 2009 Novell, Inc (http://www.novell.com)
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27
28 using System;
29 using System.IO;
30 using Microsoft.Build.BuildEngine;
31 using NUnit.Framework;
32 using System.Text;
33 using System.Threading;
34 using Microsoft.Build.Tasks;
35 using Microsoft.Build.Framework;
36 using Microsoft.Build.Utilities;
37
38 namespace MonoTests.Microsoft.Build.Tasks {
39
40         [TestFixture]
41         public class CopyTest {
42                 string source_path, target_path;
43
44                 [SetUp]
45                 public void CreateDir ()
46                 {
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);
51                 }
52
53                 [TearDown]
54                 public void RemoveDirectories ()
55                 {
56                         Directory.Delete (source_path, true);
57                         Directory.Delete (target_path, true);
58                 }
59
60                 [Test]
61                 public void TestCopy_MissingSourceFile ()
62                 {
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 ());
70                 }
71
72                 [Test]
73                 public void TestCopy1 ()
74                 {
75                         Engine engine;
76                         Project project;
77                         string file_path = Path.Combine (source_path, "copy.txt");
78                         string target_file = Path.Combine (target_path, "copy.txt");
79
80                         using (File.CreateText (file_path)) { }
81
82                         string documentString = @"
83                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
84                                         <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
85                                         <ItemGroup>
86                                                 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
87                                                 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
88                                         </ItemGroup>
89                                         <Target Name='1'>
90                                                 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' SkipUnchangedFiles='true' >
91                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
92                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
93                                                 </Copy>
94                                                 <Message Text=""I0 : @(I0), I1: @(I1)""/>
95                                         </Target>
96                                 </Project>
97                         ";
98
99                         engine = new Engine (Consts.BinPath);
100                         project = engine.CreateNewProject ();
101
102                         TestMessageLogger testLogger = new TestMessageLogger ();
103                         engine.RegisterLogger (testLogger);
104
105                         project.LoadXml (documentString);
106
107                         if (!project.Build ("1")) {
108                                 var sb = new StringBuilder ();
109                                 testLogger.DumpMessages (sb);
110                                 Assert.Fail ("Build failed " + sb.ToString ());
111                         }
112                         Assert.IsTrue (File.Exists (target_file), "A2");
113
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");
120
121                         big = project.GetEvaluatedItemsByName ("I1");
122                         Assert.AreEqual (1, big.Count, "A10");
123                         bi = big [0];
124                         Assert.AreEqual (target_file, bi.FinalItemSpec, "A11");
125                         Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A12");
126                         Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A13");
127
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");
133                         }
134                         Assert.IsTrue (File.Exists (target_file), "A20");
135
136                         big = project.GetEvaluatedItemsByName ("I0");
137                         Assert.AreEqual (1, big.Count, "A21");
138                         bi = big [0];
139                         Assert.AreEqual (target_file, bi.FinalItemSpec, "A22");
140                         Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A23");
141                         Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A24");
142
143                         big = project.GetEvaluatedItemsByName ("I1");
144                         Assert.AreEqual (1, big.Count, "A25");
145                         bi = big [0];
146                         Assert.AreEqual (target_file, bi.FinalItemSpec, "A26");
147                         Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A27");
148                         Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A28");
149                 }
150
151                 [Test]
152                 public void TestCopy2 ()
153                 {
154                         Engine engine;
155                         Project project;
156                         string [] file_paths = new string [] {
157                                 Path.Combine (source_path, "copy1.txt"),
158                                 Path.Combine (source_path, "copy2.txt")
159                         };
160
161                         using (File.CreateText (file_paths[0])) { }
162                         using (File.CreateText (file_paths[1])) { }
163
164                         string documentString = @"
165                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
166                                         <PropertyGroup><TargetPath>" + target_path + @"</TargetPath></PropertyGroup>
167                                         <ItemGroup>
168                                                 <SFiles Include='" + file_paths [0] + @"'><Md>1</Md></SFiles>
169                                                 <SFiles Include='" + file_paths [1] + @"'><Md>2</Md></SFiles>
170                                         </ItemGroup>
171                                         <Target Name='1'>
172                                                 <Copy SourceFiles='@(SFiles)' DestinationFolder='$(TargetPath)' SkipUnchangedFiles='true' >
173                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
174                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
175                                                 </Copy>
176                                         </Target>
177                                 </Project>
178                         ";
179                         engine = new Engine (Consts.BinPath);
180                         project = engine.CreateNewProject ();
181
182                         TestMessageLogger testLogger = new TestMessageLogger ();
183                         engine.RegisterLogger (testLogger);
184
185                         project.LoadXml (documentString);
186
187                         if (!project.Build ("1")) {
188                                 testLogger.DumpMessages ();
189                                 Assert.Fail ("Build failed");
190                         }
191
192                         CheckCopyBuildItems (project, file_paths, target_path, "A1");
193
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");
199                         }
200                         CheckCopyBuildItems (project, file_paths, target_path, "A2");
201                 }
202
203                 [Test]
204                 public void TestCopy_EmptySources () {
205                         Engine engine;
206                         Project project;
207
208                         string documentString = @"
209                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
210                                         <Target Name='1'>
211                                                 <Copy SourceFiles='@(NonExistantSourceFiles)' DestinationFolder='$(TargetPath)' SkipUnchangedFiles='true' >
212                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
213                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
214                                                 </Copy>
215                                         </Target>
216                                 </Project>
217                         ";
218                         engine = new Engine (Consts.BinPath);
219                         project = engine.CreateNewProject ();
220
221                         TestMessageLogger testLogger = new TestMessageLogger ();
222                         engine.RegisterLogger (testLogger);
223
224                         project.LoadXml (documentString);
225
226                         
227                         if (!project.Build ("1")) {
228                                 testLogger.DumpMessages ();
229                                 Assert.Fail ("Build failed");
230                         }
231                 }
232
233                 [Test]
234                 public void TestCopy_EmptyDestFolder () {
235                         Engine engine;
236                         Project project;
237
238                         string documentString = @"
239                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
240                                         <ItemGroup>
241                                                 <SFiles Include='foo.txt'><Md>1</Md></SFiles>
242                                         </ItemGroup>
243                                         <Target Name='1'>
244                                                 <Copy SourceFiles='@(SFiles)' DestinationFolder='@(NonExistant)' DestinationFiles='@(NonExistant)' SkipUnchangedFiles='true' >
245                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
246                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
247                                                 </Copy>
248                                         </Target>
249                                 </Project>
250                         ";
251                         engine = new Engine (Consts.BinPath);
252                         project = engine.CreateNewProject ();
253
254                         TestMessageLogger testLogger = new TestMessageLogger ();
255                         engine.RegisterLogger (testLogger);
256
257                         project.LoadXml (documentString);
258                         if (project.Build ("1")) {
259                                 testLogger.DumpMessages ();
260                                 Assert.Fail ("Build should have failed");
261                         }
262                 }
263
264                 [Test]
265                 public void TestCopy_ReadOnlyUpdate ()
266                 {
267                         Engine engine;
268                         Project project;
269                         string file_path = Path.Combine (source_path, "copyro.txt");
270                         string target_file = Path.Combine (target_path, "copyro.txt");                  
271
272                         using (File.CreateText (file_path)) { }
273                         
274                         string documentString = @"
275                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
276                                         <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
277                                         <ItemGroup>
278                                                 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
279                                                 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
280                                         </ItemGroup>
281                                         <Target Name='1'>
282                                                 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' >
283                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
284                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
285                                                 </Copy>
286                                                 <Message Text=""I0 : @(I0), I1: @(I1)""/>
287                                         </Target>
288                                 </Project>
289                         ";
290
291                         engine = new Engine (Consts.BinPath);
292                         project = engine.CreateNewProject ();
293
294                         TestMessageLogger testLogger = new TestMessageLogger ();
295                         engine.RegisterLogger (testLogger);
296
297                         project.LoadXml (documentString);
298
299                         if (!project.Build ("1")) {
300                                 testLogger.DumpMessages ();
301                                 Assert.Fail ("Build failed");
302                         }
303                         Assert.IsTrue (File.Exists (target_file), "A2");
304                         Assert.AreEqual (FileAttributes.Normal, File.GetAttributes (target_file), "A3");                                        
305                 }
306
307                 [Test]
308                 public void TestCopy_OverwriteReadOnlyTrue ()
309                 {
310                         Engine engine;
311                         Project project;
312                         string file_path = Path.Combine (source_path, "copyro1.txt");
313                         string target_file = Path.Combine (target_path, "copyro1.txt");                 
314
315                         using (File.CreateText (file_path)) { }
316                         using (File.CreateText (target_file)) { }
317
318                         File.SetAttributes (target_file, FileAttributes.ReadOnly);
319                         Assert.AreEqual (FileAttributes.ReadOnly, File.GetAttributes (target_file), "A1");
320                         
321                         string documentString = @"
322                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
323                                         <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
324                                         <ItemGroup>
325                                                 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
326                                                 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
327                                         </ItemGroup>
328                                         <Target Name='1'>
329                                                 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' OverwriteReadOnlyFiles='true'>
330                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
331                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
332                                                 </Copy>
333                                                 <Message Text=""I0 : @(I0), I1: @(I1)""/>
334                                         </Target>
335                                 </Project>
336                         ";
337
338                         engine = new Engine (Consts.BinPath);
339                         project = engine.CreateNewProject ();
340
341                         TestMessageLogger testLogger = new TestMessageLogger ();
342                         engine.RegisterLogger (testLogger);
343
344                         project.LoadXml (documentString);
345
346                         if (!project.Build ("1")) {
347                                 var sb = new StringBuilder ();
348                                 testLogger.DumpMessages (sb);
349                                 Assert.Fail ("Build failed " + sb.ToString ());
350                         }
351                         Assert.IsTrue (File.Exists (target_file), "A2");
352                         Assert.AreEqual (FileAttributes.Normal, File.GetAttributes (target_file), "A3");                                        
353                 }
354
355                 [Test]
356                 public void TestCopy_OverwriteReadOnlyFalse ()
357                 {
358                         Engine engine;
359                         Project project;
360                         string file_path = Path.Combine (source_path, "copyro2.txt");
361                         string target_file = Path.Combine (target_path, "copyro2.txt");                 
362
363                         using (File.CreateText (file_path)) { }
364                         using (File.CreateText (target_file)) { }
365
366                         File.SetAttributes (target_file, FileAttributes.ReadOnly);
367                         Assert.AreEqual (FileAttributes.ReadOnly, File.GetAttributes (target_file), "A1");
368                         
369                         string documentString = @"
370                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
371                                         <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
372                                         <ItemGroup>
373                                                 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
374                                                 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
375                                         </ItemGroup>
376                                         <Target Name='1'>
377                                                 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)'>
378                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
379                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
380                                                 </Copy>
381                                                 <Message Text=""I0 : @(I0), I1: @(I1)""/>
382                                         </Target>
383                                 </Project>
384                         ";
385
386                         engine = new Engine (Consts.BinPath);
387                         project = engine.CreateNewProject ();
388
389                         TestMessageLogger testLogger = new TestMessageLogger ();
390                         engine.RegisterLogger (testLogger);
391
392                         project.LoadXml (documentString);
393
394                         // build should fail because of the readonly target file
395                         Assert.IsFalse (project.Build ("1"));
396                         
397                         File.SetAttributes (target_file, FileAttributes.Normal);
398                 }
399
400                 [Test]
401                 public void TestCopy_Retries ()
402                 {
403                         Engine engine;
404                         Project project;
405                         string file_path = Path.Combine (source_path, "copyretries.txt");
406                         string target_file = Path.Combine (target_path, "copyretries.txt");                     
407
408                         using (File.CreateText (file_path)) { }
409                         using (File.CreateText (target_file)) { }
410
411                         File.SetAttributes (target_file, FileAttributes.ReadOnly);
412                         Assert.AreEqual (FileAttributes.ReadOnly, File.GetAttributes (target_file), "A1");
413
414                         string documentString = @"
415                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
416                                         <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
417                                         <ItemGroup>
418                                                 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
419                                                 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
420                                         </ItemGroup>
421                                         <Target Name='1'>
422                                                 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' Retries='3' RetryDelayMilliseconds='2000'>
423                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
424                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
425                                                 </Copy>
426                                                 <Message Text=""I0 : @(I0), I1: @(I1)""/>
427                                         </Target>
428                                 </Project>
429                         ";
430
431                         engine = new Engine (Consts.BinPath);
432                         project = engine.CreateNewProject ();
433
434                         TestMessageLogger testLogger = new TestMessageLogger ();
435                         engine.RegisterLogger (testLogger);
436
437                         project.LoadXml (documentString);
438
439                         // remove the read-only flag from the file after a few secs,
440                         // so copying works after retries
441                         new Thread ( () => {
442                                 Thread.Sleep (3000);
443                                 File.SetAttributes (target_file, FileAttributes.Normal);
444                         }).Start ();
445
446                         if (!project.Build ("1")) {
447                                 var sb = new StringBuilder ();
448                                 testLogger.DumpMessages (sb);
449                                 Assert.Fail ("Build failed " + sb.ToString ());
450                         }
451
452                         testLogger.CheckLoggedAny ("Copying failed. Retries left: 3.", MessageImportance.Normal, "A2");
453                 }
454
455                 void CheckCopyBuildItems (Project project, string [] source_files, string destination_folder, string prefix)
456                 {
457                         int num = source_files.Length;
458                         for (int i = 0; i < num; i ++)
459                                 Assert.IsTrue (File.Exists (source_files [i]), prefix + " C1");
460
461                         BuildItemGroup big = project.GetEvaluatedItemsByName ("I0");
462
463                         Assert.AreEqual (num, big.Count, prefix + " C2");
464                         for (int i = 0; i < num; i++) {
465                                 string suffix = (i + 1).ToString ();
466                                 BuildItem bi = big [i];
467                                 Assert.AreEqual (Path.Combine (destination_folder, Path.GetFileName (source_files [i])),
468                                         bi.FinalItemSpec, prefix + " C3 #" + suffix);
469
470                                 Assert.AreEqual (suffix, bi.GetMetadata ("Md"), prefix + " C4 #" + suffix);
471                         }
472
473                         big = project.GetEvaluatedItemsByName ("I1");
474                         Assert.AreEqual (num, big.Count, prefix + " C6");
475                         for (int i = 0; i < num; i++) {
476                                 string suffix = (i + 1).ToString ();
477                                 BuildItem bi = big [i];
478                                 Assert.AreEqual (Path.Combine (destination_folder, Path.GetFileName (source_files [i])),
479                                         bi.FinalItemSpec, prefix + " C7 #" + suffix);
480                                 Assert.AreEqual (suffix, bi.GetMetadata ("Md"), prefix + " C8 #" + suffix);
481                         }
482                  }
483         }
484 }