Merge pull request #1304 from slluis/mac-proxy-autoconfig
[mono.git] / mcs / class / Microsoft.Build.Utilities / Test / Microsoft.Build.Utilities / ToolTaskTest.cs
1 //
2 // ToolTaskTest.cs:
3 //
4 // Author:
5 //   Jonathan Pryor (jonp@xamarin.com)
6 //
7 // (C) 2013 Xamarin Inc.
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.Collections;
30 using System.Collections.Generic;
31 using System.Diagnostics;
32 using System.IO;
33 using System.Linq;
34
35 using Microsoft.Build.Framework;
36 using Microsoft.Build.Utilities;
37
38 using NUnit.Framework;
39
40 namespace MonoTests.Microsoft.Build.Utilities {
41
42         [TestFixture]
43         public class ToolTaskTest {
44
45 //NUnit 2.6 gives much better reporting of individual failures, but Mono currently uses 2.4.x
46 #if !NUNIT_2_6
47                 [Test]
48                 public void LogEventsFromTextOutput ()
49                 {
50                         foreach (var test in GetErrorParsingTestData ()) {
51                                 LogEventsFromTextOutput (test.Raw, test.ExpectedResult);
52                         }
53                 }
54
55                 class TestCaseData
56                 {
57                         public TestCaseData (string raw, LogEvent expectedResult)
58                         {
59                                 Raw = raw;
60                                 ExpectedResult = expectedResult;
61                         }
62
63                         public string Raw { get; private set; }
64                         public LogEvent ExpectedResult { get; private set; }
65
66                         public TestCaseData SetName (string name)
67                         {
68                                 return this;
69                         }
70                 }
71 #else
72                 [Test, TestCaseSource ("GetErrorParsingTestData")]
73 #endif
74                 public void LogEventsFromTextOutput (string lineText, LogEvent expected)
75                 {
76                         var task = new LogEventsFromTextOutputToolTask ();
77                         task.LogEventsFromTextOutput (lineText);
78                         Assert.AreEqual (task.LogEvents.Count, 1);
79                         var result = task.LogEvents[0];
80                         task.LogEvents.Clear ();
81
82                         if (result != null && result.Origin == task.GetType ().Name.ToUpper ())
83                                 result.Origin = "#TASKNAME";
84
85                         if (expected == null) {
86                                 Assert.IsNull (result, "#nomatch");
87                                 return;
88                         }
89
90                         Assert.IsNotNull (result, "#match");
91                         Assert.AreEqual (expected.Origin, result.Origin, "#origin");
92                         Assert.AreEqual (expected.Line, result.Line, "#line");
93                         Assert.AreEqual (expected.Column, result.Column, "#column");
94                         Assert.AreEqual (expected.EndLine, result.EndLine, "#endline");
95                         Assert.AreEqual (expected.EndColumn, result.EndColumn, "#endcolumn");
96                         Assert.AreEqual (expected.IsError, result.IsError, "#iserror");
97                         Assert.AreEqual (expected.Subcategory ?? "", result.Subcategory, "#subcategory");
98                         Assert.AreEqual (expected.Code, result.Code, "number");
99                         Assert.AreEqual (expected.Message ?? "", result.Message, "#message");
100                 }
101
102                 static IEnumerable<TestCaseData> GetErrorParsingTestData ()
103                 {
104                         yield return new TestCaseData (
105                                 "error   CS66",
106                                 null
107                         ).SetName ("NoColon");
108
109                         yield return new TestCaseData (
110                                 "error   CS66 : ",
111                                 new LogEvent {
112                                         Origin = "#TASKNAME",
113                                         IsError = true,
114                                         Code = "CS66"
115                                 }
116                         ).SetName ("Minimal");
117
118                         yield return new TestCaseData (
119                                 "pineapple   CS66 : ",
120                                 null
121                         ).SetName ("InvalidCategory");
122
123                         yield return new TestCaseData (
124                                 "ERROR  CS66 : ",
125                                 new LogEvent {
126                                         Origin = "#TASKNAME",
127                                         IsError = true,
128                                         Code = "CS66"
129                                 }
130                         ).SetName ("CaseInsensitivity");
131
132                         yield return new TestCaseData (
133                                 ": error  CS66 : ",
134                                 new LogEvent {
135                                         Origin = "#TASKNAME",
136                                         IsError = true,
137                                         Code = "CS66"
138                                 }
139                         ).SetName ("EmptyOrigin");
140
141                         yield return new TestCaseData (
142                                 "     : error  CS66 : ",
143                                 new LogEvent {
144                                         Origin = "#TASKNAME",
145                                         IsError = true,
146                                         Code = "CS66"
147                                 }
148                         ).SetName ("BlankOrigin");
149
150                         yield return new TestCaseData (
151                                 "error   CS66 : error in 'hello:thing'",
152                                 new LogEvent {
153                                         Origin = "#TASKNAME",
154                                         IsError = true,
155                                         Code = "CS66",
156                                         Message = "error in 'hello:thing'",
157                                 }
158                         ).SetName ("NoOriginButErrorLikeMessage");
159
160                         yield return new TestCaseData (
161                                 "   C:\\class.cs   (23,344)  :    error   CS66   : blah    ",
162                                 new LogEvent {
163                                         Origin = "C:\\class.cs",
164                                         Line = 23,
165                                         Column = 344,
166                                         IsError = true,
167                                         Code = "CS66",
168                                         Message = "blah",
169                                 }
170                         ).SetName ("Whitespace");
171
172                         yield return new TestCaseData (
173                                 "class1.cs(16,4): error CS0152: The label `case 1:' already occurs in this switch statement",
174                                 new LogEvent {
175                                         Origin = "class1.cs",
176                                         Line = 16,
177                                         Column = 4,
178                                         IsError = true,
179                                         Code = "CS0152",
180                                         Message = "The label `case 1:' already occurs in this switch statement",
181                                 }
182                         ).SetName ("RangeLineCol");
183
184                         yield return new TestCaseData (
185                                 "class1.cs(16,4-56): error X: blah",
186                                 new LogEvent {
187                                         Origin = "class1.cs",
188                                         Line = 16,
189                                         Column = 4,
190                                         EndColumn = 56,
191                                         IsError = true,
192                                         Code = "X",
193                                         Message = "blah",
194                                 }
195                         ).SetName ("RangeLineColCol");
196
197                         yield return new TestCaseData (
198                                 "class1.cs(16,4,56,7): error X: blah",
199                                 new LogEvent {
200                                         Origin = "class1.cs",
201                                         Line = 16,
202                                         Column = 4,
203                                         EndLine = 56,
204                                         EndColumn = 7,
205                                         IsError = true,
206                                         Code = "X",
207                                         Message = "blah",
208                                 }
209                         ).SetName ("RangeLineColLineCol");
210
211                         yield return new TestCaseData (
212                                 "class1.cs(1-77): error X: blah",
213                                 new LogEvent {
214                                         Origin = "class1.cs",
215                                         Line = 1,
216                                         EndLine = 77,
217                                         IsError = true,
218                                         Code = "X",
219                                         Message = "blah",
220                                 }
221                         ).SetName ("RangeLineLine");
222
223                         yield return new TestCaseData (
224                                 "class1.cs(1-77-89): error X: blah",
225                                 new LogEvent {
226                                         Origin = "class1.cs",
227                                         IsError = true,
228                                         Code = "X",
229                                         Message = "blah",
230                                 }
231                         ).SetName ("BadRangeTooManyDashes");
232
233                         yield return new TestCaseData (
234                                 "class1.cs(1&77-89): error X: blah",
235                                 new LogEvent {
236                                         Origin = "class1.cs(1&77-89)",
237                                         IsError = true,
238                                         Code = "X",
239                                         Message = "blah",
240                                 }
241                         ).SetName ("BadRangePunctuation");
242
243                         yield return new TestCaseData (
244                                 "class1.cs(ASDF): error X: blah",
245                                 new LogEvent {
246                                         Origin = "class1.cs(ASDF)",
247                                         IsError = true,
248                                         Code = "X",
249                                         Message = "blah",
250                                 }
251                         ).SetName ("BadRangeAlpha");
252
253                         yield return new TestCaseData (
254                                 "class1.cs(12AA45): error X: blah",
255                                 new LogEvent {
256                                         Origin = "class1.cs(12AA45)",
257                                         IsError = true,
258                                         Code = "X",
259                                         Message = "blah",
260                                 }
261                         ).SetName ("BadRangeAlphaNumeric");
262
263                         yield return new TestCaseData (
264                                 "class1.cs(1-77,89-56): error X: blah",
265                                 new LogEvent {
266                                         Origin = "class1.cs",
267                                         IsError = true,
268                                         Code = "X",
269                                         Message = "blah",
270                                 }
271                         ).SetName ("BadRangeLineLineColCol");
272
273                         yield return new TestCaseData (
274                                 "class1.cs(1,77,89): error X: blah",
275                                 new LogEvent {
276                                         Origin = "class1.cs",
277                                         IsError = true,
278                                         Code = "X",
279                                         Message = "blah",
280                                 }
281                         ).SetName ("BadRangeThreeCommas");
282
283                         yield return new TestCaseData (
284                                 "class1.cs(0): error X:",
285                                 new LogEvent {
286                                         Origin = "class1.cs",
287                                         IsError = true,
288                                         Code = "X",
289                                 }
290                         ).SetName ("RangeZero");
291
292                         yield return new TestCaseData (
293                                 "class1.cs(2,1234567890192929293833838380): error X:",
294                                 new LogEvent {
295                                         Origin = "class1.cs",
296                                         Line = 2,
297                                         IsError = true,
298                                         Code = "X",
299                                 }
300                         ).SetName ("BadRangeOverflowCol");
301
302                         yield return new TestCaseData (
303                                 "class1.cs(2,1234567890192929293833838380,5,7): error X:",
304                                 new LogEvent {
305                                         Line = 2,
306                                         EndLine = 5,
307                                         EndColumn = 7,
308                                         Origin = "class1.cs",
309                                         IsError = true,
310                                         Code = "X",
311                                 }
312                         ).SetName ("BadRangeOverflowBeforeValues");
313
314                         yield return new TestCaseData (
315                                 "c:\\foo error XXX: fatal error YYY : error blah : thing",
316                                 new LogEvent {
317                                         Origin = "c:\\foo error XXX",
318                                         IsError = true,
319                                         Subcategory = "fatal",
320                                         Code = "YYY",
321                                         Message = "error blah : thing",
322                                 }
323                         ).SetName ("LotsOfColons");
324
325                         yield return new TestCaseData (
326                                 "Main.cs(17,20): warning CS0168: The variable 'foo' is declared but never used",
327                                 new LogEvent {
328                                         Origin = "Main.cs",
329                                         Line = 17,
330                                         Column = 20,
331                                         Code = "CS0168",
332                                         Message = "The variable 'foo' is declared but never used",
333                                 }
334                         ).SetName ("MSExample1");
335
336                         yield return new TestCaseData (
337                                 "C:\\dir1\\foo.resx(2) : error BC30188: Declaration expected.",
338                                 new LogEvent {
339                                         Origin = "C:\\dir1\\foo.resx",
340                                         Line = 2,
341                                         IsError = true,
342                                         Code = "BC30188",
343                                         Message = "Declaration expected.",
344                                 }
345                         ).SetName ("MSExample2");
346
347                         yield return new TestCaseData (
348                                 "cl : Command line warning D4024 : unrecognized source file type 'foo.cs', object file assumed",
349                                 new LogEvent {
350                                         Origin = "cl",
351                                         Subcategory = "Command line",
352                                         Code = "D4024",
353                                         Message = "unrecognized source file type 'foo.cs', object file assumed",
354                                 }
355                         ).SetName ("MSExample3");
356
357                         yield return new TestCaseData (
358                                 "error CS0006: Metadata file 'System.dll' could not be found.",
359                                 new LogEvent {
360                                         Origin = "#TASKNAME",
361                                         IsError = true,
362                                         Code = "CS0006",
363                                         Message = "Metadata file 'System.dll' could not be found.",
364                                 }
365                         ).SetName ("MSExample4");
366
367                         yield return new TestCaseData (
368                                 "C:\\sourcefile.cpp(134) : error C2143: syntax error : missing ';' before '}'",
369                                 new LogEvent {
370                                         Origin = "C:\\sourcefile.cpp",
371                                         Line = 134,
372                                         IsError = true,
373                                         Code = "C2143",
374                                         Message = "syntax error : missing ';' before '}'",
375                                 }
376                         ).SetName ("MSExample5");
377
378                         yield return new TestCaseData (
379                                 "LINK : fatal error LNK1104: cannot open file 'somelib.lib'",
380                                 new LogEvent {
381                                         Origin = "LINK",
382                                         Subcategory = "fatal",
383                                         IsError = true,
384                                         Code = "LNK1104",
385                                         Message = "cannot open file 'somelib.lib'",
386                                 }
387                         ).SetName ("MSExample6");
388
389                         yield return new TestCaseData (
390                                 "/foo (bar)/baz/Component1.fs(3,5): error FS0201: Namespaces cannot contain values.",
391                                 new LogEvent {
392                                         Origin = "/foo (bar)/baz/Component1.fs",
393                                         Line = 3,
394                                         Column = 5,
395                                         IsError = true,
396                                         Code = "FS0201",
397                                         Message = "Namespaces cannot contain values.",
398                                 }
399                         ).SetName ("ParensInFilename");
400
401                         yield return new TestCaseData (
402                                 "fatal error XXX: stuff.",
403                                 new LogEvent {
404                                         Origin = "#TASKNAME",
405                                         IsError = true,
406                                         Subcategory = "fatal",
407                                         Code = "XXX",
408                                         Message = "stuff.",
409                                 }
410                         ).SetName ("SubcategoryNoOrigin");
411                 }
412
413                 [Test]
414                 public void ToolExeAndPath ()
415                 {
416                         TestToolTask a = new TestToolTask ();
417                         Assert.AreEqual (a.ToolExe, "TestTool.exe", "#1");
418                         a.ToolExe = "Foo";
419                         Assert.AreEqual (a.ToolExe, "Foo", "#2");
420                         a.ToolExe = "";
421                         Assert.AreEqual (a.ToolExe, "TestTool.exe", "#3");
422
423                         Assert.AreEqual (a.ToolPath, null, "#4");
424                         a.ToolPath = "Bar";
425                         Assert.AreEqual (a.ToolPath, "Bar", "#5");
426                         a.ToolPath = "";
427                         Assert.AreEqual (a.ToolPath, "", "#6");
428
429                         a.Execute ();
430                 }
431
432                 [Test]
433                 public void Execute_1 ()
434                 {
435                         var t = new TestExecuteToolTask ();
436                         t.OnExecuteTool = delegate { Assert.Fail ("#1"); };
437                         t.BuildEngine = new MockBuildEngine ();
438                         Assert.IsFalse (t.Execute (), "result");
439                 }
440
441                 [Test]
442                 public void Execute_2 ()
443                 {
444                         var t = new TestExecuteToolTask ();
445                         t.BuildEngine = new MockBuildEngine ();
446                         t.ToolPath = Directory.GetCurrentDirectory ();
447                         t.ToolExe = "Makefile";
448
449                         t.OnExecuteTool = (pathToTool, responseFileCommands, commandLineCommands) => {
450                                 Assert.AreEqual (Path.Combine (Directory.GetCurrentDirectory (), "Makefile"), pathToTool, "#1");
451                                 Assert.AreEqual ("", responseFileCommands, "#2");
452                                 Assert.AreEqual ("", commandLineCommands, "#3");
453
454                         };
455
456                         Assert.IsTrue (t.Execute (), "result");
457                 }
458
459                 [Test]
460                 public void Execute_3 ()
461                 {
462                         var t = new TestExecuteToolTask ();
463                         t.FullPathToTool = "fpt";
464                         t.BuildEngine = new MockBuildEngine ();
465                         t.ToolExe = "Makefile.mk";
466
467                         t.OnExecuteTool = (pathToTool, responseFileCommands, commandLineCommands) => {
468                                 Assert.AreEqual ("Makefile.mk", pathToTool, "#1");
469                                 Assert.AreEqual ("", responseFileCommands, "#2");
470                                 Assert.AreEqual ("", commandLineCommands, "#3");
471
472                         };
473
474                         Assert.IsFalse (t.Execute (), "result");
475                 }
476         }
477
478         public class LogEvent
479         {
480                 public string Origin { get; set; }
481                 public int Line { get; set; }
482                 public int Column { get; set; }
483                 public int EndLine { get; set; }
484                 public int EndColumn { get; set; }
485                 public string Subcategory { get; set; }
486                 public bool IsError { get; set; }
487                 public string Code { get; set; }
488                 public string Message { get; set; }
489         }
490
491         class LogEventsFromTextOutputToolTask : ToolTask {
492
493                 public List<LogEvent> LogEvents {
494                         get { return engine.LogEvents; }
495                 }
496
497                 CodeLoggingBuildEngine engine = new CodeLoggingBuildEngine ();
498
499                 public LogEventsFromTextOutputToolTask ()
500                 {
501                         BuildEngine = engine;
502                 }
503
504                 protected override string GenerateFullPathToTool ()
505                 {
506                         throw new NotImplementedException ();
507                 }
508
509                 protected override string ToolName {
510                         get {throw new NotImplementedException ();}
511                 }
512
513                 public void LogEventsFromTextOutput (string line)
514                 {
515                         base.LogEventsFromTextOutput (line, MessageImportance.Normal);
516                 }
517         }
518
519         class CodeLoggingBuildEngine : IBuildEngine {
520
521                 public List<LogEvent> LogEvents = new List<LogEvent> ();
522
523                 public int ColumnNumberOfTaskNode {
524                         get {
525                                 throw new NotImplementedException ();
526                         }
527                 }
528
529                 public bool ContinueOnError {
530                         get {
531                                 throw new NotImplementedException ();
532                         }
533                 }
534
535                 public int LineNumberOfTaskNode {
536                         get {
537                                 throw new NotImplementedException ();
538                         }
539                 }
540
541                 public string ProjectFileOfTaskNode {
542                         get {
543                                 throw new NotImplementedException ();
544                         }
545                 }
546
547                 public bool BuildProjectFile (string projectFileName, string[] targetNames, System.Collections.IDictionary globalProperties, System.Collections.IDictionary targetOutputs)
548                 {
549                         throw new NotImplementedException ();
550                 }
551
552                 public void LogCustomEvent (CustomBuildEventArgs e)
553                 {
554                         LogEvents.Add (null);
555                 }
556
557                 public void LogErrorEvent (BuildErrorEventArgs e)
558                 {
559                         LogEvents.Add (new LogEvent {
560                                 IsError = true,
561                                 Subcategory = e.Subcategory,
562                                 Origin = e.File,
563                                 Line = e.LineNumber,
564                                 EndLine = e.EndLineNumber,
565                                 Column = e.ColumnNumber,
566                                 EndColumn = e.EndColumnNumber,
567                                 Code = e.Code,
568                                 Message = e.Message,
569                         });
570                 }
571
572                 public void LogMessageEvent (BuildMessageEventArgs e)
573                 {
574                         LogEvents.Add (null);
575                 }
576
577                 public void LogWarningEvent (BuildWarningEventArgs e)
578                 {
579                         LogEvents.Add (new LogEvent {
580                                 Subcategory = e.Subcategory,
581                                 Origin = e.File,
582                                 Line = e.LineNumber,
583                                 EndLine = e.EndLineNumber,
584                                 Column = e.ColumnNumber,
585                                 EndColumn = e.EndColumnNumber,
586                                 Code = e.Code,
587                                 Message = e.Message,
588                         });
589                 }
590         }
591
592         class TestToolTask : ToolTask {
593
594                 protected override string ToolName {
595                         get { return "TestTool.exe"; }
596                 }
597
598                 protected override string GenerateFullPathToTool ()
599                 {
600                         return "";
601                 }
602         }
603
604         class MockBuildEngine : IBuildEngine
605         {
606                 public int ColumnNumberOfTaskNode {
607                         get {
608                                 return 0;
609                         }
610                 }
611
612                 public bool ContinueOnError {
613                         get {
614                                 throw new NotImplementedException ();
615                         }
616                 }
617
618                 public int LineNumberOfTaskNode {
619                         get {
620                                 return 0;
621                         }
622                 }
623
624                 public string ProjectFileOfTaskNode {
625                         get {
626                                 return "ProjectFileOfTaskNode";
627                         }
628                 }
629
630                 public bool BuildProjectFile (string projectFileName, string[] targetNames, IDictionary globalProperties, IDictionary targetOutputs)
631                 {
632                         throw new NotImplementedException ();
633                 }
634
635                 public void LogCustomEvent (CustomBuildEventArgs e)
636                 {
637                 }
638
639                 public void LogErrorEvent (BuildErrorEventArgs e)
640                 {
641                         Console.WriteLine (e.Message);
642                 }
643
644                 public void LogMessageEvent (BuildMessageEventArgs e)
645                 {
646                 }
647
648                 public void LogWarningEvent (BuildWarningEventArgs e)
649                 {
650                 }
651         }
652
653         class TestExecuteToolTask : ToolTask
654         {
655                 public Action<string, string, string> OnExecuteTool;
656                 public string FullPathToTool;
657
658                 protected override string ToolName {
659                         get { return "TestTool.exe"; }
660                 }
661
662                 protected override bool CallHostObjectToExecute ()
663                 {
664                         return base.CallHostObjectToExecute ();
665                 }
666
667                 protected override string GenerateFullPathToTool ()
668                 {
669                         return FullPathToTool;
670                 }
671
672                 protected override int ExecuteTool (string pathToTool, string responseFileCommands, string commandLineCommands)
673                 {
674                         if (OnExecuteTool != null)
675                                 OnExecuteTool (pathToTool, responseFileCommands, commandLineCommands);
676
677                         return 0;
678                 }
679         }
680 }
681