1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2 
3 using System.Collections.Generic;
4 using System.Globalization;
5 using System.IO;
6 using System.Web.WebPages.Resources;
7 using Moq;
8 using Xunit;
9 using Assert = Microsoft.TestCommon.AssertEx;
10 
11 namespace System.Web.WebPages.Test
12 {
13     public class RenderPageTest
14     {
15         [Fact]
RenderBasicTest()16         public void RenderBasicTest()
17         {
18             // A simple page that does the following:
19             // @{ PageData["Title"] = "MyPage"; }
20             // @PageData["Title"]
21             // hello world
22             //
23             // Expected rendered result is "MyPagehello world"
24 
25             var content = "hello world";
26             var title = "MyPage";
27             var result = Utils.RenderWebPage(
28                 p =>
29                 {
30                     p.PageData["Title"] = title;
31                     p.Write(p.PageData["Title"]);
32                     p.Write(content);
33                 });
34 
35             Assert.Equal(title + content, result);
36         }
37 
38         [Fact]
RenderDynamicDictionaryBasicTest()39         public void RenderDynamicDictionaryBasicTest()
40         {
41             // A simple page that does the following:
42             // @{ Page.Title = "MyPage"; }
43             // @Page.Title
44             // hello world
45             //
46             // Expected rendered result is "MyPagehello world"
47 
48             var content = "hello world";
49             var title = "MyPage";
50             var result = Utils.RenderWebPage(
51                 p =>
52                 {
53                     p.Page.Title = title;
54                     p.Write(p.Page.Title);
55                     p.Write(content);
56                 });
57 
58             Assert.Equal(title + content, result);
59         }
60 
61         [Fact]
RenderPageBasicTest()62         public void RenderPageBasicTest()
63         {
64             // ~/index.cshtml does the following:
65             // hello
66             // @RenderPage("subpage.cshtml")
67             //
68             // ~/subpage.cshtml does the following:
69             // world
70             //
71             // Expected output is "helloworld"
72 
73             var result = Utils.RenderWebPageWithSubPage(
74                 p =>
75                 {
76                     p.Write("hello");
77                     p.Write(p.RenderPage("subpage.cshtml"));
78                 },
79                 p => { p.Write("world"); });
80             Assert.Equal("helloworld", result);
81         }
82 
83         [Fact]
RenderPageAnonymousTypeTest()84         public void RenderPageAnonymousTypeTest()
85         {
86             // Test for passing an anonymous type object as an argument to RenderPage
87             //
88             // ~/index.cshtml does the following:
89             // @RenderPage("subpage.cshtml", new { HelloKey = "hellovalue", MyKey = "myvalue" })
90             //
91             // ~/subpage.cshtml does the following:
92             // @PageData["HelloKey"] @PageData["MyKey"] @Model.HelloKey @Model.MyKey
93             //
94             // Expected result: hellovalue myvalue hellovalue myvalue
95             var result = Utils.RenderWebPageWithSubPage(
96                 p => { p.Write(p.RenderPage("subpage.cshtml", new { HelloKey = "hellovalue", MyKey = "myvalue" })); },
97                 p =>
98                 {
99                     p.Write(p.PageData["HelloKey"]);
100                     p.Write(" ");
101                     p.Write(p.PageData["MyKey"]);
102                     p.Write(" ");
103                     p.Write(p.Model.HelloKey);
104                     p.Write(" ");
105                     p.Write(p.Model.MyKey);
106                 });
107             Assert.Equal("hellovalue myvalue hellovalue myvalue", result);
108         }
109 
110         [Fact]
RenderPageDynamicDictionaryAnonymousTypeTest()111         public void RenderPageDynamicDictionaryAnonymousTypeTest()
112         {
113             // Test for passing an anonymous type object as an argument to RenderPage
114             //
115             // ~/index.cshtml does the following:
116             // @RenderPage("subpage.cshtml", new { HelloKey = "hellovalue", MyKey = "myvalue" })
117             //
118             // ~/subpage.cshtml does the following:
119             // @Page.HelloKey @Page.MyKey @Model.HelloKey @Model.MyKey
120             //
121             // Expected result: hellovalue myvalue hellovalue myvalue
122             var result = Utils.RenderWebPageWithSubPage(
123                 p => { p.Write(p.RenderPage("subpage.cshtml", new { HelloKey = "hellovalue", MyKey = "myvalue" })); },
124                 p =>
125                 {
126                     p.Write(p.Page.HelloKey);
127                     p.Write(" ");
128                     p.Write(p.Page.MyKey);
129                     p.Write(" ");
130                     p.Write(p.Model.HelloKey);
131                     p.Write(" ");
132                     p.Write(p.Model.MyKey);
133                 });
134             Assert.Equal("hellovalue myvalue hellovalue myvalue", result);
135         }
136 
137         [Fact]
RenderPageDictionaryTest()138         public void RenderPageDictionaryTest()
139         {
140             // Test for passing a dictionary instance as an argument to RenderPage
141             //
142             // ~/index.cshtml does the following:
143             // @RenderPage("subpage.cshtml", new Dictionary<string, object>(){ { "foo", 1 }, { "bar", "hello"} })
144             //
145             // ~/subpage.cshtml does the following:
146             // @PageData["foo"] @PageData["bar"] @PageData[0]
147             //
148             // Expected result: 1 hello System.Collections.Generic.Dictionary`2[System.String,System.Object]
149 
150             var result = Utils.RenderWebPageWithSubPage(
151                 p => { p.Write(p.RenderPage("subpage.cshtml", new Dictionary<string, object>() { { "foo", 1 }, { "bar", "hello" } })); },
152                 p =>
153                 {
154                     p.Write(p.PageData["foo"]);
155                     p.Write(" ");
156                     p.Write(p.PageData["bar"]);
157                     p.Write(" ");
158                     p.Write(p.PageData[0]);
159                 });
160             Assert.Equal("1 hello System.Collections.Generic.Dictionary`2[System.String,System.Object]", result);
161         }
162 
163         [Fact]
RenderPageDynamicDictionaryTest()164         public void RenderPageDynamicDictionaryTest()
165         {
166             // Test for passing a dictionary instance as an argument to RenderPage
167             //
168             // ~/index.cshtml does the following:
169             // @RenderPage("subpage.cshtml", new Dictionary<string, object>(){ { "foo", 1 }, { "bar", "hello"} })
170             //
171             // ~/subpage.cshtml does the following:
172             // @Page.foo @Page.bar @Page[0]
173             //
174             // Expected result: 1 hello System.Collections.Generic.Dictionary`2[System.String,System.Object]
175 
176             var result = Utils.RenderWebPageWithSubPage(
177                 p => { p.Write(p.RenderPage("subpage.cshtml", new Dictionary<string, object>() { { "foo", 1 }, { "bar", "hello" } })); },
178                 p =>
179                 {
180                     p.Write(p.Page.foo);
181                     p.Write(" ");
182                     p.Write(p.Page.bar);
183                     p.Write(" ");
184                     p.Write(p.Page[0]);
185                 });
186             Assert.Equal("1 hello System.Collections.Generic.Dictionary`2[System.String,System.Object]", result);
187         }
188 
189         [Fact]
RenderPageListTest()190         public void RenderPageListTest()
191         {
192             // Test for passing a list of arguments to RenderPage
193             //
194             // ~/index.cshtml does the following:
195             // @RenderPage("subpage.cshtml", "hello", "world", 1, 2, 3)
196             //
197             // ~/subpage.cshtml does the following:
198             // @PageData[0] @PageData[1] @PageData[2] @PageData[3] @PageData[4]
199             //
200             // Expected result: hello world 1 2 3
201 
202             var result = Utils.RenderWebPageWithSubPage(
203                 p => { p.Write(p.RenderPage("subpage.cshtml", "hello", "world", 1, 2, 3)); },
204                 p =>
205                 {
206                     p.Write(p.PageData[0]);
207                     p.Write(" ");
208                     p.Write(p.PageData[1]);
209                     p.Write(" ");
210                     p.Write(p.PageData[2]);
211                     p.Write(" ");
212                     p.Write(p.PageData[3]);
213                     p.Write(" ");
214                     p.Write(p.PageData[4]);
215                 });
216             Assert.Equal("hello world 1 2 3", result);
217         }
218 
219         [Fact]
RenderPageDynamicDictionaryListTest()220         public void RenderPageDynamicDictionaryListTest()
221         {
222             // Test for passing a list of arguments to RenderPage
223             //
224             // ~/index.cshtml does the following:
225             // @RenderPage("subpage.cshtml", "hello", "world", 1, 2, 3)
226             //
227             // ~/subpage.cshtml does the following:
228             // @Page[0] @Page[1] @Page[2] @Page[3] @Page[4]
229             //
230             // Expected result: hello world 1 2 3
231 
232             var result = Utils.RenderWebPageWithSubPage(
233                 p => { p.Write(p.RenderPage("subpage.cshtml", "hello", "world", 1, 2, 3)); },
234                 p =>
235                 {
236                     p.Write(p.Page[0]);
237                     p.Write(" ");
238                     p.Write(p.Page[1]);
239                     p.Write(" ");
240                     p.Write(p.Page[2]);
241                     p.Write(" ");
242                     p.Write(p.Page[3]);
243                     p.Write(" ");
244                     p.Write(p.Page[4]);
245                 });
246             Assert.Equal("hello world 1 2 3", result);
247         }
248 
249         private class Person
250         {
251             public string FirstName { get; set; }
252         }
253 
254         [Fact]
RenderPageDynamicValueTest()255         public void RenderPageDynamicValueTest()
256         {
257             // Test that PageData[key] returns a dynamic value.
258             // ~/index.cshtml does the following:
259             // @RenderPage("subpage.cshtml", new Person(){ FirstName="MyFirstName" })
260             //
261             // ~/subpage.cshtml does the following:
262             // @PageData[0].FirstName
263             //
264             // Expected result: MyFirstName
265             var result = Utils.RenderWebPageWithSubPage(
266                 p => { p.Write(p.RenderPage("subpage.cshtml", new Person() { FirstName = "MyFirstName" })); },
267                 p => { p.Write(p.PageData[0].FirstName); });
268             Assert.Equal("MyFirstName", result);
269         }
270 
271         [Fact]
RenderPageDynamicDictionaryDynamicValueTest()272         public void RenderPageDynamicDictionaryDynamicValueTest()
273         {
274             // Test that PageData[key] returns a dynamic value.
275             // ~/index.cshtml does the following:
276             // @RenderPage("subpage.cshtml", new Person(){ FirstName="MyFirstName" })
277             //
278             // ~/subpage.cshtml does the following:
279             // @Page[0].FirstName
280             //
281             // Expected result: MyFirstName
282             var result = Utils.RenderWebPageWithSubPage(
283                 p => { p.Write(p.RenderPage("subpage.cshtml", new Person() { FirstName = "MyFirstName" })); },
284                 p => { p.Write(p.Page[0].FirstName); });
285             Assert.Equal("MyFirstName", result);
286         }
287 
288         [Fact]
PageDataSetByParentTest()289         public void PageDataSetByParentTest()
290         {
291             // Items set in the PageData should be accessible by the subpage
292             var result = Utils.RenderWebPageWithSubPage(
293                 p =>
294                 {
295                     p.PageData["test"] = "hello";
296                     p.Write(p.RenderPage("subpage.cshtml"));
297                 },
298                 p => { p.Write(p.PageData["test"]); });
299             Assert.Equal("hello", result);
300         }
301 
302         [Fact]
DynamicDictionarySetByParentTest()303         public void DynamicDictionarySetByParentTest()
304         {
305             // Items set in the PageData should be accessible by the subpage
306             var result = Utils.RenderWebPageWithSubPage(
307                 p =>
308                 {
309                     p.Page.test = "hello";
310                     p.Write(p.RenderPage("subpage.cshtml"));
311                 },
312                 p => { p.Write(p.Page.test); });
313             Assert.Equal("hello", result);
314         }
315 
316         [Fact]
OverridePageDataSetByParentTest()317         public void OverridePageDataSetByParentTest()
318         {
319             // Items set in the PageData should be accessible by the subpage unless
320             // overriden by parameters passed into RenderPage, in which case the
321             // specified value should be used.
322             var result = Utils.RenderWebPageWithSubPage(
323                 p =>
324                 {
325                     p.PageData["test"] = "hello";
326                     p.Write(p.RenderPage("subpage.cshtml", new { Test = "world" }));
327                 },
328                 p =>
329                 {
330                     p.Write(p.PageData["test"]);
331                     p.Write(p.PageData[0].Test);
332                 });
333             Assert.Equal("worldworld", result);
334         }
335 
336         [Fact]
OverrideDynamicDictionarySetByParentTest()337         public void OverrideDynamicDictionarySetByParentTest()
338         {
339             // Items set in the PageData should be accessible by the subpage unless
340             // overriden by parameters passed into RenderPage, in which case the
341             // specified value should be used.
342             var result = Utils.RenderWebPageWithSubPage(
343                 p =>
344                 {
345                     p.PageData["test"] = "hello";
346                     p.Write(p.RenderPage("subpage.cshtml", new { Test = "world" }));
347                 },
348                 p =>
349                 {
350                     p.Write(p.Page.test);
351                     p.Write(p.Page[0].Test);
352                 });
353             Assert.Equal("worldworld", result);
354         }
355 
356         [Fact]
RenderPageMissingKeyTest()357         public void RenderPageMissingKeyTest()
358         {
359             // Test that using PageData with a missing key returns null
360             //
361             // ~/index.cshtml does the following:
362             // @RenderPage("subpage.cshtml", new Dictionary<string, object>(){ { "foo", 1 }, { "bar", "hello"} })
363             // @RenderPage("subpage.cshtml", "x", "y", "z")
364             //
365             // ~/subpage.cshtml does the following:
366             // @(PageData[1] ?? "null")
367             // @(PageData["bar"] ?? "null")
368             //
369             // Expected result: null hello y null
370 
371             var result = Utils.RenderWebPageWithSubPage(
372                 p =>
373                 {
374                     p.Write(p.RenderPage("subpage.cshtml", new Dictionary<string, object>() { { "foo", 1 }, { "bar", "hello" } }));
375                     p.Write(p.RenderPage("subpage.cshtml", "x", "y", "z"));
376                 },
377                 p =>
378                 {
379                     p.Write(p.PageData[1] ?? "null1");
380                     p.Write(" ");
381                     p.Write(p.PageData["bar"] ?? "null2");
382                     p.Write(" ");
383                 });
384             Assert.Equal("null1 hello y null2 ", result);
385         }
386 
387         [Fact]
RenderPageDynamicDictionaryMissingKeyTest()388         public void RenderPageDynamicDictionaryMissingKeyTest()
389         {
390             // Test that using PageData with a missing key returns null
391             //
392             // ~/index.cshtml does the following:
393             // @RenderPage("subpage.cshtml", new Dictionary<string, object>(){ { "foo", 1 }, { "bar", "hello"} })
394             // @RenderPage("subpage.cshtml", "x", "y", "z")
395             //
396             // ~/subpage.cshtml does the following:
397             // @(Page[1] ?? "null")
398             // @(Page.bar ?? "null")
399             //
400             // Expected result: null hello y null
401 
402             Action<WebPage> subPage = p =>
403             {
404                 p.Write(p.Page[1] ?? "null1");
405                 p.Write(" ");
406                 p.Write(p.Page.bar ?? "null2");
407                 p.Write(" ");
408             };
409             var result = Utils.RenderWebPageWithSubPage(
410                 p => { p.Write(p.RenderPage("subpage.cshtml", new Dictionary<string, object>() { { "foo", 1 }, { "bar", "hello" } })); }, subPage);
411             Assert.Equal("null1 hello ", result);
412             result = Utils.RenderWebPageWithSubPage(
413                 p => { p.Write(p.RenderPage("subpage.cshtml", "x", "y", "z")); }, subPage);
414             Assert.Equal("y null2 ", result);
415         }
416 
417         [Fact]
RenderPageNoArgumentsTest()418         public void RenderPageNoArgumentsTest()
419         {
420             // Test that using PageData within the calling page, and also
421             // within the subppage when the calling page doesn't provide any arguments
422             //
423             // ~/index.cshtml does the following:
424             // @(PageData["foo"] ?? "null1")
425             // @RenderPage("subpage.cshtml")
426             //
427             // ~/subpage.cshtml does the following:
428             // @(PageData[1] ?? "null2")
429             // @(PageData["bar"] ?? "null3")
430             //
431             // Expected result: null1 null2 null3
432 
433             var result = Utils.RenderWebPageWithSubPage(
434                 p =>
435                 {
436                     p.Write(p.PageData["foo"] ?? "null1 ");
437                     p.Write(p.RenderPage("subpage.cshtml"));
438                 },
439                 p =>
440                 {
441                     p.Write(p.PageData[1] ?? "null2");
442                     p.Write(" ");
443                     p.Write(p.PageData["bar"] ?? "null3");
444                 });
445             Assert.Equal("null1 null2 null3", result);
446         }
447 
448         [Fact]
RenderPageDynamicDictionaryNoArgumentsTest()449         public void RenderPageDynamicDictionaryNoArgumentsTest()
450         {
451             // Test that using PageData within the calling page, and also
452             // within the subppage when the calling page doesn't provide any arguments
453             //
454             // ~/index.cshtml does the following:
455             // @(Page.foo ?? "null1")
456             // @RenderPage("subpage.cshtml")
457             //
458             // ~/subpage.cshtml does the following:
459             // @(Page[1] ?? "null2")
460             // @(Page.bar ?? "null3")
461             //
462             // Expected result: null1 null2 null3
463 
464             var result = Utils.RenderWebPageWithSubPage(
465                 p =>
466                 {
467                     p.Write(p.Page.foo ?? "null1 ");
468                     p.Write(p.RenderPage("subpage.cshtml"));
469                 },
470                 p =>
471                 {
472                     p.Write(p.Page[1] ?? "null2");
473                     p.Write(" ");
474                     p.Write(p.Page.bar ?? "null3");
475                 });
476             Assert.Equal("null1 null2 null3", result);
477         }
478 
479         [Fact]
RenderPageNestedSubPageListTest()480         public void RenderPageNestedSubPageListTest()
481         {
482             // Test that PageData for each level of nesting returns the values as specified in the
483             // previous calling page.
484             //
485             // ~/index.cshtml does the following:
486             // @(PageData["foo"] ?? "null")
487             // @RenderPage("subpage1.cshtml", "a", "b", "c")
488             //
489             // ~/subpage1.cshtml does the following:
490             // @(PageData[0] ?? "sub1null0")
491             // @(PageData[1] ?? "sub1null1")
492             // @(PageData[2] ?? "sub1null2")
493             // @(PageData[3] ?? "sub1null3")
494             // @RenderPage("subpage2.cshtml", "x", "y", "z")
495             //
496             // ~/subpage2.cshtml does the following:
497             // @(PageData[0] ?? "sub2null0")
498             // @(PageData[1] ?? "sub2null1")
499             // @(PageData[2] ?? "sub2null2")
500             // @(PageData[3] ?? "sub2null3")
501             //
502             // Expected result: null a b c sub1null3 x y z sub2null3
503             var page = Utils.CreatePage(
504                 p =>
505                 {
506                     p.Write(p.PageData["foo"] ?? "null ");
507                     p.Write(p.RenderPage("subpage1.cshtml", "a", "b", "c"));
508                 });
509             var subpage1Path = "~/subpage1.cshtml";
510             var subpage1 = Utils.CreatePage(
511                 p =>
512                 {
513                     p.Write(p.PageData[0] ?? "sub1null0");
514                     p.Write(" ");
515                     p.Write(p.PageData[1] ?? "sub1null1");
516                     p.Write(" ");
517                     p.Write(p.PageData[2] ?? "sub1null2");
518                     p.Write(" ");
519                     p.Write(p.PageData[3] ?? "sub1null3");
520                     p.Write(" ");
521                     p.Write(p.RenderPage("subpage2.cshtml", "x", "y", "z"));
522                 }, subpage1Path);
523             var subpage2Path = "~/subpage2.cshtml";
524             var subpage2 = Utils.CreatePage(
525                 p =>
526                 {
527                     p.Write(p.PageData[0] ?? "sub2null0");
528                     p.Write(" ");
529                     p.Write(p.PageData[1] ?? "sub2null1");
530                     p.Write(" ");
531                     p.Write(p.PageData[2] ?? "sub2null2");
532                     p.Write(" ");
533                     p.Write(p.PageData[3] ?? "sub2null3");
534                 }, subpage2Path);
535 
536             Utils.AssignObjectFactoriesAndDisplayModeProvider(page, subpage1, subpage2);
537 
538             var result = Utils.RenderWebPage(page);
539             Assert.Equal("null a b c sub1null3 x y z sub2null3", result);
540         }
541 
542         [Fact]
RenderPageNestedSubPageAnonymousTypeTest()543         public void RenderPageNestedSubPageAnonymousTypeTest()
544         {
545             // Test that PageData for each level of nesting returns the values as specified in the
546             // previous calling page.
547             //
548             // ~/index.cshtml does the following:
549             // @(PageData["foo"] ?? "null")
550             // @RenderPage("subpage.cshtml", new { foo = 1 , bar = "hello" })
551             //
552             // ~/subpage1.cshtml does the following:
553             // @(PageData["foo"] ?? "sub1nullfoo")
554             // @(PageData["bar"] ?? "sub1nullbar")
555             // @(PageData["x"] ?? "sub1nullx")
556             // @(PageData["y"] ?? "sub1nully")
557             // @RenderPage("subpage2.cshtml", new { bar = "world", x = "good", y = "bye"})
558             //
559             // ~/subpage2.cshtml does the following:
560             // @(PageData["foo"] ?? "sub2nullfoo")
561             // @(PageData["bar"] ?? "sub2nullbar")
562             // @(PageData["x"] ?? "sub2nullx")
563             // @(PageData["y"] ?? "sub2nully")
564             //
565             // Expected result: null 1 hello sub1nullx sub1nully sub2nullfoo world good bye
566             var page = Utils.CreatePage(
567                 p =>
568                 {
569                     p.Write(p.PageData["foo"] ?? "null ");
570                     p.Write(p.RenderPage("subpage1.cshtml", new { foo = 1, bar = "hello" }));
571                 });
572             var subpage1Path = "~/subpage1.cshtml";
573             var subpage1 = Utils.CreatePage(
574                 p =>
575                 {
576                     p.Write(p.PageData["foo"] ?? "sub1nullfoo");
577                     p.Write(" ");
578                     p.Write(p.PageData["bar"] ?? "sub1nullbar");
579                     p.Write(" ");
580                     p.Write(p.PageData["x"] ?? "sub1nullx");
581                     p.Write(" ");
582                     p.Write(p.PageData["y"] ?? "sub1nully");
583                     p.Write(" ");
584                     p.Write(p.RenderPage("subpage2.cshtml", new { bar = "world", x = "good", y = "bye" }));
585                 }, subpage1Path);
586             var subpage2Path = "~/subpage2.cshtml";
587             var subpage2 = Utils.CreatePage(
588                 p =>
589                 {
590                     p.Write(p.PageData["foo"] ?? "sub2nullfoo");
591                     p.Write(" ");
592                     p.Write(p.PageData["bar"] ?? "sub2nullbar");
593                     p.Write(" ");
594                     p.Write(p.PageData["x"] ?? "sub2nullx");
595                     p.Write(" ");
596                     p.Write(p.PageData["y"] ?? "sub2nully");
597                 }, subpage2Path);
598 
599             Utils.AssignObjectFactoriesAndDisplayModeProvider(subpage1, subpage2, page);
600 
601             var result = Utils.RenderWebPage(page);
602             Assert.Equal("null 1 hello sub1nullx sub1nully sub2nullfoo world good bye", result);
603         }
604 
605         [Fact]
RenderPageNestedSubPageDictionaryTest()606         public void RenderPageNestedSubPageDictionaryTest()
607         {
608             // Test that PageData for each level of nesting returns the values as specified in the
609             // previous calling page.
610             //
611             // ~/index.cshtml does the following:
612             // @(PageData["foo"] ?? "null")
613             // @RenderPage("subpage.cshtml", new Dictionary<string, object>(){ { "foo", 1 }, { "bar", "hello"} })
614             //
615             // ~/subpage1.cshtml does the following:
616             // @(PageData["foo"] ?? "sub1nullfoo")
617             // @(PageData["bar"] ?? "sub1nullbar")
618             // @(PageData["x"] ?? "sub1nullx")
619             // @(PageData["y"] ?? "sub1nully")
620             // @RenderPage("subpage2.cshtml", new Dictionary<string, object>(){ { { "bar", "world"}, {"x", "good"}, {"y", "bye"} })
621             //
622             // ~/subpage2.cshtml does the following:
623             // @(PageData["foo"] ?? "sub2nullfoo")
624             // @(PageData["bar"] ?? "sub2nullbar")
625             // @(PageData["x"] ?? "sub2nullx")
626             // @(PageData["y"] ?? "sub2nully")
627             //
628             // Expected result: null 1 hello sub1nullx sub1nully sub2nullfoo world good bye
629             var page = Utils.CreatePage(
630                 p =>
631                 {
632                     p.Write(p.PageData["foo"] ?? "null ");
633                     p.Write(p.RenderPage("subpage1.cshtml", new Dictionary<string, object>() { { "foo", 1 }, { "bar", "hello" } }));
634                 });
635             var subpage1Path = "~/subpage1.cshtml";
636             var subpage1 = Utils.CreatePage(
637                 p =>
638                 {
639                     p.Write(p.PageData["foo"] ?? "sub1nullfoo");
640                     p.Write(" ");
641                     p.Write(p.PageData["bar"] ?? "sub1nullbar");
642                     p.Write(" ");
643                     p.Write(p.PageData["x"] ?? "sub1nullx");
644                     p.Write(" ");
645                     p.Write(p.PageData["y"] ?? "sub1nully");
646                     p.Write(" ");
647                     p.Write(p.RenderPage("subpage2.cshtml", new Dictionary<string, object>() { { "bar", "world" }, { "x", "good" }, { "y", "bye" } }));
648                 }, subpage1Path);
649             var subpage2Path = "~/subpage2.cshtml";
650             var subpage2 = Utils.CreatePage(
651                 p =>
652                 {
653                     p.Write(p.PageData["foo"] ?? "sub2nullfoo");
654                     p.Write(" ");
655                     p.Write(p.PageData["bar"] ?? "sub2nullbar");
656                     p.Write(" ");
657                     p.Write(p.PageData["x"] ?? "sub2nullx");
658                     p.Write(" ");
659                     p.Write(p.PageData["y"] ?? "sub2nully");
660                 }, subpage2Path);
661 
662             Utils.AssignObjectFactoriesAndDisplayModeProvider(page, subpage1, subpage2);
663 
664             var result = Utils.RenderWebPage(page);
665             Assert.Equal("null 1 hello sub1nullx sub1nully sub2nullfoo world good bye", result);
666         }
667 
668         [Fact]
RenderPageNestedParentPageDataTest()669         public void RenderPageNestedParentPageDataTest()
670         {
671             // PageData should return values set by parent pages.
672             var page = Utils.CreatePage(
673                 p =>
674                 {
675                     p.PageData["key1"] = "value1";
676                     p.Write(p.RenderPage("subpage1.cshtml"));
677                 });
678             var subpage1Path = "~/subpage1.cshtml";
679             var subpage1 = Utils.CreatePage(
680                 p =>
681                 {
682                     p.WriteLiteral("<subpage1>");
683                     p.Write(p.PageData["key1"]);
684                     p.Write(p.RenderPage("subpage2.cshtml"));
685                     p.Write(p.PageData["key1"]);
686                     p.PageData["key1"] = "value2";
687                     p.Write(p.RenderPage("subpage2.cshtml"));
688                     p.WriteLiteral("</subpage1>");
689                 }, subpage1Path);
690             var subpage2Path = "~/subpage2.cshtml";
691             var subpage2 = Utils.CreatePage(
692                 p =>
693                 {
694                     p.WriteLiteral("<subpage2>");
695                     p.Write(p.PageData["key1"]);
696                     // Setting the value in the child page should
697                     // not affect the parent page
698                     p.PageData["key1"] = "value3";
699                     p.Write(p.RenderPage("subpage3.cshtml", new { Key1 = "value4" }));
700                     p.WriteLiteral("</subpage2>");
701                 }, subpage2Path);
702             var subpage3Path = "~/subpage3.cshtml";
703             var subpage3 = Utils.CreatePage(
704                 p =>
705                 {
706                     p.WriteLiteral("<subpage3>");
707                     p.Write(p.PageData["key1"]);
708                     p.WriteLiteral("</subpage3>");
709                 }, subpage3Path);
710 
711             Utils.AssignObjectFactoriesAndDisplayModeProvider(subpage1, subpage2, subpage3, page);
712 
713             var result = Utils.RenderWebPage(page);
714             Assert.Equal("<subpage1>value1<subpage2>value1<subpage3>value4</subpage3></subpage2>value1<subpage2>value2<subpage3>value4</subpage3></subpage2></subpage1>", result);
715         }
716 
717         [Fact]
WriteNullTest()718         public void WriteNullTest()
719         {
720             // Test for @null
721             var result = Utils.RenderWebPage(
722                 p =>
723                 {
724                     p.Write(null);
725                     p.Write((object)null);
726                     p.Write((HelperResult)null);
727                 });
728 
729             Assert.Equal("", result);
730         }
731 
732         [Fact]
WriteTest()733         public void WriteTest()
734         {
735             // Test for calling WebPage.Write on text and HtmlHelper
736             var text = "Hello";
737             var wrote = false;
738             Action<TextWriter> action = tw =>
739             {
740                 tw.Write(text);
741                 wrote = true;
742             };
743             var helper = new HelperResult(action);
744             var result = Utils.RenderWebPage(
745                 p => { p.Write(helper); });
746             Assert.Equal(text, result);
747             Assert.True(wrote);
748         }
749 
750         [Fact]
WriteLiteralTest()751         public void WriteLiteralTest()
752         {
753             // Test for calling WebPage.WriteLiteral on text and HtmlHelper
754             var text = "Hello";
755             var wrote = false;
756             Action<TextWriter> action = tw =>
757             {
758                 tw.Write(text);
759                 wrote = true;
760             };
761             var helper = new HelperResult(action);
762             var result = Utils.RenderWebPage(
763                 p => { p.WriteLiteral(helper); });
764             Assert.Equal(text, result);
765             Assert.True(wrote);
766         }
767 
768         [Fact]
ExtensionNotSupportedTest()769         public void ExtensionNotSupportedTest()
770         {
771             // Tests that calling RenderPage on an unsupported extension returns a new simpler error message
772             // instead of the full error about build providers in system.web.dll.
773             var vpath = "~/hello/world.txt";
774             var ext = ".txt";
775             var compilationUtilThrowingBuildManager = new CompilationUtil();
776             var otherExceptionBuildManager = new Mock<IVirtualPathFactory>();
777             var msg = "The file \"~/hello/world.txt\" could not be rendered, because it does not exist or is not a valid page.";
778             otherExceptionBuildManager.Setup(c => c.CreateInstance(It.IsAny<string>())).Throws(new HttpException(msg));
779 
780             Assert.Throws<HttpException>(() =>
781                                                   WebPage.CreateInstanceFromVirtualPath(vpath, new VirtualPathFactoryManager(compilationUtilThrowingBuildManager)),
782                                                   String.Format(CultureInfo.CurrentCulture, WebPageResources.WebPage_FileNotSupported, ext, vpath));
783 
784             // Test that other error messages are thrown unmodified.
785             Assert.Throws<HttpException>(() => WebPage.CreateInstanceFromVirtualPath(vpath, otherExceptionBuildManager.Object), msg);
786         }
787 
788         [Fact]
RenderBodyCalledInChildPageTest()789         public void RenderBodyCalledInChildPageTest()
790         {
791             // A Page that is called by RenderPage should not be able to call RenderBody().
792 
793             Assert.Throws<HttpException>(() =>
794                 Utils.RenderWebPageWithSubPage(
795                     p =>
796                     {
797                         p.Write("hello");
798                         p.Write(p.RenderPage("subpage.cshtml"));
799                     },
800                     p =>
801                     {
802                         p.Write("world");
803                         p.RenderBody();
804                     }),
805                 String.Format(CultureInfo.CurrentCulture, WebPageResources.WebPage_CannotRequestDirectly, "~/subpage.cshtml", "RenderBody"));
806         }
807 
808         [Fact]
RenderPageInvalidPageType()809         public void RenderPageInvalidPageType()
810         {
811             var pagePath = "~/foo.js";
812             var page = Utils.CreatePage(p => { p.Write(p.RenderPage(pagePath)); });
813 
814             var objectFactory = new Mock<IVirtualPathFactory>();
815             objectFactory.Setup(c => c.Exists(It.IsAny<string>())).Returns<string>(p => pagePath.Equals(p, StringComparison.OrdinalIgnoreCase));
816             objectFactory.Setup(c => c.CreateInstance(It.IsAny<string>())).Returns<string>(_ => null);
817             page.VirtualPathFactory = objectFactory.Object;
818 
819             Assert.Throws<HttpException>(() =>
820             {
821                 page.VirtualPathFactory = objectFactory.Object;
822                 page.DisplayModeProvider = new DisplayModeProvider();
823                 Utils.RenderWebPage(page);
824             },
825             String.Format(CultureInfo.CurrentCulture, WebPageResources.WebPage_InvalidPageType, pagePath));
826         }
827 
828         [Fact]
RenderPageValidPageType()829         public void RenderPageValidPageType()
830         {
831             var pagePath = "~/foo.js";
832             var page = Utils.CreatePage(p => { p.Write(p.RenderPage(pagePath)); });
833 
834             var contents = "hello world";
835             var subPage = Utils.CreatePage(p => p.Write(contents), pagePath);
836 
837             Utils.AssignObjectFactoriesAndDisplayModeProvider(page, subPage);
838 
839             Assert.Equal(contents, Utils.RenderWebPage(page));
840         }
841 
842         [Fact]
RenderPageNull()843         public void RenderPageNull()
844         {
845             Assert.ThrowsArgumentNullOrEmptyString(() => Utils.RenderWebPage(p => p.RenderPage(null)), "path");
846         }
847 
848         [Fact]
RenderPageEmptyString()849         public void RenderPageEmptyString()
850         {
851             Assert.ThrowsArgumentNullOrEmptyString(() => Utils.RenderWebPage(p => p.RenderPage("")), "path");
852         }
853 
854         [Fact]
SamePageCaseInsensitiveTest()855         public void SamePageCaseInsensitiveTest()
856         {
857             var result = Utils.RenderWebPage(
858                 p =>
859                 {
860                     p.PageData["xyz"] = "value";
861                     p.PageData["XYZ"] = "VALUE";
862                     p.Write(p.PageData["xYz"]);
863                 });
864 
865             Assert.Equal("VALUE", result);
866         }
867     }
868 }
869