Merge pull request #980 from StephenMcConnel/bug-18638
[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 Microsoft.Build.Tasks;
34 using Microsoft.Build.Framework;
35 using Microsoft.Build.Utilities;
36
37 namespace MonoTests.Microsoft.Build.Tasks {
38
39         [TestFixture]
40         public class CopyTest {
41                 string source_path, target_path;
42
43                 [SetUp]
44                 public void CreateDir ()
45                 {
46                         source_path = Path.Combine (Path.Combine ("Test", "resources"), "Copy");
47                         Directory.CreateDirectory (source_path);
48                         target_path = Path.Combine (Path.Combine ("Test", "resources"), "Target");
49                         Directory.CreateDirectory (target_path);
50                 }
51
52                 [TearDown]
53                 public void RemoveDirectories ()
54                 {
55                         Directory.Delete (source_path, true);
56                         Directory.Delete (target_path, true);
57                 }
58
59                 [Test]
60                 public void TestCopy_MissingSourceFile ()
61                 {
62                         Copy copy = new Copy ();
63                         copy.BuildEngine = new TestEngine ();
64                         copy.SourceFiles = new ITaskItem [1];
65                         copy.SourceFiles [0] = new TaskItem ("SourceDoesNotExist");
66                         copy.DestinationFiles = new ITaskItem [1];
67                         copy.DestinationFiles [0] = new TaskItem ("DestDoesNotExist");
68                         Assert.IsFalse (copy.Execute ());
69                 }
70
71                 [Test]
72                 public void TestCopy1 ()
73                 {
74                         Engine engine;
75                         Project project;
76                         string file_path = Path.Combine (source_path, "copy.txt");
77                         string target_file = Path.Combine (target_path, "copy.txt");
78
79                         using (File.CreateText (file_path)) { }
80
81                         string documentString = @"
82                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
83                                         <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
84                                         <ItemGroup>
85                                                 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
86                                                 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
87                                         </ItemGroup>
88                                         <Target Name='1'>
89                                                 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' SkipUnchangedFiles='true' >
90                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
91                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
92                                                 </Copy>
93                                                 <Message Text=""I0 : @(I0), I1: @(I1)""/>
94                                         </Target>
95                                 </Project>
96                         ";
97
98                         engine = new Engine (Consts.BinPath);
99                         project = engine.CreateNewProject ();
100
101                         TestMessageLogger testLogger = new TestMessageLogger ();
102                         engine.RegisterLogger (testLogger);
103
104                         project.LoadXml (documentString);
105
106                         if (!project.Build ("1")) {
107                                 var sb = new StringBuilder ();
108                                 testLogger.DumpMessages (sb);
109                                 Assert.Fail ("Build failed " + sb.ToString ());
110                         }
111                         Assert.IsTrue (File.Exists (target_file), "A2");
112
113                         BuildItemGroup big = project.GetEvaluatedItemsByName ("I0");
114                         Assert.AreEqual (1, big.Count, "A3");
115                         BuildItem bi = big [0];
116                         Assert.AreEqual (target_file, bi.FinalItemSpec, "A4");
117                         Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A4");
118                         Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A5");
119
120                         big = project.GetEvaluatedItemsByName ("I1");
121                         Assert.AreEqual (1, big.Count, "A10");
122                         bi = big [0];
123                         Assert.AreEqual (target_file, bi.FinalItemSpec, "A11");
124                         Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A12");
125                         Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A13");
126
127                         // build again, this time files won't get copied because
128                         // of SkipUnchangedFiles=true
129                         if (!project.Build ("1")) {
130                                 testLogger.DumpMessages ();
131                                 Assert.Fail ("Build failed #2");
132                         }
133                         Assert.IsTrue (File.Exists (target_file), "A20");
134
135                         big = project.GetEvaluatedItemsByName ("I0");
136                         Assert.AreEqual (1, big.Count, "A21");
137                         bi = big [0];
138                         Assert.AreEqual (target_file, bi.FinalItemSpec, "A22");
139                         Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A23");
140                         Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A24");
141
142                         big = project.GetEvaluatedItemsByName ("I1");
143                         Assert.AreEqual (1, big.Count, "A25");
144                         bi = big [0];
145                         Assert.AreEqual (target_file, bi.FinalItemSpec, "A26");
146                         Assert.AreEqual ("1", bi.GetMetadata ("Md"), "A27");
147                         Assert.AreEqual ("2", bi.GetMetadata ("Mde"), "A28");
148                 }
149
150                 [Test]
151                 public void TestCopy2 ()
152                 {
153                         Engine engine;
154                         Project project;
155                         string [] file_paths = new string [] {
156                                 Path.Combine (source_path, "copy1.txt"),
157                                 Path.Combine (source_path, "copy2.txt")
158                         };
159
160                         using (File.CreateText (file_paths[0])) { }
161                         using (File.CreateText (file_paths[1])) { }
162
163                         string documentString = @"
164                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
165                                         <PropertyGroup><TargetPath>" + target_path + @"</TargetPath></PropertyGroup>
166                                         <ItemGroup>
167                                                 <SFiles Include='" + file_paths [0] + @"'><Md>1</Md></SFiles>
168                                                 <SFiles Include='" + file_paths [1] + @"'><Md>2</Md></SFiles>
169                                         </ItemGroup>
170                                         <Target Name='1'>
171                                                 <Copy SourceFiles='@(SFiles)' DestinationFolder='$(TargetPath)' SkipUnchangedFiles='true' >
172                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
173                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
174                                                 </Copy>
175                                         </Target>
176                                 </Project>
177                         ";
178                         engine = new Engine (Consts.BinPath);
179                         project = engine.CreateNewProject ();
180
181                         TestMessageLogger testLogger = new TestMessageLogger ();
182                         engine.RegisterLogger (testLogger);
183
184                         project.LoadXml (documentString);
185
186                         if (!project.Build ("1")) {
187                                 testLogger.DumpMessages ();
188                                 Assert.Fail ("Build failed");
189                         }
190
191                         CheckCopyBuildItems (project, file_paths, target_path, "A1");
192
193                         // build again, this time files won't get copied because
194                         // of SkipUnchangedFiles=true
195                         if (!project.Build ("1")) {
196                                 testLogger.DumpMessages ();
197                                 Assert.Fail ("Build failed #2");
198                         }
199                         CheckCopyBuildItems (project, file_paths, target_path, "A2");
200                 }
201
202                 [Test]
203                 public void TestCopy_EmptySources () {
204                         Engine engine;
205                         Project project;
206
207                         string documentString = @"
208                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
209                                         <Target Name='1'>
210                                                 <Copy SourceFiles='@(NonExistantSourceFiles)' DestinationFolder='$(TargetPath)' SkipUnchangedFiles='true' >
211                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
212                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
213                                                 </Copy>
214                                         </Target>
215                                 </Project>
216                         ";
217                         engine = new Engine (Consts.BinPath);
218                         project = engine.CreateNewProject ();
219
220                         TestMessageLogger testLogger = new TestMessageLogger ();
221                         engine.RegisterLogger (testLogger);
222
223                         project.LoadXml (documentString);
224
225                         
226                         if (!project.Build ("1")) {
227                                 testLogger.DumpMessages ();
228                                 Assert.Fail ("Build failed");
229                         }
230                 }
231
232                 [Test]
233                 public void TestCopy_EmptyDestFolder () {
234                         Engine engine;
235                         Project project;
236
237                         string documentString = @"
238                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
239                                         <ItemGroup>
240                                                 <SFiles Include='foo.txt'><Md>1</Md></SFiles>
241                                         </ItemGroup>
242                                         <Target Name='1'>
243                                                 <Copy SourceFiles='@(SFiles)' DestinationFolder='@(NonExistant)' DestinationFiles='@(NonExistant)' SkipUnchangedFiles='true' >
244                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
245                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
246                                                 </Copy>
247                                         </Target>
248                                 </Project>
249                         ";
250                         engine = new Engine (Consts.BinPath);
251                         project = engine.CreateNewProject ();
252
253                         TestMessageLogger testLogger = new TestMessageLogger ();
254                         engine.RegisterLogger (testLogger);
255
256                         project.LoadXml (documentString);
257                         if (project.Build ("1")) {
258                                 testLogger.DumpMessages ();
259                                 Assert.Fail ("Build should have failed");
260                         }
261                 }
262
263                 [Test]
264                 public void TestCopy_ReadOnlyUpdate ()
265                 {
266                         Engine engine;
267                         Project project;
268                         string file_path = Path.Combine (source_path, "copyro.txt");
269                         string target_file = Path.Combine (target_path, "copyro.txt");                  
270
271                         using (File.CreateText (file_path)) { }
272                         
273                         string documentString = @"
274                                 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
275                                         <PropertyGroup><DestFile>" + target_file + @"</DestFile></PropertyGroup>
276                                         <ItemGroup>
277                                                 <SFiles Include='" + file_path + @"'><Md>1</Md></SFiles>
278                                                 <DFiles Include='$(DestFile)'><Mde>2</Mde></DFiles>
279                                         </ItemGroup>
280                                         <Target Name='1'>
281                                                 <Copy SourceFiles='@(SFiles)' DestinationFiles='@(DFiles)' >
282                                                         <Output TaskParameter='CopiedFiles' ItemName='I0'/>
283                                                         <Output TaskParameter='DestinationFiles' ItemName='I1'/>
284                                                 </Copy>
285                                                 <Message Text=""I0 : @(I0), I1: @(I1)""/>
286                                         </Target>
287                                 </Project>
288                         ";
289
290                         engine = new Engine (Consts.BinPath);
291                         project = engine.CreateNewProject ();
292
293                         TestMessageLogger testLogger = new TestMessageLogger ();
294                         engine.RegisterLogger (testLogger);
295
296                         project.LoadXml (documentString);
297
298                         if (!project.Build ("1")) {
299                                 testLogger.DumpMessages ();
300                                 Assert.Fail ("Build failed");
301                         }
302                         Assert.IsTrue (File.Exists (target_file), "A2");
303                         Assert.AreEqual (FileAttributes.Normal, File.GetAttributes (target_file), "A3");                                        
304                 }
305
306 #if NET_3_5
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 #endif
400
401                 void CheckCopyBuildItems (Project project, string [] source_files, string destination_folder, string prefix)
402                 {
403                         int num = source_files.Length;
404                         for (int i = 0; i < num; i ++)
405                                 Assert.IsTrue (File.Exists (source_files [i]), prefix + " C1");
406
407                         BuildItemGroup big = project.GetEvaluatedItemsByName ("I0");
408
409                         Assert.AreEqual (num, big.Count, prefix + " C2");
410                         for (int i = 0; i < num; i++) {
411                                 string suffix = (i + 1).ToString ();
412                                 BuildItem bi = big [i];
413                                 Assert.AreEqual (Path.Combine (destination_folder, Path.GetFileName (source_files [i])),
414                                         bi.FinalItemSpec, prefix + " C3 #" + suffix);
415
416                                 Assert.AreEqual (suffix, bi.GetMetadata ("Md"), prefix + " C4 #" + suffix);
417                         }
418
419                         big = project.GetEvaluatedItemsByName ("I1");
420                         Assert.AreEqual (num, big.Count, prefix + " C6");
421                         for (int i = 0; i < num; i++) {
422                                 string suffix = (i + 1).ToString ();
423                                 BuildItem bi = big [i];
424                                 Assert.AreEqual (Path.Combine (destination_folder, Path.GetFileName (source_files [i])),
425                                         bi.FinalItemSpec, prefix + " C7 #" + suffix);
426                                 Assert.AreEqual (suffix, bi.GetMetadata ("Md"), prefix + " C8 #" + suffix);
427                         }
428                  }
429         }
430 }