[process] Allocate a handle even for non-child processes (#4393)
[mono.git] / mcs / class / System / Test / System.Diagnostics / ProcessTest.cs
1 //
2 // ProcessTest.cs - NUnit Test Cases for System.Diagnostics.Process
3 //
4 // Authors:
5 //   Gert Driesen (drieseng@users.sourceforge.net)
6 //   Robert Jordan <robertj@gmx.net>
7 //
8 // (C) 2007 Gert Driesen
9 // 
10
11 using System;
12 using System.ComponentModel;
13 using System.Diagnostics;
14 using System.IO;
15 using System.Text;
16 using System.Threading;
17 using System.Runtime.InteropServices;
18
19 using NUnit.Framework;
20
21 namespace MonoTests.System.Diagnostics
22 {
23         [TestFixture]
24         public class ProcessTest
25         {
26                 [Test]
27                 public void GetProcessById_MachineName_Null ()
28                 {
29                         try {
30                                 Process.GetProcessById (1, (string) null);
31                                 Assert.Fail ("#1");
32                         } catch (ArgumentNullException ex) {
33                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
34                                 Assert.IsNotNull (ex.Message, "#3");
35                                 Assert.IsNotNull (ex.ParamName, "#4");
36                                 Assert.AreEqual ("machineName", ex.ParamName, "#5");
37                                 Assert.IsNull (ex.InnerException, "#6");
38                         }
39                 }
40
41                 [Test]
42                 public void GetProcesses_MachineName_Null ()
43                 {
44                         try {
45                                 Process.GetProcesses ((string) null);
46                                 Assert.Fail ("#1");
47                         } catch (ArgumentNullException ex) {
48                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
49                                 Assert.IsNotNull (ex.Message, "#3");
50                                 Assert.IsNotNull (ex.ParamName, "#4");
51                                 Assert.AreEqual ("machineName", ex.ParamName, "#5");
52                                 Assert.IsNull (ex.InnerException, "#6");
53                         }
54                 }
55
56                 [Test] // Covers #26363
57                 [NUnit.Framework.Category ("MobileNotWorking")]
58                 public void GetProcesses_StartTime ()
59                 {
60                         foreach (var p in Process.GetProcesses ()) {
61                                 if (!p.HasExited && p.StartTime.Year < 1800)
62                                         Assert.Fail ("Process should not be started since the 18th century.");
63                         }
64                 }
65
66                 [Test]
67                 public void PriorityClass_NotStarted ()
68                 {
69                         Process process = new Process ();
70                         try {
71                                 process.PriorityClass = ProcessPriorityClass.Normal;
72                                 Assert.Fail ("#A1");
73                         } catch (InvalidOperationException ex) {
74                                 // No process is associated with this object
75                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#A2");
76                                 Assert.IsNull (ex.InnerException, "#A3");
77                                 Assert.IsNotNull (ex.Message, "#A4");
78                         }
79
80                         try {
81                                 Assert.Fail ("#B1:" + process.PriorityClass);
82                         } catch (InvalidOperationException ex) {
83                                 // No process is associated with this object
84                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#B2");
85                                 Assert.IsNull (ex.InnerException, "#B3");
86                                 Assert.IsNotNull (ex.Message, "#B4");
87                         }
88                 }
89
90                 [Test]
91                 public void PriorityClass_Invalid ()
92                 {
93                         Process process = new Process ();
94                         try {
95                                 process.PriorityClass = (ProcessPriorityClass) 666;
96                                 Assert.Fail ("#1");
97                         } catch (InvalidEnumArgumentException ex) {
98                                 Assert.AreEqual (typeof (InvalidEnumArgumentException), ex.GetType (), "#2");
99                                 Assert.IsNull (ex.InnerException, "#3");
100                                 Assert.IsNotNull (ex.Message, "#4");
101                                 Assert.IsTrue (ex.Message.IndexOf ("666") != -1, "#5");
102                                 Assert.IsTrue (ex.Message.IndexOf (typeof (ProcessPriorityClass).Name) != -1, "#6");
103                                 Assert.IsNotNull (ex.ParamName, "#7");
104                                 Assert.AreEqual ("value", ex.ParamName, "#8");
105                         }
106                 }
107
108 #if MONO_FEATURE_PROCESS_START
109                 [Test] // Start ()
110                 public void Start1_FileName_Empty ()
111                 {
112                         Process process = new Process ();
113                         process.StartInfo = new ProcessStartInfo (string.Empty);
114
115                         // no shell
116                         process.StartInfo.UseShellExecute = false;
117                         try {
118                                 process.Start ();
119                                 Assert.Fail ("#A1");
120                         } catch (InvalidOperationException ex) {
121                                 // Cannot start process because a file name has
122                                 // not been provided
123                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#A2");
124                                 Assert.IsNull (ex.InnerException, "#A3");
125                                 Assert.IsNotNull (ex.Message, "#A4");
126                         }
127
128                         // shell
129                         process.StartInfo.UseShellExecute = true;
130                         try {
131                                 process.Start ();
132                                 Assert.Fail ("#B1");
133                         } catch (InvalidOperationException ex) {
134                                 // Cannot start process because a file name has
135                                 // not been provided
136                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#B2");
137                                 Assert.IsNull (ex.InnerException, "#B3");
138                                 Assert.IsNotNull (ex.Message, "#B4");
139                         }
140                 }
141
142                 [Test] // Start ()
143                 public void Start1_FileName_InvalidPathCharacters ()
144                 {
145                         if (RunningOnUnix)
146                                 // on unix, all characters are allowed
147                                 Assert.Ignore ("Running on Unix.");
148
149                         string systemDir = Environment.GetFolderPath (Environment.SpecialFolder.System);
150                         string exe = "\"" + Path.Combine (systemDir, "calc.exe") + "\"";
151
152                         Process process = new Process ();
153                         process.StartInfo = new ProcessStartInfo (exe);
154
155                         // no shell
156                         process.StartInfo.UseShellExecute = false;
157                         Assert.IsTrue (process.Start ());
158                         process.Kill ();
159
160                         // shell
161                         process.StartInfo.UseShellExecute = true;
162                         Assert.IsTrue (process.Start ());
163                         process.Kill ();
164                 }
165
166                 [Test] // Start ()
167                 public void Start1_FileName_NotFound ()
168                 {
169                         Process process = new Process ();
170                         string exe = RunningOnUnix ? exe = "/usr/bin/shouldnoteverexist"
171                                 : @"c:\shouldnoteverexist.exe";
172
173                         // absolute path, no shell
174                         process.StartInfo = new ProcessStartInfo (exe);
175                         process.StartInfo.UseShellExecute = false;
176                         try {
177                                 process.Start ();
178                                 Assert.Fail ("#A1");
179                         } catch (Win32Exception ex) {
180                                 // The system cannot find the file specified
181                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#A2");
182                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#A3");
183                                 Assert.IsNull (ex.InnerException, "#A4");
184                                 Assert.IsNotNull (ex.Message, "#A5");
185                                 Assert.AreEqual (2, ex.NativeErrorCode, "#A6");
186                         }
187
188                         // relative path, no shell
189                         process.StartInfo.FileName = "shouldnoteverexist.exe";
190                         process.StartInfo.UseShellExecute = false;
191                         try {
192                                 process.Start ();
193                                 Assert.Fail ("#B1");
194                         } catch (Win32Exception ex) {
195                                 // The system cannot find the file specified
196                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#B2");
197                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#B3");
198                                 Assert.IsNull (ex.InnerException, "#B4");
199                                 Assert.IsNotNull (ex.Message, "#B5");
200                                 Assert.AreEqual (2, ex.NativeErrorCode, "#B6");
201                         }
202
203                         if (RunningOnUnix)
204                                 Assert.Ignore ("On Unix and Mac OS X, we try " +
205                                         "to open any file (using xdg-open, ...)" +
206                                         " and we do not report an exception " +
207                                         "if this fails.");
208
209                         // absolute path, shell
210                         process.StartInfo.FileName = exe;
211                         process.StartInfo.UseShellExecute = true;
212                         try {
213                                 process.Start ();
214                                 Assert.Fail ("#C1");
215                         } catch (Win32Exception ex) {
216                                 // The system cannot find the file specified
217                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#C2");
218                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#C3");
219                                 Assert.IsNull (ex.InnerException, "#C4");
220                                 Assert.IsNotNull (ex.Message, "#C5");
221                                 Assert.AreEqual (2, ex.NativeErrorCode, "#C6");
222                         }
223
224                         // relative path, shell
225                         process.StartInfo.FileName = "shouldnoteverexist.exe";
226                         process.StartInfo.UseShellExecute = true;
227                         try {
228                                 process.Start ();
229                                 Assert.Fail ("#D1");
230                         } catch (Win32Exception ex) {
231                                 // The system cannot find the file specified
232                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#D2");
233                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#D3");
234                                 Assert.IsNull (ex.InnerException, "#D4");
235                                 Assert.IsNotNull (ex.Message, "#D5");
236                                 Assert.AreEqual (2, ex.NativeErrorCode, "#D6");
237                         }
238                 }
239
240                 [Test] // Start ()
241                 public void Start1_FileName_Null ()
242                 {
243                         Process process = new Process ();
244                         process.StartInfo = new ProcessStartInfo ((string) null);
245
246                         // no shell
247                         process.StartInfo.UseShellExecute = false;
248                         try {
249                                 process.Start ();
250                                 Assert.Fail ("#A1");
251                         } catch (InvalidOperationException ex) {
252                                 // Cannot start process because a file name has
253                                 // not been provided
254                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#A2");
255                                 Assert.IsNull (ex.InnerException, "#A3");
256                                 Assert.IsNotNull (ex.Message, "#A4");
257                         }
258
259                         // shell
260                         process.StartInfo.UseShellExecute = true;
261                         try {
262                                 process.Start ();
263                                 Assert.Fail ("#B1");
264                         } catch (InvalidOperationException ex) {
265                                 // Cannot start process because a file name has
266                                 // not been provided
267                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#B2");
268                                 Assert.IsNull (ex.InnerException, "#B3");
269                                 Assert.IsNotNull (ex.Message, "#B4");
270                         }
271                 }
272
273                 [Test] // Start ()
274                 public void Start1_FileName_Whitespace ()
275                 {
276                         Process process = new Process ();
277                         process.StartInfo = new ProcessStartInfo (" ");
278                         process.StartInfo.UseShellExecute = false;
279                         try {
280                                 process.Start ();
281                                 Assert.Fail ("#1");
282                         } catch (Win32Exception ex) {
283                                 // The system cannot find the file specified
284                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#2");
285                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#3");
286                                 Assert.IsNull (ex.InnerException, "#4");
287                                 Assert.IsNotNull (ex.Message, "#5");
288                                 // TODO: On windows we get ACCESS_DENIED (5) instead of FILE_NOT_FOUND (2) and .NET
289                                 // gives ERROR_INVALID_PARAMETER (87). See https://bugzilla.xamarin.com/show_bug.cgi?id=44514
290                                 Assert.IsTrue (ex.NativeErrorCode == 2 || ex.NativeErrorCode == 5 || ex.NativeErrorCode == 87, "#6");
291                         }
292                 }
293
294                 [Test] // Start (ProcessStartInfo)
295                 public void Start2_FileName_Empty ()
296                 {
297                         ProcessStartInfo startInfo = new ProcessStartInfo (string.Empty);
298
299                         // no shell
300                         startInfo.UseShellExecute = false;
301                         try {
302                                 Process.Start (startInfo);
303                                 Assert.Fail ("#A1");
304                         } catch (InvalidOperationException ex) {
305                                 // Cannot start process because a file name has
306                                 // not been provided
307                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#A2");
308                                 Assert.IsNull (ex.InnerException, "#A3");
309                                 Assert.IsNotNull (ex.Message, "#A4");
310                         }
311
312                         // shell
313                         startInfo.UseShellExecute = true;
314                         try {
315                                 Process.Start (startInfo);
316                                 Assert.Fail ("#B1");
317                         } catch (InvalidOperationException ex) {
318                                 // Cannot start process because a file name has
319                                 // not been provided
320                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#B2");
321                                 Assert.IsNull (ex.InnerException, "#B3");
322                                 Assert.IsNotNull (ex.Message, "#B4");
323                         }
324                 }
325
326                 [Test] // Start (ProcessStartInfo)
327                 public void Start2_FileName_NotFound ()
328                 {
329                         ProcessStartInfo startInfo = new ProcessStartInfo ();
330                         string exe = RunningOnUnix ? exe = "/usr/bin/shouldnoteverexist"
331                                 : @"c:\shouldnoteverexist.exe";
332
333                         // absolute path, no shell
334                         startInfo.FileName = exe;
335                         startInfo.UseShellExecute = false;
336                         try {
337                                 Process.Start (startInfo);
338                                 Assert.Fail ("#A1");
339                         } catch (Win32Exception ex) {
340                                 // The system cannot find the file specified
341                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#A2");
342                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#A3");
343                                 Assert.IsNull (ex.InnerException, "#A4");
344                                 Assert.IsNotNull (ex.Message, "#A5");
345                                 Assert.AreEqual (2, ex.NativeErrorCode, "#A6");
346                         }
347
348                         // relative path, no shell
349                         startInfo.FileName = "shouldnoteverexist.exe";
350                         startInfo.UseShellExecute = false;
351                         try {
352                                 Process.Start (startInfo);
353                                 Assert.Fail ("#B1");
354                         } catch (Win32Exception ex) {
355                                 // The system cannot find the file specified
356                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#B2");
357                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#B3");
358                                 Assert.IsNull (ex.InnerException, "#B4");
359                                 Assert.IsNotNull (ex.Message, "#B5");
360                                 Assert.AreEqual (2, ex.NativeErrorCode, "#B6");
361                         }
362
363                         if (RunningOnUnix)
364                                 Assert.Ignore ("On Unix and Mac OS X, we try " +
365                                         "to open any file (using xdg-open, ...)" +
366                                         " and we do not report an exception " +
367                                         "if this fails.");
368
369                         // absolute path, shell
370                         startInfo.FileName = exe;
371                         startInfo.UseShellExecute = true;
372                         try {
373                                 Process.Start (startInfo);
374                                 Assert.Fail ("#C1");
375                         } catch (Win32Exception ex) {
376                                 // The system cannot find the file specified
377                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#C2");
378                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#C3");
379                                 Assert.IsNull (ex.InnerException, "#C4");
380                                 Assert.IsNotNull (ex.Message, "#C5");
381                                 Assert.AreEqual (2, ex.NativeErrorCode, "#C6");
382                         }
383
384                         // relative path, shell
385                         startInfo.FileName = "shouldnoteverexist.exe";
386                         startInfo.UseShellExecute = true;
387                         try {
388                                 Process.Start (startInfo);
389                                 Assert.Fail ("#D1");
390                         } catch (Win32Exception ex) {
391                                 // The system cannot find the file specified
392                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#D2");
393                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#D3");
394                                 Assert.IsNull (ex.InnerException, "#D4");
395                                 Assert.IsNotNull (ex.Message, "#D5");
396                                 Assert.AreEqual (2, ex.NativeErrorCode, "#D6");
397                         }
398                 }
399
400                 [Test] // Start (ProcessStartInfo)
401                 public void Start2_FileName_Null ()
402                 {
403                         ProcessStartInfo startInfo = new ProcessStartInfo ((string) null);
404
405                         // no shell
406                         startInfo.UseShellExecute = false;
407                         try {
408                                 Process.Start (startInfo);
409                                 Assert.Fail ("#A1");
410                         } catch (InvalidOperationException ex) {
411                                 // Cannot start process because a file name has
412                                 // not been provided
413                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#A2");
414                                 Assert.IsNull (ex.InnerException, "#A3");
415                                 Assert.IsNotNull (ex.Message, "#A4");
416                         }
417
418                         // shell
419                         startInfo.UseShellExecute = true;
420                         try {
421                                 Process.Start (startInfo);
422                                 Assert.Fail ("#B1");
423                         } catch (InvalidOperationException ex) {
424                                 // Cannot start process because a file name has
425                                 // not been provided
426                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#B2");
427                                 Assert.IsNull (ex.InnerException, "#B3");
428                                 Assert.IsNotNull (ex.Message, "#B4");
429                         }
430                 }
431
432                 [Test] // Start (ProcessStartInfo)
433                 public void Start2_FileName_Whitespace ()
434                 {
435                         ProcessStartInfo startInfo = new ProcessStartInfo (" ");
436                         startInfo.UseShellExecute = false;
437                         try {
438                                 Process.Start (startInfo);
439                                 Assert.Fail ("#1");
440                         } catch (Win32Exception ex) {
441                                 // The system cannot find the file specified
442                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#2");
443                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#3");
444                                 Assert.IsNull (ex.InnerException, "#4");
445                                 Assert.IsNotNull (ex.Message, "#5");
446                                 // TODO: On windows we get ACCESS_DENIED (5) instead of FILE_NOT_FOUND (2) and .NET
447                                 // gives ERROR_INVALID_PARAMETER (87). See https://bugzilla.xamarin.com/show_bug.cgi?id=44514
448                                 Assert.IsTrue (ex.NativeErrorCode == 2 || ex.NativeErrorCode == 5 || ex.NativeErrorCode == 87, "#6");
449                         }
450                 }
451
452                 [Test] // Start (ProcessStartInfo)
453                 public void Start2_StartInfo_Null ()
454                 {
455                         try {
456                                 Process.Start ((ProcessStartInfo) null);
457                                 Assert.Fail ("#1");
458                         } catch (ArgumentNullException ex) {
459                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
460                                 Assert.IsNull (ex.InnerException, "#3");
461                                 Assert.IsNotNull (ex.Message, "#4");
462                                 Assert.IsNotNull (ex.ParamName, "#5");
463                                 Assert.AreEqual ("startInfo", ex.ParamName, "#6");
464                         }
465                 }
466
467                 [Test] // Start (string)
468                 public void Start3_FileName_Empty ()
469                 {
470                         try {
471                                 Process.Start (string.Empty);
472                                 Assert.Fail ("#1");
473                         } catch (InvalidOperationException ex) {
474                                 // Cannot start process because a file name has
475                                 // not been provided
476                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#2");
477                                 Assert.IsNull (ex.InnerException, "#3");
478                                 Assert.IsNotNull (ex.Message, "#4");
479                         }
480                 }
481
482                 [Test] // Start (string)
483                 public void Start3_FileName_NotFound ()
484                 {
485                         if (RunningOnUnix)
486                                 Assert.Ignore ("On Unix and Mac OS X, we try " +
487                                         "to open any file (using xdg-open, ...)" +
488                                         " and we do not report an exception " +
489                                         "if this fails.");
490
491                         string exe = @"c:\shouldnoteverexist.exe";
492
493                         // absolute path, no shell
494                         try {
495                                 Process.Start (exe);
496                                 Assert.Fail ("#A1");
497                         } catch (Win32Exception ex) {
498                                 // The system cannot find the file specified
499                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#A2");
500                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#A3");
501                                 Assert.IsNull (ex.InnerException, "#A4");
502                                 Assert.IsNotNull (ex.Message, "#A5");
503                                 Assert.AreEqual (2, ex.NativeErrorCode, "#A6");
504                         }
505
506                         // relative path, no shell
507                         try {
508                                 Process.Start ("shouldnoteverexist.exe");
509                                 Assert.Fail ("#B1");
510                         } catch (Win32Exception ex) {
511                                 // The system cannot find the file specified
512                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#B2");
513                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#B3");
514                                 Assert.IsNull (ex.InnerException, "#B4");
515                                 Assert.IsNotNull (ex.Message, "#B5");
516                                 Assert.AreEqual (2, ex.NativeErrorCode, "#B6");
517                         }
518                 }
519
520                 [Test] // Start (string)
521                 public void Start3_FileName_Null ()
522                 {
523                         try {
524                                 Process.Start ((string) null);
525                                 Assert.Fail ("#1");
526                         } catch (InvalidOperationException ex) {
527                                 // Cannot start process because a file name has
528                                 // not been provided
529                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#2");
530                                 Assert.IsNull (ex.InnerException, "#3");
531                                 Assert.IsNotNull (ex.Message, "#4");
532                         }
533                 }
534
535                 [Test] // Start (string, string)
536                 public void Start4_Arguments_Null ()
537                 {
538                         if (RunningOnUnix)
539                                 Assert.Ignore ("On Unix and Mac OS X, we try " +
540                                         "to open any file (using xdg-open, ...)" +
541                                         " and we do not report an exception " +
542                                         "if this fails.");
543
544                         string exe = @"c:\shouldnoteverexist.exe";
545
546                         try {
547                                 Process.Start ("whatever.exe", (string) null);
548                                 Assert.Fail ("#1");
549                         } catch (Win32Exception ex) {
550                                 // The system cannot find the file specified
551                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#B2");
552                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#B3");
553                                 Assert.IsNull (ex.InnerException, "#B4");
554                                 Assert.IsNotNull (ex.Message, "#B5");
555                                 Assert.AreEqual (2, ex.NativeErrorCode, "#B6");
556                         }
557                 }
558
559                 [Test] // Start (string, string)
560                 public void Start4_FileName_Empty ()
561                 {
562                         try {
563                                 Process.Start (string.Empty, string.Empty);
564                                 Assert.Fail ("#1");
565                         } catch (InvalidOperationException ex) {
566                                 // Cannot start process because a file name has
567                                 // not been provided
568                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#2");
569                                 Assert.IsNull (ex.InnerException, "#3");
570                                 Assert.IsNotNull (ex.Message, "#4");
571                         }
572                 }
573
574                 [Test] // Start (string, string)
575                 public void Start4_FileName_NotFound ()
576                 {
577                         if (RunningOnUnix)
578                                 Assert.Ignore ("On Unix and Mac OS X, we try " +
579                                         "to open any file (using xdg-open, ...)" +
580                                         " and we do not report an exception " +
581                                         "if this fails.");
582
583                         string exe = @"c:\shouldnoteverexist.exe";
584
585                         // absolute path, no shell
586                         try {
587                                 Process.Start (exe, string.Empty);
588                                 Assert.Fail ("#A1");
589                         } catch (Win32Exception ex) {
590                                 // The system cannot find the file specified
591                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#A2");
592                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#A3");
593                                 Assert.IsNull (ex.InnerException, "#A4");
594                                 Assert.IsNotNull (ex.Message, "#A5");
595                                 Assert.AreEqual (2, ex.NativeErrorCode, "#A6");
596                         }
597
598                         // relative path, no shell
599                         try {
600                                 Process.Start ("shouldnoteverexist.exe", string.Empty);
601                                 Assert.Fail ("#B1");
602                         } catch (Win32Exception ex) {
603                                 // The system cannot find the file specified
604                                 Assert.AreEqual (typeof (Win32Exception), ex.GetType (), "#B2");
605                                 Assert.AreEqual (-2147467259, ex.ErrorCode, "#B3");
606                                 Assert.IsNull (ex.InnerException, "#B4");
607                                 Assert.IsNotNull (ex.Message, "#B5");
608                                 Assert.AreEqual (2, ex.NativeErrorCode, "#B6");
609                         }
610                 }
611
612                 [Test]
613                 public void Start_UseShellExecuteWithEmptyUserName ()
614                 {
615                         if (RunningOnUnix)
616                                 Assert.Ignore ("On Unix and Mac OS X, we try " +
617                                         "to open any file (using xdg-open, ...)" +
618                                         " and we do not report an exception " +
619                                         "if this fails.");
620
621                         string exe = @"c:\shouldnoteverexist.exe";
622
623                         try {
624                                 Process p = new Process ();
625                                 p.StartInfo.FileName = exe;
626                                 p.StartInfo.UseShellExecute = true;
627                                 p.StartInfo.UserName = "";
628                                 p.Start ();
629                                 Assert.Fail ("#1");
630                         } catch (InvalidOperationException) {
631                                 Assert.Fail ("#2");
632                         } catch (Win32Exception) {
633                         }
634
635                         try {
636                                 Process p = new Process ();
637                                 p.StartInfo.FileName = exe;
638                                 p.StartInfo.UseShellExecute = true;
639                                 p.StartInfo.UserName = null;
640                                 p.Start ();
641                                 Assert.Fail ("#3");                             
642                         } catch (InvalidOperationException) {
643                                 Assert.Fail ("#4");
644                         } catch (Win32Exception) {
645                         }
646                 }
647                 
648                 [Test] // Start (string, string)
649                 public void Start4_FileName_Null ()
650                 {
651                         try {
652                                 Process.Start ((string) null, string.Empty);
653                                 Assert.Fail ("#1");
654                         } catch (InvalidOperationException ex) {
655                                 // Cannot start process because a file name has
656                                 // not been provided
657                                 Assert.AreEqual (typeof (InvalidOperationException), ex.GetType (), "#2");
658                                 Assert.IsNull (ex.InnerException, "#3");
659                                 Assert.IsNotNull (ex.Message, "#4");
660                         }
661                 }
662
663                 [Test]
664                 public void StartInfo ()
665                 {
666                         ProcessStartInfo startInfo = new ProcessStartInfo ();
667
668                         Process p = new Process ();
669                         Assert.IsNotNull (p.StartInfo, "#A1");
670                         p.StartInfo = startInfo;
671                         Assert.AreSame (startInfo, p.StartInfo, "#A2");
672                 }
673
674                 [Test]
675                 public void StartInfo_Null ()
676                 {
677                         Process p = new Process ();
678                         try {
679                                 p.StartInfo = null;
680                                 Assert.Fail ("#1");
681                         } catch (ArgumentNullException ex) {
682                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
683                                 Assert.IsNull (ex.InnerException, "#3");
684                                 Assert.IsNotNull (ex.Message, "#4");
685                                 Assert.IsNotNull (ex.ParamName, "#5");
686                                 Assert.AreEqual ("value", ex.ParamName, "#6");
687                         }
688                 }
689
690                 [Test]
691                 [NUnit.Framework.Category ("NotDotNet")]
692                 [NUnit.Framework.Category ("MobileNotWorking")]
693                 public void TestRedirectedOutputIsAsync ()
694                 {
695                         // Test requires cygwin, so we just bail out for now.
696                         if (Path.DirectorySeparatorChar == '\\')
697                                 Assert.Ignore ("Test requires cygwin.");
698                         
699                         Process p = new Process ();
700                         p.StartInfo = new ProcessStartInfo ("/bin/sh", "-c \"sleep 2; echo hello\"");
701                         p.StartInfo.RedirectStandardOutput = true;
702                         p.StartInfo.UseShellExecute = false;
703                         p.Start ();
704
705                         Stream stdout = p.StandardOutput.BaseStream;
706
707                         byte [] buffer = new byte [200];
708
709                         // start async Read operation
710                         DateTime start = DateTime.Now;
711                         IAsyncResult ar = stdout.BeginRead (buffer, 0, buffer.Length,
712                                                             new AsyncCallback (Read), stdout);
713
714                         Assert.IsTrue ((DateTime.Now - start).TotalMilliseconds < 1000, "#01 BeginRead was not async");
715                         p.WaitForExit ();
716                         Assert.AreEqual (0, p.ExitCode, "#02 script failure");
717
718                         /*
719                         ar.AsyncWaitHandle.WaitOne (2000, false);
720                         if (bytesRead < "hello".Length)
721                                 Assert.Fail ("#03 got {0} bytes", bytesRead);
722                         Assert.AreEqual ("hello", Encoding.Default.GetString (buffer, 0, 5), "#04");
723                         */
724                 }
725                 
726                 void Read (IAsyncResult ar)
727                 {
728                         Stream stm = (Stream) ar.AsyncState;
729                         bytesRead = stm.EndRead (ar);
730                 }
731
732                 static bool RunningOnUnix {
733                         get {
734                                 int p = (int)Environment.OSVersion.Platform;
735                                 return ((p == 128) || (p == 4) || (p == 6));
736                         }
737                 }
738
739                 public int bytesRead = -1;
740
741                 [Test]
742                 [NUnit.Framework.Category ("MobileNotWorking")]
743                 // This was for bug #459450
744                 public void TestEventRaising ()
745                 {
746                         EventWaitHandle errorClosed = new ManualResetEvent(false);
747                         EventWaitHandle outClosed = new ManualResetEvent(false);
748                         EventWaitHandle exited = new ManualResetEvent(false);
749
750                         Process p = new Process();
751                         
752                         p.StartInfo = GetCrossPlatformStartInfo ();
753                         p.StartInfo.UseShellExecute = false;
754                         p.StartInfo.RedirectStandardOutput = true;
755                         p.StartInfo.RedirectStandardError = true;
756                         p.StartInfo.RedirectStandardInput = false;
757                         p.OutputDataReceived += (object sender, DataReceivedEventArgs e) => {
758                                 if (e.Data == null) {
759                                         outClosed.Set();
760                                 }
761                         };
762                         
763                         p.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => {
764                                 if (e.Data == null) {
765                                         errorClosed.Set();
766                                 }
767                         };
768                         
769                         p.Exited += (object sender, EventArgs e) => {
770                                 exited.Set ();
771                         };
772                         
773                         p.EnableRaisingEvents = true;
774
775                         p.Start();
776
777                         p.BeginErrorReadLine();
778                         p.BeginOutputReadLine();
779
780                         Console.WriteLine("started, waiting for handles");
781                         bool r = WaitHandle.WaitAll(new WaitHandle[] { errorClosed, outClosed, exited }, 10000, false);
782
783                         Assert.AreEqual (true, r, "Null Argument Events Raised");
784                 }
785
786                 [Test]
787                 [NUnit.Framework.Category ("MobileNotWorking")]
788                 public void TestEnableEventsAfterExitedEvent ()
789                 {
790                         Process p = new Process ();
791                         
792                         p.StartInfo = GetCrossPlatformStartInfo ();
793                         p.StartInfo.UseShellExecute = false;
794                         p.StartInfo.RedirectStandardOutput = true;
795                         p.StartInfo.RedirectStandardError = true;
796
797                         var exitedCalledCounter = 0;
798                         var exited = new ManualResetEventSlim ();
799                         p.Exited += (object sender, EventArgs e) => {
800                                 exitedCalledCounter++;
801                                 Assert.IsTrue (p.HasExited);
802                                 exited.Set ();
803                         };
804
805                         p.EnableRaisingEvents = true;
806
807                         p.Start ();
808                         p.BeginErrorReadLine ();
809                         p.BeginOutputReadLine ();
810                         p.WaitForExit ();
811
812                         exited.Wait (10000);
813                         Assert.AreEqual (1, exitedCalledCounter);
814                         Thread.Sleep (50);
815                         Assert.AreEqual (1, exitedCalledCounter);
816                 }
817
818                 [Test]
819                 [NUnit.Framework.Category ("MobileNotWorking")]
820                 public void TestEnableEventsBeforeExitedEvent ()
821                 {
822                         Process p = new Process ();
823                         
824                         p.StartInfo = GetCrossPlatformStartInfo ();
825                         p.StartInfo.UseShellExecute = false;
826                         p.StartInfo.RedirectStandardOutput = true;
827                         p.StartInfo.RedirectStandardError = true;
828
829                         p.EnableRaisingEvents = true;
830
831                         var exitedCalledCounter = 0;
832                         var exited = new ManualResetEventSlim ();
833                         p.Exited += (object sender, EventArgs e) => {
834                                 exitedCalledCounter++;
835                                 Assert.IsTrue (p.HasExited);
836                                 exited.Set ();
837                         };
838
839                         p.Start ();
840                         p.BeginErrorReadLine ();
841                         p.BeginOutputReadLine ();
842                         p.WaitForExit ();
843
844                         Assert.IsTrue (exited.Wait (10000));
845                         Assert.AreEqual (1, exitedCalledCounter);
846                         Thread.Sleep (50);
847                         Assert.AreEqual (1, exitedCalledCounter);
848                 }
849
850                 [Test]
851                 [NUnit.Framework.Category ("MobileNotWorking")]
852                 public void TestDisableEventsBeforeExitedEvent ()
853                 {
854                         Process p = new Process ();
855                         
856                         p.StartInfo = GetCrossPlatformStartInfo ();
857                         p.StartInfo.UseShellExecute = false;
858                         p.StartInfo.RedirectStandardOutput = true;
859                         p.StartInfo.RedirectStandardError = true;
860
861                         p.EnableRaisingEvents = false;
862
863                         ManualResetEvent mre = new ManualResetEvent (false);
864                         p.Exited += (object sender, EventArgs e) => {
865                                 mre.Set ();
866                         };
867
868                         p.Start ();
869                         p.BeginErrorReadLine ();
870                         p.BeginOutputReadLine ();
871                         p.WaitForExit ();
872
873                         Assert.IsFalse (mre.WaitOne (1000));
874                 }
875
876                 ProcessStartInfo GetCrossPlatformStartInfo ()
877                 {
878                         if (RunningOnUnix) {
879                                 string path;
880 #if MONODROID
881                                 path = "/system/bin/ls";
882 #else
883                                 path = "/bin/ls";
884 #endif
885                                 return new ProcessStartInfo (path, "/");
886                         } else
887                                 return new ProcessStartInfo ("help", "");
888                 }
889
890                 ProcessStartInfo GetEchoCrossPlatformStartInfo ()
891                 {
892                         if (RunningOnUnix) {
893                                 string path;
894 #if MONODROID
895                                 path = "/system/bin/cat";
896 #else
897                                 path = "/bin/cat";
898 #endif
899                                 return new ProcessStartInfo (path);
900                         } else {
901                                 var psi = new ProcessStartInfo ("findstr");
902                                 psi.Arguments = "\"^\"";
903                                 return psi;
904                         }
905                 }
906 #endif // MONO_FEATURE_PROCESS_START
907
908                 [Test]
909                 public void ProcessName_NotStarted ()
910                 {
911                         Process p = new Process ();
912                         Exception e = null;
913                         try {
914                                 String.IsNullOrEmpty (p.ProcessName);
915                         } catch (Exception ex) {
916                                 e = ex;
917                         }
918                         
919                         Assert.IsNotNull (e, "ProcessName should raise if process was not started");
920                         
921                         //msg should be "No process is associated with this object"
922                         Assert.AreEqual (e.GetType (), typeof (InvalidOperationException),
923                                          "exception should be IOE, I got: " + e.GetType ().Name);
924                         
925                         Assert.IsNull (e.InnerException, "IOE inner exception should be null");
926                 }
927                 
928 #if MONO_FEATURE_PROCESS_START
929                 [Test]
930                 [NUnit.Framework.Category ("MobileNotWorking")]
931                 public void ProcessName_AfterExit ()
932                 {
933                         Process p = new Process ();
934                         p.StartInfo = GetCrossPlatformStartInfo ();
935                         p.StartInfo.UseShellExecute = false;
936                         p.StartInfo.RedirectStandardOutput = true;
937                         p.StartInfo.RedirectStandardError = true;
938                         p.Start ();
939                         p.BeginErrorReadLine();
940                         p.BeginOutputReadLine();
941                         p.WaitForExit ();
942                         String.IsNullOrEmpty (p.ExitCode + "");
943                         
944                         Exception e = null;
945                         try {
946                                 String.IsNullOrEmpty (p.ProcessName);
947                         } catch (Exception ex) {
948                                 e = ex;
949                         }
950                         
951                         Assert.IsNotNull (e, "ProcessName should raise if process was finished");
952                         
953                         //msg should be "Process has exited, so the requested information is not available"
954                         Assert.AreEqual (e.GetType (), typeof (InvalidOperationException),
955                                          "exception should be IOE, I got: " + e.GetType ().Name);
956                         
957                         Assert.IsNull (e.InnerException, "IOE inner exception should be null");
958                 }
959 #endif // MONO_FEATURE_PROCESS_START
960
961                 [Test]
962                 public void Handle_ThrowsOnNotStarted ()
963                 {
964                         Process p = new Process ();
965                         try {
966                                 var x = p.Handle;
967                                 Assert.Fail ("Handle should throw for unstated procs, but returned " + x);
968                         } catch (InvalidOperationException) {
969                         }
970                 }
971
972                 [Test]
973                 public void HasExitedCurrent () {
974                         Assert.IsFalse (Process.GetCurrentProcess ().HasExited);
975                 }
976
977 #if MONO_FEATURE_PROCESS_START
978                 [Test]
979                 [NUnit.Framework.Category ("MobileNotWorking")]
980                 public void DisposeWithDisposedStreams ()
981                 {
982                         var psi = GetCrossPlatformStartInfo ();
983                         psi.RedirectStandardInput = true;
984                         psi.RedirectStandardOutput = true;
985                         psi.UseShellExecute = false;
986
987                         var p = Process.Start (psi);
988                         p.StandardInput.BaseStream.Dispose ();
989                         p.StandardOutput.BaseStream.Dispose ();
990                         p.Dispose ();
991                 }
992
993                 [Test]
994                 [NUnit.Framework.Category ("MobileNotWorking")]
995                 public void StandardInputWrite ()
996                 {
997                         var psi = GetEchoCrossPlatformStartInfo ();
998                         psi.RedirectStandardInput = true;
999                         psi.RedirectStandardOutput = true;
1000                         psi.UseShellExecute = false;
1001
1002                         using (var p = Process.Start (psi)) {
1003                                 // drain stdout
1004                                 p.OutputDataReceived += (s, e) => {};
1005                                 p.BeginOutputReadLine ();
1006
1007                                 for (int i = 0; i < 1024 * 9; ++i) {
1008                                         p.StandardInput.Write ('x');
1009                                         if (i > 0 && i % 128 == 0)
1010                                                 p.StandardInput.WriteLine ();
1011                                 }
1012
1013                                 p.StandardInput.Close ();
1014
1015                                 p.WaitForExit ();
1016                         }
1017                 }
1018 #endif // MONO_FEATURE_PROCESS_START
1019
1020                 [Test]
1021                 public void Modules () {
1022                         var modules = Process.GetCurrentProcess ().Modules;
1023                         foreach (var a in AppDomain.CurrentDomain.GetAssemblies ()) {
1024                                 var found = false;
1025                                 var name = a.GetName ();
1026
1027                                 StringBuilder sb = new StringBuilder ();
1028                                 sb.AppendFormat ("Could not found: {0} {1}\n", name.Name, name.Version);
1029                                 sb.AppendLine ("Looked in modules:");
1030
1031                                 foreach (var o in modules) {
1032                                         var m = (ProcessModule) o;
1033
1034                                         sb.AppendFormat ("   {0} {1}.{2}.{3}\n", m.FileName.ToString (),
1035                                                         m.FileVersionInfo.FileMajorPart,
1036                                                         m.FileVersionInfo.FileMinorPart,
1037                                                         m.FileVersionInfo.FileBuildPart);
1038
1039                                         if (!m.FileName.StartsWith ("[In Memory] " + name.Name))
1040                                                 continue;
1041
1042                                         var fv = m.FileVersionInfo;
1043                                         if (fv.FileBuildPart != name.Version.Build ||
1044                                                 fv.FileMinorPart != name.Version.Minor ||
1045                                                 fv.FileMajorPart != name.Version.Major)
1046                                                 continue;
1047
1048                                         found = true;
1049                                 }
1050
1051                                 Assert.IsTrue (found, sb.ToString ());
1052                         }
1053                 }
1054
1055 #if MONO_FEATURE_PROCESS_START
1056                 [Test]
1057                 [NUnit.Framework.Category ("MobileNotWorking")]
1058                 [ExpectedException (typeof (InvalidOperationException))]
1059                 public void TestDoubleBeginOutputReadLine ()
1060                 {
1061                         using (Process p = new Process ()) {
1062                                 p.StartInfo = GetCrossPlatformStartInfo ();
1063                                 p.StartInfo.UseShellExecute = false;
1064                                 p.StartInfo.RedirectStandardOutput = true;
1065                                 p.StartInfo.RedirectStandardError = true;
1066
1067                                 p.Start ();
1068
1069                                 p.BeginOutputReadLine ();
1070                                 p.BeginOutputReadLine ();
1071
1072                                 Assert.Fail ();
1073                         }
1074                 }
1075
1076                 [Test]
1077                 [NUnit.Framework.Category ("MobileNotWorking")]
1078                 [ExpectedException (typeof (InvalidOperationException))]
1079                 public void TestDoubleBeginErrorReadLine ()
1080                 {
1081                         using (Process p = new Process ()) {
1082                                 p.StartInfo = GetCrossPlatformStartInfo ();
1083                                 p.StartInfo.UseShellExecute = false;
1084                                 p.StartInfo.RedirectStandardOutput = true;
1085                                 p.StartInfo.RedirectStandardError = true;
1086
1087                                 p.Start ();
1088
1089                                 p.BeginErrorReadLine ();
1090                                 p.BeginErrorReadLine ();
1091
1092                                 Assert.Fail ();
1093                         }
1094                 }
1095
1096                 [Test]
1097                 [NUnit.Framework.Category ("MobileNotWorking")]
1098                 public void TestExitedRaisedTooSoon ()
1099                 {
1100                         if (!RunningOnUnix)
1101                                 Assert.Ignore ("using sleep command, only available on unix");
1102
1103                         int sleeptime = 5;
1104
1105                         using (Process p = Process.Start("sleep", sleeptime.ToString ())) {
1106                                 ManualResetEvent mre = new ManualResetEvent (false);
1107
1108                                 p.EnableRaisingEvents = true;
1109                                 p.Exited += (sender, e) => {
1110                                         mre.Set ();
1111                                 };
1112
1113                                 Assert.IsFalse (mre.WaitOne ((sleeptime - 2) * 1000), "Exited triggered before the process returned");
1114                         }
1115                 }
1116 #endif // MONO_FEATURE_PROCESS_START
1117
1118                 [Test]
1119                 public void GetProcessesByName()
1120                 {
1121                         // This should return Process[0] or a Process[] with all the "foo" programs running
1122                         Process.GetProcessesByName ("foo");
1123                 }
1124
1125                 [Test]
1126                 [ExpectedException(typeof(InvalidOperationException))]
1127                 public void HigherPrivilegeProcessName ()
1128                 {
1129                         if (!RunningOnUnix)
1130                                 Assert.Ignore ("accessing pid 1, only available on unix");
1131
1132                         string v = Process.GetProcessById (1).ProcessName;
1133                 }
1134
1135                 [Test]
1136                 public void NonChildProcessWaitForExit ()
1137                 {
1138                         if (!RunningOnUnix)
1139                                 Assert.Ignore ("accessing parent pid, only available on unix");
1140
1141                         using (Process process = Process.GetProcessById (getppid ()))
1142                         {
1143                                 Assert.IsFalse (process.WaitForExit (10), "#1");
1144                                 Assert.IsFalse (process.HasExited, "#2");
1145                                 Assert.Throws<InvalidOperationException>(delegate { int exitCode = process.ExitCode; }, "#3");
1146
1147                                 process.Exited += (s, e) => Assert.Fail ("#4");
1148
1149                                 Assert.IsFalse (process.WaitForExit (10), "#5");
1150                                 Assert.IsFalse (process.HasExited, "#6");
1151                                 Assert.Throws<InvalidOperationException>(delegate { int exitCode = process.ExitCode; }, "#7");
1152                         }
1153                 }
1154
1155                 [Test]
1156                 public void NonChildProcessName ()
1157                 {
1158                         if (!RunningOnUnix)
1159                                 Assert.Ignore ("accessing parent pid, only available on unix");
1160
1161                         using (Process process = Process.GetProcessById (getppid ()))
1162                         {
1163                                 string pname = process.ProcessName;
1164                                 Assert.IsNotNull (pname, "#1");
1165                                 AssertHelper.IsNotEmpty (pname, "#2");
1166                         }
1167                 }
1168
1169                 [Test]
1170                 public void NonChildProcessId ()
1171                 {
1172                         if (!RunningOnUnix)
1173                                 Assert.Ignore ("accessing parent pid, only available on unix");
1174
1175                         int ppid;
1176                         using (Process process = Process.GetProcessById (ppid = getppid ()))
1177                         {
1178                                 int pid = process.Id;
1179                                 Assert.AreEqual (ppid, pid, "#1");
1180                                 AssertHelper.Greater (pid, 0, "#2");
1181                         }
1182                 }
1183
1184                 [DllImport ("libc")]
1185                 static extern int getppid();
1186         }
1187 }