예제 #1
0
 def test_reference_has_no_inferred_name(self) -> None:
     sub_recipe = SubRecipe(Ingredient(SVS("spam")), (SVS("spam"), ), False)
     assert compile(["spam\nspam\nspam"]) == [
         Recipe((
             sub_recipe,
             Reference(sub_recipe, 0),
             Reference(sub_recipe, 0),
         )),
     ]
예제 #2
0
    def test_name_validation(self) -> None:
        sr = SubRecipe(Ingredient(SVS("spam")), (SVS("foo"), SVS("bar")))

        # Should work
        Reference(sr)
        Reference(sr, 0)
        Reference(sr, 1)

        # Unknown name
        with pytest.raises(OutputIndexError):
            Reference(sr, 2)
예제 #3
0
    def test_scale(self) -> None:
        sr_2 = SubRecipe(Ingredient(SVS("spam"), Quantity(2)),
                         (SVS([2, " blocks of spam"]), ))
        sr_6 = SubRecipe(Ingredient(SVS("spam"), Quantity(6)),
                         (SVS([6, " blocks of spam"]), ))

        assert Reference(sr_2, 0).scale(3) == Reference(sr_6, 0)
        assert Reference(sr_2, 0, Quantity(100, "g")).scale(3) == Reference(
            sr_6,
            0,
            Quantity(300, "g"),
        )
예제 #4
0
    def test_scale(self) -> None:
        sr_2 = SubRecipe(Ingredient(SVS("spam"), Quantity(2)), (SVS("spam"), ))
        ref_sr_2 = Reference(sr_2)

        sr_6 = SubRecipe(Ingredient(SVS("spam"), Quantity(6)), (SVS("spam"), ))
        ref_sr_6 = Reference(sr_6)

        first_rec_2 = Recipe((sr_2, ))
        second_rec_2 = Recipe((ref_sr_2, ), follows=first_rec_2)

        first_rec_6 = Recipe((sr_6, ))
        second_rec_6 = Recipe((ref_sr_6, ), follows=first_rec_6)

        assert first_rec_2.scale(3) == first_rec_6
        assert second_rec_2.scale(3) == second_rec_6
예제 #5
0
    def test_separate_recipes(self) -> None:
        compiled = compile_markdown(
            dedent("""
                Fried egg:

                ```recipe
                1 egg
                ```

                ```recipe
                fry(egg)
                ```

                Boiled egg:

                ```new-recipe
                2 egg
                ```

                ```recipe
                boil(egg)
                ```
                """).strip())

        e1 = SubRecipe(
            Ingredient(SVS("egg"), Quantity(1)),
            (SVS("egg"), ),
            show_output_names=False,
        )
        r1 = Recipe((e1, ))
        r2 = Recipe((Step(SVS("fry"), (Reference(e1), )), ), follows=r1)

        e2 = SubRecipe(
            Ingredient(SVS("egg"), Quantity(2)),
            (SVS("egg"), ),
            show_output_names=False,
        )
        r3 = Recipe((e2, ))
        r4 = Recipe((Step(SVS("boil"), (Reference(e2), )), ), follows=r3)

        assert compiled.recipes == [[r1, r2], [r3, r4]]

        # Check anchor IDs are unique too
        html = compiled.render()
        assert 'id="recipe-egg"' in html
        assert 'href="#recipe-egg"' in html
        assert 'id="recipe2-egg"' in html
        assert 'href="#recipe2-egg"' in html
예제 #6
0
    def test_nested_reference_to_sub_recipe_not_in_recipe(self) -> None:
        external_sr = SubRecipe(Ingredient(SVS("eggs")), (SVS("foo"), ))
        ref = Reference(external_sr)
        step = Step(SVS("bar"), (ref, ))

        with pytest.raises(ReferenceToInvalidSubRecipeError):
            Recipe((step, ))
예제 #7
0
    def _compile_reference(
            self,
            ast_reference: ast.Reference) -> Union[Ingredient, Reference]:
        name = compile_string(ast_reference.name)
        normalised_name = normalise_output_name(name)

        if normalised_name in self._named_outputs:
            # Name refers to a SubRecipe output, this is a Reference
            output = self._named_outputs[normalised_name]
            reference = Reference(
                sub_recipe=output.sub_recipe,
                output_index=output.output_index,
                amount=self._compile_quantity_or_proportion(
                    ast_reference.quantity_or_proportion),
            )
            output.references.append((reference, self._current_recipe_index))
            return reference
        else:
            # This is an ingredient
            if isinstance(ast_reference.quantity_or_proportion,
                          ast.Proportion):
                raise ProportionGivenForIngredientError.from_ast_reference(
                    self._sources[self._current_recipe_index],
                    ast_reference,
                )
            return Ingredient(
                description=name,
                quantity=(self._compile_quantity(
                    ast_reference.quantity_or_proportion)
                          if ast_reference.quantity_or_proportion is not None
                          else None),
            )
예제 #8
0
    def test_recipes_split_across_blocks(self) -> None:
        compiled = compile_markdown(
            dedent("""
                A recipe in two parts. Part one:

                    sauce = boil down(tomatoes, water)

                Part two:

                    pour over(pasta, sauce)
                """).strip())

        sr = SubRecipe(
            Step(
                SVS("boil down"),
                (
                    Ingredient(SVS("tomatoes")),
                    Ingredient(SVS("water")),
                ),
            ),
            (SVS("sauce"), ),
        )
        r1 = Recipe((sr, ))
        r2 = Recipe(
            (Step(
                SVS("pour over"),
                (
                    Ingredient(SVS("pasta")),
                    Reference(sr),
                ),
            ), ),
            follows=r1,
        )

        assert compiled.recipes == [[r1, r2]]
예제 #9
0
    def test_reference_to_nested_sub_recipe(self) -> None:
        nested_sr = SubRecipe(Ingredient(SVS("eggs")), (SVS("foo"), ))
        step = Step(SVS("scramble"), (nested_sr, ))

        ref = Reference(nested_sr)

        with pytest.raises(ReferenceToInvalidSubRecipeError):
            Recipe((step, ref))
예제 #10
0
    def test_valid_references(self) -> None:
        sr = SubRecipe(Ingredient(SVS("eggs")), (SVS("foo"), ))
        ref1 = Reference(sr)

        # Shouldn't fail
        rec1 = Recipe((sr, ref1))

        # Also shouldn't fail (since marked as follows)
        ref2 = Reference(sr)
        rec2 = Recipe((ref2, ), follows=rec1)

        # Chained references
        ref3 = Reference(sr)
        Recipe((ref3, ), follows=rec2)

        # Should fail: not referenced
        ref4 = Reference(sr)
        with pytest.raises(ReferenceToInvalidSubRecipeError):
            Recipe((ref4, ))
예제 #11
0
 def test_reference_compilation(self) -> None:
     sub_recipe = SubRecipe(
         Step(SVS("open"), (Ingredient(SVS("spam")), )),
         (SVS("spam"), SVS("tin")),
         True,
     )
     assert compile([
         "spam, tin = open(spam)\nspam\n1/3*spam\n25% of the spam\nleft over spam\n2 'tin'\n50g spam"  # noqa: E501
     ]) == [
         Recipe((
             sub_recipe,
             # spam
             Reference(sub_recipe, 0, Proportion(1.0)),
             # 1/3*spam
             Reference(sub_recipe, 0,
                       Proportion(Fraction(1, 3), preposition="*")),
             # 25% of the spam
             Reference(
                 sub_recipe,
                 0,
                 Proportion(0.25, percentage=True, preposition="% of the"),
             ),
             # remaining
             Reference(sub_recipe, 0,
                       Proportion(None, remainder_wording="left over")),
             # 2 tin
             Reference(sub_recipe, 1, Quantity(2.0)),
             # 50g spam
             Reference(sub_recipe, 0, Quantity(50.0, "g")),
         )),
     ]
예제 #12
0
    def test_substitute(self) -> None:
        a = Ingredient(SVS("a"))
        b = SubRecipe(a, (SVS("b"), ))
        c = Ingredient(SVS("c"))
        d = SubRecipe(c, (SVS("d"), ))

        orig = Reference(b, 0)

        assert orig.substitute(a, c) == Reference(SubRecipe(c, (SVS("b"), )),
                                                  0)
        assert orig.substitute(b, d) == Reference(SubRecipe(c, (SVS("d"), )),
                                                  0)
        assert orig.substitute(orig, c) == c
예제 #13
0
 def test_dont_inline_partial_uses_of_a_subrecipe(self) -> None:
     sub_recipe = SubRecipe(
         Ingredient(SVS("spam"), Quantity(100, "g")),
         (SVS("spam"), ),
         False,
     )
     assert compile(["100g spam\nfry(50g spam, eggs)"]) == [
         Recipe((
             sub_recipe,
             Step(
                 SVS("fry"),
                 (
                     Reference(sub_recipe, 0, Quantity(50, "g")),
                     Ingredient(SVS("eggs")),
                 ),
             ),
         ))
     ]
예제 #14
0
 def test_dont_inline_multi_output_subrecipes(self) -> None:
     sub_recipe = SubRecipe(
         Ingredient(SVS("spam")),
         (SVS("meat"), SVS("tin")),
         True,
     )
     assert compile(["meat, tin = spam\nfry(meat, eggs)"]) == [
         Recipe((
             sub_recipe,
             Step(
                 SVS("fry"),
                 (
                     Reference(sub_recipe, 0),
                     Ingredient(SVS("eggs")),
                 ),
             ),
         ))
     ]
예제 #15
0
 def test_dont_inline_definitions_from_earlier_blocks(self) -> None:
     sub_recipe = SubRecipe(
         Ingredient(SVS("spam"), Quantity(100, "g")),
         (SVS("spam"), ),
         False,
     )
     recipe0 = Recipe((sub_recipe, ))
     recipe1 = Recipe(
         (Step(
             SVS("fry"),
             (
                 Reference(sub_recipe, 0, Quantity(50, "g")),
                 Ingredient(SVS("eggs")),
             ),
         ), ),
         follows=recipe0,
     )
     assert compile(["100g spam",
                     "fry(50g spam, eggs)"]) == [recipe0, recipe1]
예제 #16
0
        SVS("fOo"))
    assert normalise_output_name(SVS(" Foo ")) != normalise_output_name(
        SVS("bAr"))


@pytest.mark.parametrize(
    "recipe_tree, exp",
    [
        # Workable cases
        (Ingredient(SVS("spam")), SVS("spam")),
        (Step(SVS("fry"), (Ingredient(SVS("spam")), )), SVS("spam")),
        # Can't name step with several inputs
        (Step(SVS("fry"),
              (Ingredient(SVS("spam")), Ingredient(SVS("eggs")))), None),
        # Can't name references
        (Reference(SubRecipe(Ingredient(SVS("spam")),
                             (SVS("spam"), )), 0), None),
        # Can't name sub recipes (they're already named!)
        (SubRecipe(Ingredient(SVS("spam")), (SVS("spam"), )), None),
    ],
)
def test_infer_output_name(recipe_tree: RecipeTreeNode,
                           exp: Optional[SVS]) -> None:
    assert infer_output_name(recipe_tree) == exp


@pytest.mark.parametrize(
    "recipe_tree, exp",
    [
        # Workable cases
        (Ingredient(SVS("spam")), None),
        (Ingredient(SVS("spam"), Quantity(100)), Quantity(100)),
예제 #17
0
def test_generate_subrecipe_output_id() -> None:
    sub_recipe = SubRecipe(
        Ingredient(SVS("spam")),
        (SVS("foo"), SVS(["foo bar ", 123, " baz?"])),
    )
    assert generate_subrecipe_output_id(sub_recipe, 0, "qux-") == "qux-foo"
    assert generate_subrecipe_output_id(sub_recipe, 1,
                                        "qux-") == "qux-foo-bar-123-baz"


@pytest.mark.parametrize(
    "reference, exp",
    [
        # No amount (consumes whole thing)
        (
            Reference(SubRecipe(Ingredient(SVS("spam")),
                                (SVS("foo"), )), 0, Proportion(1)),
            '<a href="#sub-recipe-foo">foo</a>',
        ),
        # Non-whole proportion
        (
            Reference(SubRecipe(Ingredient(SVS("spam")),
                                (SVS("foo"), )), 0, Proportion(None)),
            ('<a href="#sub-recipe-foo">'
             '<span class="rg-proportion-remainder">remaining</span> foo'
             "</a>"),
        ),
        (
            Reference(
                SubRecipe(Ingredient(SVS("spam")), (SVS("foo"), )),
                0,
                Proportion(0.5, preposition=" *"),
예제 #18
0
def test_reference() -> None:
    sub_recipe = SubRecipe(Ingredient(SVS("spam")), (SVS("out"), ))
    reference = Reference(sub_recipe, 0)
    assert recipe_tree_to_table(reference) == set_border_around_table(
        Table.from_dict({(0, 0): Cell(reference)}), BorderType.sub_recipe)
예제 #19
0
 def test_reference(self) -> None:
     assert (render_cell(
         Cell(
             Reference(SubRecipe(Ingredient(SVS("spam")), (SVS("foo"), )),
                       0))
     ) == '<td class="rg-reference"><a href="#sub-recipe-foo">foo</a></td>')
예제 #20
0
    def test_reference_to_sub_recipe_later_in_recipe(self) -> None:
        later_sr = SubRecipe(Ingredient(SVS("eggs")), (SVS("foo"), ))
        ref = Reference(later_sr)

        with pytest.raises(ReferenceToInvalidSubRecipeError):
            Recipe((ref, later_sr))