diff --git a/src/Nancy.Tests/Unit/ViewEngines/SuperSimpleViewEngineTests.cs b/src/Nancy.Tests/Unit/ViewEngines/SuperSimpleViewEngineTests.cs index 5b7abdcf57..9000bbf9f5 100644 --- a/src/Nancy.Tests/Unit/ViewEngines/SuperSimpleViewEngineTests.cs +++ b/src/Nancy.Tests/Unit/ViewEngines/SuperSimpleViewEngineTests.cs @@ -1,36 +1,14 @@ namespace Nancy.Tests.Unit.ViewEngines { + using System.Collections.Generic; using System.Dynamic; using System.Linq; using Nancy.ViewEngines; using Xunit; - using System.Collections.Generic; - public class SuperSimpleViewEngineTests { - public class FakeModel - { - public FakeModel(string name, List users) - { - this.Name = name; - this.Users = users; - } - - public List Users { get; private set; } - - public string Name { get; private set; } - - public bool HasUsers - { - get - { - return this.Users.Any(); - } - } - } - - private SuperSimpleViewEngine viewEngine; + private readonly SuperSimpleViewEngine viewEngine; public SuperSimpleViewEngineTests() { @@ -38,291 +16,401 @@ public SuperSimpleViewEngineTests() } [Fact] - public void Replaces_valid_property_when_followed_by_closing_tag() + public void Should_not_throw_exception_when_model_it_null() { - var input = @"Hello there @Model.Name"; + // Given + const string input = @"Hello"; + dynamic model = null; + + // When + var exception = + Record.Exception(() => this.viewEngine.Render(input, model)); + + // Then + exception.ShouldBeNull(); + } + + [Fact] + public void Should_replaces_valid_property_when_followed_by_closing_tag() + { + // Given + const string input = @"Hello there @Model.Name"; dynamic model = new ExpandoObject(); model.Name = "Bob"; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"Hello there Bob", output); } [Fact] - public void Replaces_multiple_properties_with_the_same_name() + public void Should_replace_multiple_properties_with_the_same_name() { - var input = @"Hello there @Model.Name, nice to see you @Model.Name"; + // Given + const string input = @"Hello there @Model.Name, nice to see you @Model.Name"; dynamic model = new ExpandoObject(); model.Name = "Bob"; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"Hello there Bob, nice to see you Bob", output); } [Fact] - public void Replaces_invalid_properties_with_error_string() + public void Should_replace_invalid_properties_with_error_string() { - var input = @"Hello there @Model.Wrong"; + // Given + const string input = @"Hello there @Model.Wrong"; dynamic model = new ExpandoObject(); model.Name = "Bob"; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"Hello there [ERR!]", output); } [Fact] - public void Does_not_replace_properties_if_case_is_incorrect() + public void Should_not_replace_properties_if_case_is_incorrect() { - var input = @"Hello there @Model.name"; + // Given + const string input = @"Hello there @Model.name"; dynamic model = new ExpandoObject(); model.Name = "Bob"; + // When var output = viewEngine.Render(input, model); Assert.Equal(@"Hello there [ERR!]", output); } [Fact] - public void Replaces_multiple_properties_from_dictionary() + public void Should_replace_multiple_properties_from_dictionary() { - var input = @"Hello there @Model.Name - welcome to @Model.SiteName"; + // Given + const string input = @"Hello there @Model.Name - welcome to @Model.SiteName"; dynamic model = new ExpandoObject(); model.Name = "Bob"; model.SiteName = "Cool Site!"; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"Hello there Bob - welcome to Cool Site!", output); } [Fact] - public void Creates_multiple_entries_for_each_statements() + public void Should_create_multiple_entries_for_each_statements() { - var input = @""; + // Given + const string input = @""; dynamic model = new ExpandoObject(); model.Users = new List() { "Bob", "Jim", "Bill" }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
  • Bob
  • Jim
  • Bill
", output); } [Fact] - public void Can_use_multiple_current_statements_inside_each() + public void Should_use_multiple_current_statements_inside_each() { - var input = @"
    @Each.Users
  • @Current
  • @EndEach
"; + // Given + const string input = @"
    @Each.Users
  • @Current
  • @EndEach
"; dynamic model = new ExpandoObject(); model.Users = new List() { "Bob", "Jim", "Bill" }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
  • Bob
  • Jim
  • Bill
", output); } [Fact] - public void Trying_to_use_non_enumerable_in_each_shows_error() + public void Should_try_to_use_non_enumerable_in_each_shows_error() { - var input = @"
    @Each.Users
  • @Current
  • @EndEach
"; + // Given + const string input = @"
    @Each.Users
  • @Current
  • @EndEach
"; dynamic model = new ExpandoObject(); model.Users = new object(); + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
    [ERR!]
", output); } [Fact] - public void Can_combine_single_substitutions_and_each_substitutions() + public void Should_combine_single_substitutions_and_each_substitutions() { - var input = @"
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
"; + // Given + const string input = @"
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
"; dynamic model = new ExpandoObject(); model.Name = "Nancy"; model.Users = new List() { "Bob", "Jim", "Bill" }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
  • Hello Bob, Nancy says hello!
  • Hello Jim, Nancy says hello!
  • Hello Bill, Nancy says hello!
", output); } [Fact] - public void Model_statement_can_be_followed_by_a_newline() + public void Should_allow_model_statement_to_be_followed_by_a_newline() { - var input = "Hello there @Model.Name\n"; + // Given + const string input = "Hello there @Model.Name\n"; dynamic model = new ExpandoObject(); model.Name = "Bob"; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal("Hello there Bob\n", output); } [Fact] - public void Each_statements_should_work_over_multiple_lines() + public void Should_allow_each_statements_to_work_over_multiple_lines() { - var input = "\n\t\n\t\n\t\n\t\t
    @Each.Users\n\t\t\t
  • @Current
  • @EndEach\n\t\t
\n\t\n"; + // Given + const string input = "\n\t\n\t\n\t\n\t\t
    @Each.Users\n\t\t\t
  • @Current
  • @EndEach\n\t\t
\n\t\n"; dynamic model = new ExpandoObject(); model.Users = new List() { "Bob", "Jim", "Bill" }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal("\n\t\n\t\n\t\n\t\t
    \n\t\t\t
  • Bob
  • \n\t\t\t
  • Jim
  • \n\t\t\t
  • Bill
  • \n\t\t
\n\t\n", output); } [Fact] public void Single_substitutions_work_with_standard_anonymous_type_objects() { - var input = @"Hello there @Model.Name - welcome to @Model.SiteName"; + // Given + const string input = @"Hello there @Model.Name - welcome to @Model.SiteName"; var model = new { Name = "Bob", SiteName = "Cool Site!" }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"Hello there Bob - welcome to Cool Site!", output); } [Fact] - public void Each_substitutions_work_with_standard_anonymous_type_objects() + public void Should_allow_each_substitutions_to_work_with_standard_anonymous_type_objects() { - var input = @"
    @Each.Users
  • @Current
  • @EndEach
"; + // Given + const string input = @"
    @Each.Users
  • @Current
  • @EndEach
"; var model = new { Users = new List() { "Bob", "Jim", "Bill" } }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
  • Bob
  • Jim
  • Bill
", output); } [Fact] - public void Substitutions_work_with_standard_objects() + public void Should_allow_substitutions_to_work_with_standard_objects() { - var input = @"
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
"; + // Given + const string input = @"
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
"; var model = new FakeModel("Nancy", new List() { "Bob", "Jim", "Bill" }); + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
  • Hello Bob, Nancy says hello!
  • Hello Jim, Nancy says hello!
  • Hello Bill, Nancy says hello!
", output); } [Fact] - public void If_statement_with_true_returned_renders_block() + public void Should_render_block_when_if_statement_returns_true() { - var input = @"@If.HasUsers
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
@EndIf"; + // Given + const string input = @"@If.HasUsers
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
@EndIf"; var model = new FakeModel("Nancy", new List() { "Bob", "Jim", "Bill" }); + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
  • Hello Bob, Nancy says hello!
  • Hello Jim, Nancy says hello!
  • Hello Bill, Nancy says hello!
", output); } [Fact] - public void If_statement_with_false_returned_does_not_render_block() + public void Should_not_render_block_when_if_statement_returns_false() { - var input = @"@If.HasUsers
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
@EndIf"; + // Given + const string input = @"@If.HasUsers
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
@EndIf"; var model = new FakeModel("Nancy", new List()); + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"", output); } [Fact] - public void IfNot_statement_with_true_returned_does_not_renders_block() + public void Should_not_render_block_when_ifnot_statements_returns_true() { - var input = @"@IfNot.HasUsers

No users found!

@EndIf
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
"; + // Given + const string input = @"@IfNot.HasUsers

No users found!

@EndIf
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
"; var model = new FakeModel("Nancy", new List() { "Bob", "Jim", "Bill" }); + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
  • Hello Bob, Nancy says hello!
  • Hello Jim, Nancy says hello!
  • Hello Bill, Nancy says hello!
", output); } [Fact] - public void IfNot_statement_with_false_returned_renders_block() + public void Should_render_block_when_ifnot_statement_returns_false() { - var input = @"@IfNot.HasUsers

No users found!

@EndIf
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
"; + // Given + const string input = @"@IfNot.HasUsers

No users found!

@EndIf
    @Each.Users
  • Hello @Current, @Model.Name says hello!
  • @EndEach
"; var model = new FakeModel("Nancy", new List()); + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"

No users found!

    ", output); } [Fact] - public void If_and_IfNot_statements_combined_but_not_nested_do_not_conflict() + public void Should_not_conflict_when_if_and_ifNot_statements_combined_but_not_nested() { - var input = @"@IfNot.HasUsers

    No users found!

    @EndIf@If.HasUsers
      @Each.Users
    • Hello @Current, @Model.Name says hello!
    • @EndEach
    @EndIf"; + // Given + const string input = @"@IfNot.HasUsers

    No users found!

    @EndIf@If.HasUsers
      @Each.Users
    • Hello @Current, @Model.Name says hello!
    • @EndEach
    @EndIf"; var model = new FakeModel("Nancy", new List()); + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"

    No users found!

    ", output); } [Fact] - public void Multiple_if_statements_match_correctly() + public void Should_match_multiple_if_statements_correctly() { - var input = "@If.One

    One

    @EndIf @If.Two

    Two

    @EndIf"; + // Given + const string input = "@If.One

    One

    @EndIf @If.Two

    Two

    @EndIf"; var model = new { One = true, Two = true }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"

    One

    Two

    ", output); } [Fact] - public void Multiple_each_statements_match_correctly() + public void Should_match_correctly_when_multiple_each_statements() { - var input = "@Each.Users
  • @Current
  • @EndEach @Each.Admins
  • @Current
  • @EndEach"; + // Given + const string input = "@Each.Users
  • @Current
  • @EndEach @Each.Admins
  • @Current
  • @EndEach"; var model = new { Users = new List { "1", "2" }, Admins = new List { "3", "4" } }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
  • 1
  • 2
  • 3
  • 4
  • ", output); } [Fact] - public void If_model_has_a_collection_with_items_but_no_bool_then_If_HasCollection_returns_true() + public void Should_return_true_for_ifhascollection_when_if_model_has_a_collection_with_items_but_no_bool() { - var input = @"@If.HasUsers
      @Each.Users
    • Hello @Current, @Model.Name says hello!
    • @EndEach
    @EndIf"; + // Given + const string input = @"@If.HasUsers
      @Each.Users
    • Hello @Current, @Model.Name says hello!
    • @EndEach
    @EndIf"; var model = new { Users = new List() { "Bob", "Jim", "Bill" }, Name = "Nancy" }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"
    • Hello Bob, Nancy says hello!
    • Hello Jim, Nancy says hello!
    • Hello Bill, Nancy says hello!
    ", output); } [Fact] - public void If_model_has_a_collection_with_items_but_no_bool_then_IfNot_HasCollection_returns_false() + public void Should_return_false_for_ifnot_hascollection_when_model_has_a_collection_with_items_but_no_bool() { - var input = @"@IfNot.HasUsers

    No Users!

    @EndIf"; + // Given + const string input = @"@IfNot.HasUsers

    No Users!

    @EndIf"; var model = new { Users = new List() { "Bob", "Jim", "Bill" } }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"", output); } [Fact] - public void Implicit_has_support_ignores_item_if_item_isnt_a_collection() + public void Should_ignore_item_for_implicit_has_support_when_item_isnt_a_collection() { - var input = @"@If.HasUsers

    Users!

    @EndIf"; + // Given + const string input = @"@If.HasUsers

    Users!

    @EndIf"; var model = new { Users = new object() }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"", output); } [Fact] - public void If_model_has_HasItem_bool_then_it_takes_precedence_over_implcit_has_support() + public void Should_give_precedence_to_hasitem_bool_when_model_has_bool_and_collection() { - var input = @"@If.HasUsers
      @Each.Users
    • Hello @Current, @Model.Name says hello!
    • @EndEach
    @EndIf"; + // Given + const string input = @"@If.HasUsers
      @Each.Users
    • Hello @Current, @Model.Name says hello!
    • @EndEach
    @EndIf"; var model = new { HasUsers = false, Users = new List() { "Bob", "Jim", "Bill" }, Name = "Nancy" }; + // When var output = viewEngine.Render(input, model); + // Then Assert.Equal(@"", output); } } -} + + public class FakeModel + { + public FakeModel(string name, List users) + { + this.Name = name; + this.Users = users; + } + + public List Users { get; private set; } + + public string Name { get; private set; } + + public bool HasUsers + { + get + { + return this.Users.Any(); + } + } + } +} \ No newline at end of file diff --git a/src/Nancy/ViewEngines/SuperSimpleViewEngine.cs b/src/Nancy/ViewEngines/SuperSimpleViewEngine.cs index 7c933ba120..dcaa96e587 100644 --- a/src/Nancy/ViewEngines/SuperSimpleViewEngine.cs +++ b/src/Nancy/ViewEngines/SuperSimpleViewEngine.cs @@ -58,6 +58,11 @@ public SuperSimpleViewEngine() /// A string containing the expanded template. public string Render(string template, dynamic model) { + if (model == null) + { + model = new object(); + } + var propertyExtractor = this.GetPropertyExtractor(model); return this.processors.Aggregate(template, (current, processor) => processor(current, model, propertyExtractor));