📄 test/JsonLdRecipeParser.Tests/RecipeTests/FromShould.cs
using System;
using JsonLdRecipeParser.Json;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;

namespace JsonLdRecipeParser.Tests.RecipeTests;

[TestClass]
public class FromShould
{
    [TestMethod]
    public void MapNameAndDescription()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Chocolate Cake",
            Description = "A rich and moist cake.",
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Name.ShouldBe("Chocolate Cake");
        result.Description.ShouldBe("A rich and moist cake.");
    }

    [TestMethod]
    public void MapASingleAuthor()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            Author = new Authors
            {
                Value = new JsonLdRecipeParser.Json.Author { Value = new Person { Name = "Mary Stone" } },
            },
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Authors.Length.ShouldBe(1);
        result.Authors[0].Name.ShouldBe("Mary Stone");
    }

    [TestMethod]
    public void MapMultipleAuthors()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            Author = new Authors
            {
                Value = new JsonLdRecipeParser.Json.Author[]
                {
                    new() { Value = new Person { Name = "Mary Stone" } },
                    new() { Value = new Person { Name = "John Doe" } },
                },
            },
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Authors.Length.ShouldBe(2);
        result.Authors[0].Name.ShouldBe("Mary Stone");
        result.Authors[1].Name.ShouldBe("John Doe");
    }

    [TestMethod]
    public void MapNoAuthors()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe { Name = "Test Recipe" };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Authors.ShouldBeEmpty();
    }

    [TestMethod]
    public void MapTimes()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            PrepTime = TimeSpan.FromMinutes(10),
            CookTime = TimeSpan.FromMinutes(30),
            TotalTime = TimeSpan.FromMinutes(40),
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.PrepTime.ShouldBe(TimeSpan.FromMinutes(10));
        result.CookTime.ShouldBe(TimeSpan.FromMinutes(30));
        result.TotalTime.ShouldBe(TimeSpan.FromMinutes(40));
    }

    [TestMethod]
    public void MapCategoryFromString()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            RecipeCategory = new RecipeCategories { Value = "Dessert" },
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Category.ShouldBe(["Dessert"]);
    }

    [TestMethod]
    public void MapCategoryFromStringArray()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            RecipeCategory = new RecipeCategories { Value = new[] { "Dessert", "Cake" } },
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Category.ShouldBe(["Dessert", "Cake"]);
    }

    [TestMethod]
    public void MapNoCategory()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe { Name = "Test Recipe" };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Category.ShouldBeEmpty();
    }

    [TestMethod]
    public void MapCuisineFromString()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            RecipeCuisine = new RecipeCuisines { Value = "American" },
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Cuisine.ShouldBe(["American"]);
    }

    [TestMethod]
    public void MapCuisineFromStringArray()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            RecipeCuisine = new RecipeCuisines { Value = new[] { "American", "Southern" } },
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Cuisine.ShouldBe(["American", "Southern"]);
    }

    [TestMethod]
    public void MapNoCuisine()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe { Name = "Test Recipe" };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Cuisine.ShouldBeEmpty();
    }

    [TestMethod]
    public void MapNullNutrition()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe { Name = "Test Recipe" };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Nutrients.ShouldBeNull();
    }

    [TestMethod]
    public void MapNullYield()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe { Name = "Test Recipe" };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Yield.ShouldBeNull();
    }

    [TestMethod]
    public void MapNullIngredients()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe { Name = "Test Recipe" };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Ingredients.ShouldBeEmpty();
    }

    [TestMethod]
    public void MapNullInstructions()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe { Name = "Test Recipe" };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.InstructionSections.ShouldBeEmpty();
    }

    [TestMethod]
    public void PassThroughIngredients()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            RecipeIngredient = [new RecipeIngredient { Value = "sugar" }, new RecipeIngredient { Value = "flour" }],
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Ingredients.Length.ShouldBe(2);
        result.Ingredients[0].Name.ShouldBe("sugar");
        result.Ingredients[1].Name.ShouldBe("flour");
    }

    [TestMethod]
    public void PassThroughInstructions()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            RecipeInstructions =
            [
                new RecipeInstruction { Value = "Mix ingredients." },
                new RecipeInstruction { Value = "Bake for 30 minutes." },
            ],
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.InstructionSections.Length.ShouldBe(2);
        result.InstructionSections[0].Instructions[0].Text.ShouldBe("Mix ingredients.");
        result.InstructionSections[1].Instructions[0].Text.ShouldBe("Bake for 30 minutes.");
    }

    [TestMethod]
    public void PassThroughNutrition()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            Nutrition = new NutritionInformation { Calories = new Quantity { Value = "120 calories" } },
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Nutrients.ShouldNotBeNull();
        result.Nutrients!.Calories!.Value.ShouldBe(new ExactAmountValue(120.0d));
    }

    [TestMethod]
    public void PassThroughYield()
    {
        // Arrange
        var recipe = new JsonLdRecipeParser.Json.Recipe
        {
            Name = "Test Recipe",
            RecipeYield = new Quantity { Value = "4 servings" },
        };

        // Act
        var result = Recipe.From(recipe);

        // Assert
        result.Yield.ShouldNotBeNull();
        result.Yield!.Value.ShouldBe(new ExactAmountValue(4.0d));
        result.Yield.Unit.ShouldBe("servings");
    }
}