Merge pull request #1909 from esdrubal/reflection
[mono.git] / mcs / class / System.Web / Test / System.Web / HttpResponseTest.cs
1 //
2 // System.Web.HttpResponseTest.cs - Unit tests for System.Web.HttpResponse
3 //
4 // Author:
5 //      Miguel de Icaza  <miguel@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.Collections;
31 using System.Collections.Specialized;
32 using System.Configuration.Provider;
33 using System.IO;
34 using System.Text;
35 using System.Web;
36 using System.Web.Routing;
37 using System.Web.Caching;
38
39 using NUnit.Framework;
40
41 using MonoTests.Common;
42
43 namespace MonoTests.System.Web {
44
45         public class FakeHttpWorkerRequest2 : HttpWorkerRequest {
46                 public Hashtable KnownResponseHeaders;
47                 public Hashtable UnknownResponseHeaders;
48                 public int return_kind;
49                 
50                 public FakeHttpWorkerRequest2 (int re)
51                 {
52                         KnownResponseHeaders = CollectionsUtil.CreateCaseInsensitiveHashtable();
53                         UnknownResponseHeaders = CollectionsUtil.CreateCaseInsensitiveHashtable();
54                         return_kind = re;
55                 }
56                 
57                 public override string GetUriPath()
58                 {
59                         return "/fake";
60                 }
61                 
62                 public override string GetQueryString()
63                 {
64                         return "GetQueryString";
65                 }
66                 
67                 public override string GetRawUrl()
68                 {
69                         return "/GetRawUrl";
70                 }
71                 
72                 public override string GetHttpVerbName()
73                 {
74                         return "GET";
75                 }
76                 
77                 public override string GetHttpVersion()
78                 {
79                         if (return_kind == 1)
80                                 return "HTTP/1.0";
81                         else
82                                 return "HTTP/1.1";
83                 }
84                 
85                 public override string GetRemoteAddress()
86                 {
87                         return "__GetRemoteAddress";
88                         }
89         
90                 public override int GetRemotePort()
91                 {
92                         return 1010;
93                 }
94                 
95                 public override string GetLocalAddress()
96                 {
97                         return "GetLocalAddress";
98                 }
99                 
100                 public override string GetAppPath ()
101                 {
102                         return "AppPath";
103                 }
104                 
105                 public override int GetLocalPort()
106                 {
107                         return 2020;
108                 }
109
110                 public bool status_sent;
111                 public int status_code;
112                 public string status_string;
113                 
114                 public override void SendStatus(int s, string x)
115                 {
116                         status_sent = true;
117                         status_code = s;
118                         status_string = x;
119                 }
120
121                 void AddHeader (Hashtable table, string header_name, object header)
122                 {
123                         object o = table [header_name];
124                         if (o == null)
125                                 table.Add (header_name, header);
126                         else {
127                                 ArrayList al = o as ArrayList;
128                                 if (al == null) {
129                                         al = new ArrayList ();
130                                         al.Add (o);
131                                         table [header_name] = al;
132                                 } else
133                                         al = o as ArrayList;
134                                 
135                                 al.Add (header);
136                         }
137                 }
138                 
139                 bool headers_sent;
140                 public override void SendKnownResponseHeader(int x, string j)
141                 {
142                         string header_name = HttpWorkerRequest.GetKnownRequestHeaderName (x);
143                         AddHeader (KnownResponseHeaders, header_name, new KnownResponseHeader (x, j));
144                         headers_sent = true;
145                 }
146                 
147                 public override void SendUnknownResponseHeader(string a, string b)
148                 {
149                         AddHeader (UnknownResponseHeaders, a, new UnknownResponseHeader (a, b));
150                         headers_sent = true;
151                 }
152
153                 bool data_sent;
154                 public byte [] data;
155                 public int data_len;
156                 public int total = 0;
157                 
158                 public override void SendResponseFromMemory(byte[] arr, int x)
159                 {
160                         data_sent = true;
161                         if (data != null) {
162                                 byte [] tmp = new byte [data.Length + x];
163                                 Array.Copy (data, tmp, data.Length);
164                                 Array.Copy (arr, 0, tmp, data.Length, x);
165                                 data = tmp;
166                                 data_len = data.Length;
167                         } else {
168                                 data = new byte [x];
169                                 for (int i = 0; i < x; i++)
170                                         data [i] = arr [i];
171                                 data_len = x;
172                         }
173                         total += x;
174                 }
175                 
176                 public override void SendResponseFromFile(string a, long b , long c)
177                 {
178                         data_sent = true;
179                 }
180                 
181                 public override void SendResponseFromFile (IntPtr a, long b, long c)
182                 {
183                         data_sent = true;
184                 }
185                 
186                 public override void FlushResponse(bool x)
187                 {
188                 }
189                 
190                 public override void EndOfRequest() {
191                 }
192                 
193                 public override string GetKnownRequestHeader (int index)
194                 {
195                         return null;
196                 }
197
198                 public bool OutputProduced {
199                         get {
200                                 return headers_sent || data_sent;
201                         }
202                 }
203         }
204
205         class KnownResponseHeader
206         {
207                 private int index;
208                 private string value;
209
210                 public KnownResponseHeader (int index, string value)
211                 {
212                         this.index = index;
213                         this.value = value;
214                 }
215
216                 public int Index {
217                         get { return index; }
218                 }
219
220                 public string Value {
221                         get { return value; }
222                 }
223         }
224
225         class UnknownResponseHeader
226         {
227                 private string name;
228                 private string value;
229
230                 public UnknownResponseHeader (string name, string value)
231                 {
232                         this.name = name;
233                         this.value = value;
234                 }
235
236                 public string Name {
237                         get { return name; }
238                 }
239
240                 public string Value {
241                         get { return value; }
242                 }
243         }
244
245         [TestFixture]
246         public class HttpResponseTest {
247                 public static HttpContext Cook (int re, out FakeHttpWorkerRequest2 f)
248                 {
249                         f = new FakeHttpWorkerRequest2 (re);
250                         HttpContext c = new HttpContext (f);
251
252                         return c;
253                 }
254
255                 [SetUp]
256                 public void SetUp ()
257                 {
258                         AppDomain.CurrentDomain.SetData (".appPath", AppDomain.CurrentDomain.BaseDirectory);
259                 }
260
261                 [Test]
262                 public void Test_Response ()
263                 {
264                         FakeHttpWorkerRequest2 f;
265                         HttpContext c = Cook (1, out f);
266
267                         c.Response.Write ("a");
268                         Assert.AreEqual (false, f.OutputProduced, "T1");
269                         c.Response.Flush ();
270                         Assert.AreEqual (1, f.data_len, "T2");
271                         c.Response.Write ("Hola");
272                         Assert.AreEqual (1, f.data_len, "T3");
273                         c.Response.Flush ();
274                         Assert.AreEqual (5, f.data_len, "T4");
275                         Assert.AreEqual ((byte) 'a', f.data [0], "T5");
276                         Assert.AreEqual ((byte) 'H', f.data [1], "T6");
277                         Assert.AreEqual ((byte) 'o', f.data [2], "T7");
278                         Assert.AreEqual ((byte) 'l', f.data [3], "T8");
279                         Assert.AreEqual ((byte) 'a', f.data [4], "T9");
280                 }
281
282                 [Test]
283                 public void TestResponse_Chunked ()
284                 {
285                         FakeHttpWorkerRequest2 f;
286                         HttpContext c = Cook (2, out f);
287
288                         c.Response.Write ("a");
289                         Assert.AreEqual (false, f.OutputProduced, "CT1");
290                         c.Response.Flush ();
291                         Assert.AreEqual (6, f.total, "CT2");
292                         c.Response.Write ("Hola");
293                         Assert.AreEqual (6, f.total, "CT3");
294                         c.Response.Flush ();
295                         
296                 }
297
298                 [Test]
299                 public void Status1 ()
300                 {
301                         FakeHttpWorkerRequest2 f;
302                         HttpContext c = Cook (2, out f);
303
304                         HttpResponse resp = c.Response;
305                         resp.Status = "200 Lalala";
306                         Assert.AreEqual (200, resp.StatusCode, "ST1");
307                         Assert.AreEqual ("Lalala", resp.StatusDescription, "ST2");
308
309                         resp.Status = "10000 La la la";
310                         Assert.AreEqual (10000, resp.StatusCode, "ST3");
311                         Assert.AreEqual ("La la la", resp.StatusDescription, "ST4");
312
313                         resp.Status = "-1 La la la";
314                         Assert.AreEqual (-1, resp.StatusCode, "ST5");
315                         Assert.AreEqual ("La la la", resp.StatusDescription, "ST6");
316
317                         resp.Status = "-200 La la la";
318                         Assert.AreEqual (-200, resp.StatusCode, "ST7");
319                         Assert.AreEqual ("La la la", resp.StatusDescription, "ST8");
320
321                         resp.Status = "200 ";
322                         Assert.AreEqual (200, resp.StatusCode, "ST7");
323                         Assert.AreEqual ("", resp.StatusDescription, "ST8");
324                 }
325
326                 [Test]
327                 public void Status2 ()
328                 {
329                         FakeHttpWorkerRequest2 f;
330                         HttpContext c = Cook (2, out f);
331
332                         HttpResponse resp = c.Response;
333                         try {
334                                 resp.Status = "200";
335                                 Assert.Fail ("#1");
336                         } catch (HttpException) {
337                         }
338                 }
339
340                 [Test]
341                 public void Status3 ()
342                 {
343                         FakeHttpWorkerRequest2 f;
344                         HttpContext c = Cook (2, out f);
345
346                         HttpResponse resp = c.Response;
347                         try {
348                                 resp.Status = "200\t";
349                                 Assert.Fail ("#1");
350                         } catch (HttpException) {
351                         }
352                 }
353
354                 [Test]
355                 public void Status4 ()
356                 {
357                         FakeHttpWorkerRequest2 f;
358                         HttpContext c = Cook (2, out f);
359
360                         HttpResponse resp = c.Response;
361
362                         Assert.AreEqual (200, resp.StatusCode, "STT1");
363                         Assert.AreEqual (HttpWorkerRequest.GetStatusDescription (200), resp.StatusDescription, "STT2");
364
365                         resp.StatusCode = 400;
366                         Assert.AreEqual (400, resp.StatusCode, "STT3");
367                         Assert.AreEqual (HttpWorkerRequest.GetStatusDescription (400), resp.StatusDescription, "STT4");
368
369                         resp.StatusDescription = "Something else";
370                         Assert.AreEqual (400, resp.StatusCode, "STT5");
371                         Assert.AreEqual ("Something else", resp.StatusDescription, "STT6");
372
373                         resp.StatusDescription = null;
374                         Assert.AreEqual (400, resp.StatusCode, "STT7");
375                         Assert.AreEqual (HttpWorkerRequest.GetStatusDescription (400), resp.StatusDescription, "STT8");
376                 }
377
378                 //
379                 // TODO: Add test for BinaryWrite and the various writes to check for Chunked Mode
380                 //`
381
382                 [Test]
383                 public void SetCacheability ()
384                 {
385                         FakeHttpWorkerRequest2 f;
386                         HttpContext c = Cook (1, out f);
387
388                         //
389                         // Basically the values from CacheControl are useless once Response.Cache is used
390                         //
391                         c.Response.Cache.SetCacheability (HttpCacheability.ServerAndNoCache);
392                         Assert.AreEqual ("private", c.Response.CacheControl, "C1");
393                         
394                         c.Response.Cache.SetCacheability (HttpCacheability.ServerAndPrivate);
395                         Assert.AreEqual ("private", c.Response.CacheControl, "C2");
396                         
397                         c.Response.Cache.SetCacheability (HttpCacheability.NoCache);
398                         Assert.AreEqual ("private", c.Response.CacheControl, "C3");
399                         
400                         c.Response.Cache.SetCacheability (HttpCacheability.Private);
401                         Assert.AreEqual ("private", c.Response.CacheControl, "C4");
402                         
403                         c.Response.Cache.SetCacheability (HttpCacheability.Server);
404                         Assert.AreEqual ("private", c.Response.CacheControl, "C5");
405                         
406                         c.Response.Cache.SetCacheability (HttpCacheability.Public);
407                         Assert.AreEqual ("private", c.Response.CacheControl, "C6");
408                 }
409
410                 //
411                 // Test the values allowed;  .NET only documents private and public, but
412                 // "no-cache" from the spec is also allowed
413                 //
414                 [Test]
415                 public void CacheControl ()
416                 {
417                         FakeHttpWorkerRequest2 f;
418                         HttpContext c = Cook (1, out f);
419
420                         // Default value.
421                         Assert.AreEqual ("private", c.Response.CacheControl, "D1");
422                                          
423                         c.Response.CacheControl = "private";
424                         Assert.AreEqual ("private", c.Response.CacheControl, "D2");
425
426                         c.Response.CacheControl = "public";
427                         Assert.AreEqual ("public", c.Response.CacheControl, "D3");
428                         
429                         c.Response.CacheControl = "no-cache";
430                         Assert.AreEqual ("no-cache", c.Response.CacheControl, "D4");
431
432                         c.Response.CacheControl = null;
433                         Assert.AreEqual ("private", c.Response.CacheControl, "D5");
434
435                         c.Response.CacheControl = "";
436                         Assert.AreEqual ("private", c.Response.CacheControl, "D6");
437                 }
438
439                 //
440                 // Just checks if the AddFileDepend* methods accept values, added after bug #342511
441                 [Test]
442                 public void AddFileDependencies ()
443                 {
444                         FakeHttpWorkerRequest2 f;
445                         HttpContext c = Cook (1, out f);
446
447                         ArrayList a = new ArrayList (1);
448                         a.Add ("somefile.txt");
449                         c.Response.AddFileDependencies (a);
450
451                         string[] sa = new string [1] {"somefile.txt"};
452                         c = Cook (1, out f);
453                         c.Response.AddFileDependencies (sa);
454
455                         c = Cook (1, out f);
456                         c.Response.AddFileDependency ("somefile.txt");
457                 }
458
459                 [Test] // bug #488702
460                 public void WriteHeaders ()
461                 {
462                         FakeHttpWorkerRequest2 f;
463                         HttpContext c = Cook (2, out f);
464
465                         HttpResponse resp = c.Response;
466                         resp.CacheControl = "public";
467                         resp.Cache.SetCacheability (HttpCacheability.NoCache);
468                         resp.ContentType = "text/xml";
469                         resp.AppendHeader ("Content-Disposition", "inline");
470                         resp.AppendHeader ("Content-Type", "application/ms-word");
471                         resp.AppendHeader ("Content-Length", "40");
472                         resp.AppendHeader ("Transfer-Encoding", "compress");
473                         resp.AppendHeader ("My-Custom-Header", "never");
474                         resp.AppendHeader ("My-Custom-Header", "always");
475
476                         Assert.AreEqual ("public", resp.CacheControl, "#A1");
477                         Assert.AreEqual ("application/ms-word", resp.ContentType, "#A2");
478                         Assert.AreEqual (0, f.KnownResponseHeaders.Count, "#A3");
479                         Assert.AreEqual (0, f.UnknownResponseHeaders.Count, "#A4");
480
481                         resp.Flush ();
482
483                         KnownResponseHeader known;
484
485                         Assert.AreEqual (6, f.KnownResponseHeaders.Count, "#B1");
486                         
487                         known = (KnownResponseHeader)f.KnownResponseHeaders ["Content-Length"];
488                         Assert.AreEqual (HttpWorkerRequest.HeaderContentLength, known.Index, "#B2");
489                         Assert.AreEqual ("40", known.Value, "#B3");
490                         
491                         known = (KnownResponseHeader)f.KnownResponseHeaders["Transfer-Encoding"];
492                         Assert.AreEqual (HttpWorkerRequest.HeaderTransferEncoding, known.Index, "#B4");
493                         Assert.AreEqual ("compress", known.Value, "#B5");
494                         
495                         known = (KnownResponseHeader)f.KnownResponseHeaders["Cache-Control"];
496                         Assert.AreEqual (HttpWorkerRequest.HeaderCacheControl, known.Index, "#B6");
497                         Assert.AreEqual ("no-cache", known.Value, "#B7");
498                         
499                         known = (KnownResponseHeader)f.KnownResponseHeaders["Pragma"];
500                         Assert.AreEqual (HttpWorkerRequest.HeaderPragma, known.Index, "#B8");
501                         Assert.AreEqual ("no-cache", known.Value, "#B9");
502                         
503                         known = (KnownResponseHeader)f.KnownResponseHeaders["Expires"];
504                         Assert.AreEqual (HttpWorkerRequest.HeaderExpires, known.Index, "#B10");
505                         Assert.AreEqual ("-1", known.Value, "#B11");
506                         
507                         known = (KnownResponseHeader)f.KnownResponseHeaders["Content-Type"];
508                         Assert.AreEqual (HttpWorkerRequest.HeaderContentType, known.Index, "#B12");
509                         Assert.AreEqual ("application/ms-word", known.Value, "#B13");
510
511                         UnknownResponseHeader unknown;
512
513                         Assert.AreEqual (3, f.UnknownResponseHeaders.Count, "#C1");
514
515                         unknown = (UnknownResponseHeader) f.UnknownResponseHeaders ["X-AspNet-Version"];
516                         Assert.AreEqual ("X-AspNet-Version", unknown.Name, "#C2");
517                         Assert.AreEqual (Environment.Version.ToString (3), unknown.Value, "#C3");
518
519                         unknown = (UnknownResponseHeader) f.UnknownResponseHeaders ["Content-Disposition"];
520                         Assert.AreEqual ("Content-Disposition", unknown.Name, "#C4");
521                         Assert.AreEqual ("inline", unknown.Value, "#C5");
522
523                         ArrayList al = f.UnknownResponseHeaders ["My-Custom-Header"] as ArrayList;
524                         Assert.AreEqual (2, al.Count, "#C6");
525
526                         unknown = (UnknownResponseHeader) al [0];
527                         Assert.AreEqual ("My-Custom-Header", unknown.Name, "#C7");
528                         Assert.AreEqual ("never", unknown.Value, "#C8");
529
530                         unknown = (UnknownResponseHeader) al [1];
531                         Assert.AreEqual ("My-Custom-Header", unknown.Name, "#C9");
532                         Assert.AreEqual ("always", unknown.Value, "#C10");
533                 }
534
535                 [Test] // pull #866
536                 public void WriteHeadersNoCharset ()
537                 {
538                         FakeHttpWorkerRequest2 f;
539                         HttpContext c = Cook (2, out f);
540
541                         HttpResponse resp = c.Response;
542                         resp.ContentType = "text/plain";
543
544                         Assert.AreEqual ("text/plain", resp.ContentType, "#A1");
545
546                         resp.Flush ();
547
548                         KnownResponseHeader known;
549
550                         Assert.LessOrEqual (1, f.KnownResponseHeaders.Count, "#B1");
551
552                         known = (KnownResponseHeader)f.KnownResponseHeaders ["Content-Type"];
553                         Assert.AreEqual (HttpWorkerRequest.HeaderContentType, known.Index, "#B2");
554                         Assert.AreEqual ("text/plain", known.Value, "#B3");
555                 }
556
557                 [Test] // pull #866
558                 public void WriteHeadersHasCharset ()
559                 {
560                         FakeHttpWorkerRequest2 f;
561                         HttpContext c = Cook (2, out f);
562
563                         HttpResponse resp = c.Response;
564                         resp.ContentType = "text/plain";
565                         resp.Charset = "big5";
566
567                         Assert.AreEqual ("text/plain", resp.ContentType, "#A1");
568                         Assert.AreEqual ("big5", resp.Charset, "#A2");
569
570                         resp.Flush ();
571
572                         KnownResponseHeader known;
573
574                         Assert.LessOrEqual (1, f.KnownResponseHeaders.Count, "#B1");
575
576                         known = (KnownResponseHeader)f.KnownResponseHeaders ["Content-Type"];
577                         Assert.AreEqual (HttpWorkerRequest.HeaderContentType, known.Index, "#B2");
578                         Assert.AreEqual ("text/plain; charset=big5", known.Value, "#B3");
579                 }
580
581                 [Test] // bug #485557
582                 [Category ("NotWorking")] // bug #488702
583                 public void ClearHeaders ()
584                 {
585                         FakeHttpWorkerRequest2 f;
586                         HttpContext c = Cook (2, out f);
587
588                         HttpResponse resp = c.Response;
589                         resp.CacheControl = "public";
590                         resp.Cache.SetCacheability (HttpCacheability.NoCache);
591                         resp.ContentType = "text/xml";
592                         resp.AppendHeader ("Content-Disposition", "inline");
593                         resp.AppendHeader ("Content-Type", "application/ms-word");
594                         resp.AppendHeader ("Content-Length", "40");
595                         resp.AppendHeader ("Transfer-Encoding", "compress");
596                         resp.AppendHeader ("My-Custom-Header", "never");
597                         resp.AppendHeader ("My-Custom-Header", "always");
598                         resp.ClearHeaders ();
599
600                         Assert.AreEqual ("private", resp.CacheControl, "#A1");
601                         Assert.AreEqual ("text/html", resp.ContentType, "#A2");
602                         Assert.AreEqual (0, f.KnownResponseHeaders.Count, "#A3");
603                         Assert.AreEqual (0, f.UnknownResponseHeaders.Count, "#A4");
604
605                         resp.Flush ();
606
607                         KnownResponseHeader known;
608
609                         Assert.AreEqual (3, f.KnownResponseHeaders.Count, "#B1");
610                         
611                         known = (KnownResponseHeader) f.KnownResponseHeaders ["Transfer-Encoding"];
612                         Assert.AreEqual (HttpWorkerRequest.HeaderTransferEncoding, known.Index, "#B2");
613                         Assert.AreEqual ("chunked", known.Value, "#B3");
614                         
615                         known = (KnownResponseHeader) f.KnownResponseHeaders ["Cache-Control"];
616                         Assert.AreEqual (HttpWorkerRequest.HeaderCacheControl, known.Index, "#B4");
617                         Assert.AreEqual ("private", known.Value, "#B5");
618                         
619                         known = (KnownResponseHeader) f.KnownResponseHeaders ["Content-Type"];
620                         Assert.AreEqual (HttpWorkerRequest.HeaderContentType, known.Index, "#B6");
621                         Assert.AreEqual ("text/html", known.Value, "#B7");
622
623                         Assert.AreEqual (1, f.UnknownResponseHeaders.Count, "#C1");
624                         UnknownResponseHeader unknown = (UnknownResponseHeader) f.UnknownResponseHeaders ["X-AspNet-Version"];
625                         Assert.AreEqual ("X-AspNet-Version", unknown.Name, "#C2");
626                         Assert.AreEqual (Environment.Version.ToString (3), unknown.Value, "#C3");
627                 }
628
629                 [Test]
630                 public void Constructor ()
631                 {
632                         var resp = new HttpResponse (null);
633                         Assert.IsNull (resp.Output, "#A1");
634                 }
635                 [Test]
636                 public void RedirectPermanent ()
637                 {
638                         FakeHttpWorkerRequest2 request;
639                         HttpContext context = Cook (1, out request);
640                         AssertExtensions.Throws<ArgumentNullException> (() => {
641                                 context.Response.RedirectPermanent (null);
642                         }, "#A1");
643
644                         AssertExtensions.Throws<ArgumentException> (() => {
645                                 context.Response.RedirectPermanent ("http://invalid\nurl.com");
646                         }, "#A2");
647
648                         AssertExtensions.Throws<ArgumentNullException> (() => {
649                                 context.Response.RedirectPermanent (null, true);
650                         }, "#A3");
651
652                         AssertExtensions.Throws<ArgumentException> (() => {
653                                 context.Response.RedirectPermanent ("http://invalid\nurl.com", true);
654                         }, "#A4");
655                 }
656
657                 [Test]
658                 public void RedirectToRoute ()
659                 {
660                         var resp = new HttpResponse (new StringWriter ());
661                         // Ho, ho, ho!
662                         AssertExtensions.Throws<NullReferenceException> (() => {
663                                 resp.RedirectToRoute ("SomeRoute");
664                         }, "#A1");
665
666                         FakeHttpWorkerRequest2 request;
667                         HttpContext context = Cook (1, out request);
668
669                         // From RouteCollection.GetVirtualPath
670                         AssertExtensions.Throws<ArgumentException> (() => {
671                                 context.Response.RedirectToRoute ("SomeRoute");
672                         }, "#A2");
673
674                         AssertExtensions.Throws<InvalidOperationException> (() => {
675                                 context.Response.RedirectToRoute (new { productId = "1", category = "widgets" });
676                         }, "#A3");
677                 }
678
679                 [Test]
680                 public void RemoveOutputCacheItem ()
681                 {
682                         AssertExtensions.Throws<ArgumentNullException> (() => {
683                                 HttpResponse.RemoveOutputCacheItem (null, "MyProvider");
684                         }, "#A1");
685
686                         AssertExtensions.Throws<ArgumentException> (() => {
687                                 HttpResponse.RemoveOutputCacheItem ("badPath", null);
688                         }, "#A2");
689
690                         Assert.IsNull (OutputCache.Providers, "#A3");
691                         HttpResponse.RemoveOutputCacheItem ("/Path", null);
692
693                         AssertExtensions.Throws<ProviderException> (() => {
694                                 HttpResponse.RemoveOutputCacheItem ("/Path", String.Empty);
695                         }, "#A3");
696
697                         AssertExtensions.Throws<ProviderException> (() => {
698                                 HttpResponse.RemoveOutputCacheItem ("/Path", "MyProvider");
699                         }, "#A4");
700                 }
701
702                 [Test]
703                 public void OutputSetter ()
704                 {
705                         FakeHttpWorkerRequest2 request;
706                         HttpContext context = Cook (1, out request);
707
708                         Assert.IsNotNull (context.Response.Output, "#A1");
709                         context.Response.Output = null;
710                         Assert.IsNull (context.Response.Output, "#A2");
711
712                         // Classy...
713                         AssertExtensions.Throws<NullReferenceException> (() => {
714                                 context.Response.Write ('t');
715                         }, "#A3-1");
716
717                         AssertExtensions.Throws<NullReferenceException> (() => {
718                                 context.Response.Write ((object) 5);
719                         }, "#A3-2");
720
721                         AssertExtensions.Throws<NullReferenceException> (() => {
722                                 context.Response.Write ("string");
723                         }, "#A3-3");
724
725                         AssertExtensions.Throws<NullReferenceException> (() => {
726                                 context.Response.Write (new char [] { '1' }, 0, 1);
727                         }, "#A3-4");
728
729                         AssertExtensions.Throws<NullReferenceException> (() => {
730                                 context.Response.Write ((object) null);
731                         }, "#A3-5");
732                 }
733         }
734
735         [TestFixture]
736         public class HttpResponseOutputStreamTest
737         {
738                 FakeHttpWorkerRequest2 worker;
739                 HttpContext context;
740                 HttpResponse response;
741                 Stream out_stream;
742
743                 [SetUp]
744                 public void Setup ()
745                 {
746                         context = Cook (2, out worker);
747                         response = context.Response;
748                         out_stream = response.OutputStream;
749                 }
750
751                 [TearDown]
752                 public void TearDown ()
753                 {
754                         if (response != null)
755                                 response.Close ();
756                 }
757
758                 [Test]
759                 public void CanRead ()
760                 {
761                         Assert.IsFalse (out_stream.CanRead, "#1");
762                         out_stream.Close ();
763                         Assert.IsFalse (out_stream.CanRead, "#2");
764                 }
765
766                 [Test]
767                 public void CanSeek ()
768                 {
769                         Assert.IsFalse (out_stream.CanSeek, "#1");
770                         out_stream.Close ();
771                         Assert.IsFalse (out_stream.CanSeek, "#2");
772                 }
773
774                 [Test]
775                 public void CanWrite ()
776                 {
777                         Assert.IsTrue (out_stream.CanWrite, "#1");
778                         out_stream.Close ();
779                         Assert.IsTrue (out_stream.CanWrite, "#2");
780                 }
781
782                 [Test]
783                 public void Flush ()
784                 {
785                         byte [] buffer = Encoding.UTF8.GetBytes ("mono");
786                         out_stream.Write (buffer, 0, buffer.Length);
787                         out_stream.Flush ();
788                         Assert.AreEqual (0, worker.data_len);
789                 }
790
791                 [Test]
792                 public void Length ()
793                 {
794                         try {
795                                 long len = out_stream.Length;
796                                 Assert.Fail ("#1:" + len);
797                         } catch (NotSupportedException ex) {
798                                 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#2");
799                                 Assert.IsNull (ex.InnerException, "#3");
800                                 Assert.IsNotNull (ex.Message, "#4");
801                         }
802                 }
803
804                 [Test]
805                 public void Position ()
806                 {
807                         try {
808                                 long pos = out_stream.Position;
809                                 Assert.Fail ("#A1:" + pos);
810                         } catch (NotSupportedException ex) {
811                                 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#A2");
812                                 Assert.IsNull (ex.InnerException, "#A3");
813                                 Assert.IsNotNull (ex.Message, "#A4");
814                         }
815
816                         try {
817                                 out_stream.Position = 0;
818                                 Assert.Fail ("#B1");
819                         } catch (NotSupportedException ex) {
820                                 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#B2");
821                                 Assert.IsNull (ex.InnerException, "#B3");
822                                 Assert.IsNotNull (ex.Message, "#B4");
823                         }
824                 }
825
826                 [Test]
827                 public void Read ()
828                 {
829                         byte [] buffer = new byte [5];
830
831                         try {
832                                 out_stream.Read (buffer, 0, buffer.Length);
833                                 Assert.Fail ("#1");
834                         } catch (NotSupportedException ex) {
835                                 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#2");
836                                 Assert.IsNull (ex.InnerException, "#3");
837                                 Assert.IsNotNull (ex.Message, "#4");
838                         }
839                 }
840
841                 [Test]
842                 public void Seek ()
843                 {
844                         try {
845                                 out_stream.Seek (5, SeekOrigin.Begin);
846                                 Assert.Fail ("#1");
847                         } catch (NotSupportedException ex) {
848                                 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#2");
849                                 Assert.IsNull (ex.InnerException, "#3");
850                                 Assert.IsNotNull (ex.Message, "#4");
851                         }
852                 }
853
854                 [Test]
855                 public void SetLength ()
856                 {
857                         try {
858                                 out_stream.SetLength (5L);
859                                 Assert.Fail ("#1");
860                         } catch (NotSupportedException ex) {
861                                 Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#2");
862                                 Assert.IsNull (ex.InnerException, "#3");
863                                 Assert.IsNotNull (ex.Message, "#4");
864                         }
865                 }
866
867                 [Test]
868                 public void Write ()
869                 {
870                         byte [] buffer;
871
872                         buffer = Encoding.UTF8.GetBytes ("mono");
873                         out_stream.Write (buffer, 0, buffer.Length);
874                         buffer = Encoding.UTF8.GetBytes ("just rocks!!");
875                         out_stream.Write (buffer, 5, 6);
876                         out_stream.Write (buffer, 0, 4);
877                         Assert.IsFalse (worker.OutputProduced, "#1");
878                         response.Flush ();
879                         Assert.IsTrue (worker.OutputProduced, "#2");
880
881                         string output = Encoding.UTF8.GetString (worker.data);
882                         Assert.AreEqual ("e\r\nmonorocks!just\r\n", output);
883                 }
884
885                 [Test]
886                 public void Write_Buffer_Null ()
887                 {
888                         try {
889                                 out_stream.Write ((byte []) null, 0, 0);
890                                 Assert.Fail ("#1");
891                         } catch (ArgumentNullException ex) {
892                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
893                                 Assert.IsNull (ex.InnerException, "#3");
894                                 Assert.IsNotNull (ex.Message, "#4");
895                                 Assert.AreEqual ("buffer", ex.ParamName, "#5");
896                         }
897                 }
898
899                 [Test]
900                 public void Write_Count_Negative ()
901                 {
902                         byte [] buffer = new byte [] { 0x0a, 0x1f, 0x2d };
903
904                         // offset < 0
905                         try {
906                                 out_stream.Write (buffer, 1, -1);
907                                 Assert.Fail ("#1");
908                         } catch (ArgumentOutOfRangeException ex) {
909                                 Assert.AreEqual (typeof (ArgumentOutOfRangeException), ex.GetType (), "#2");
910                                 Assert.IsNull (ex.InnerException, "#3");
911                                 Assert.IsNotNull (ex.Message, "#4");
912                                 Assert.AreEqual ("count", ex.ParamName, "#5");
913                         }
914                 }
915
916                 [Test]
917                 public void Write_Count_Overflow ()
918                 {
919                         byte [] buffer;
920
921                         buffer = Encoding.UTF8.GetBytes ("Mono");
922                         out_stream.Write (buffer, 0, buffer.Length + 5);
923                         buffer = Encoding.UTF8.GetBytes ("Just Rocks!!");
924                         out_stream.Write (buffer, 5, buffer.Length - 2);
925                         response.Flush ();
926
927                         string output = Encoding.UTF8.GetString (worker.data);
928                         Assert.AreEqual ("b\r\nMonoRocks!!\r\n", output);
929                 }
930
931                 [Test]
932                 public void Write_Offset_Negative ()
933                 {
934                         byte [] buffer = new byte [] { 0x0a, 0x1f, 0x2d };
935
936                         // offset < 0
937                         try {
938                                 out_stream.Write (buffer, -1, 0);
939                                 Assert.Fail ("#1");
940                         } catch (ArgumentOutOfRangeException ex) {
941                                 Assert.AreEqual (typeof (ArgumentOutOfRangeException), ex.GetType (), "#2");
942                                 Assert.IsNull (ex.InnerException, "#3");
943                                 Assert.IsNotNull (ex.Message, "#4");
944                                 Assert.AreEqual ("offset", ex.ParamName, "#5");
945                         }
946                 }
947
948                 [Test]
949                 public void Write_Offset_Overflow ()
950                 {
951                         byte [] buffer = new byte [] { 0x0a, 0x1f, 0x2d };
952
953                         // offset == buffer length
954                         try {
955                                 out_stream.Write (buffer, buffer.Length, 0);
956                                 Assert.Fail ("#A1");
957                         } catch (ArgumentOutOfRangeException ex) {
958                                 Assert.AreEqual (typeof (ArgumentOutOfRangeException), ex.GetType (), "#A2");
959                                 Assert.IsNull (ex.InnerException, "#A3");
960                                 Assert.IsNotNull (ex.Message, "#A4");
961                                 Assert.AreEqual ("offset", ex.ParamName, "#A5");
962                         }
963
964                         // offset > buffer length
965                         try {
966                                 out_stream.Write (buffer, buffer.Length + 1, 0);
967                                 Assert.Fail ("#B1");
968                         } catch (ArgumentOutOfRangeException ex) {
969                                 Assert.AreEqual (typeof (ArgumentOutOfRangeException), ex.GetType (), "#B2");
970                                 Assert.IsNull (ex.InnerException, "#B3");
971                                 Assert.IsNotNull (ex.Message, "#B4");
972                                 Assert.AreEqual ("offset", ex.ParamName, "#B5");
973                         }
974
975                         response.Flush ();
976                         Assert.AreEqual (0, worker.data_len);
977                 }
978
979                 [Test]
980                 public void Write_Stream_Closed ()
981                 {
982                         byte [] buffer = Encoding.UTF8.GetBytes ("mono");
983                         out_stream.Close ();
984                         out_stream.Write (buffer, 0, buffer.Length);
985                         response.Flush ();
986
987                         string output = Encoding.UTF8.GetString (worker.data);
988                         Assert.AreEqual ("4\r\nmono\r\n", output);
989                 }
990
991                 HttpContext Cook (int re, out FakeHttpWorkerRequest2 f)
992                 {
993                         f = new FakeHttpWorkerRequest2 (re);
994                         return new HttpContext (f);
995                 }
996         }
997 }