Пример #1
0
class TestNumbersInValues(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(FluentResource(dedent_ftl("""
            foo = Foo { $num }
            bar = { foo }
            baz =
                .attr = Baz Attribute { $num }
            qux = { "a" ->
               *[a]     Baz Variant A { $num }
             }
        """)))

    def test_can_be_used_in_the_message_value(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('foo').value, {'num': 3})
        self.assertEqual(val, 'Foo 3')
        self.assertEqual(len(errs), 0)

    def test_can_be_used_in_the_message_value_which_is_referenced(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('bar').value, {'num': 3})
        self.assertEqual(val, 'Foo 3')
        self.assertEqual(len(errs), 0)

    def test_can_be_used_in_an_attribute(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('baz').attributes['attr'], {'num': 3})
        self.assertEqual(val, 'Baz Attribute 3')
        self.assertEqual(len(errs), 0)

    def test_can_be_used_in_a_variant(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('qux').value, {'num': 3})
        self.assertEqual(val, 'Baz Variant A 3')
        self.assertEqual(len(errs), 0)
Пример #2
0
class TestResolving(unittest.TestCase):
    def setUp(self):
        self.args_passed = []

        def number_processor(number):
            self.args_passed.append(number)
            return number

        self.bundle = FluentBundle(
            ['en-US'],
            use_isolating=False,
            functions={'NUMBER_PROCESSOR': number_processor})

        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            pass-number = { NUMBER_PROCESSOR(1) }
            pass-arg = { NUMBER_PROCESSOR($arg) }
        """)))

    def test_args_passed_as_numbers(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-arg').value, {'arg': 1})
        self.assertEqual(val, "1")
        self.assertEqual(len(errs), 0)
        self.assertEqual(self.args_passed, [1])

    def test_literals_passed_as_numbers(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-number').value, {})
        self.assertEqual(val, "1")
        self.assertEqual(len(errs), 0)
        self.assertEqual(self.args_passed, [1])
Пример #3
0
class TestAttributesWithStringValues(unittest.TestCase):

    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(FluentResource(dedent_ftl("""
            foo = Foo
                .attr = Foo Attribute
            bar = { foo } Bar
                .attr = Bar Attribute
            ref-foo = { foo.attr }
            ref-bar = { bar.attr }
        """)))

    def test_can_be_referenced_for_entities_with_string_values(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('ref-foo').value, {})
        self.assertEqual(val, 'Foo Attribute')
        self.assertEqual(len(errs), 0)

    def test_can_be_referenced_for_entities_with_pattern_values(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('ref-bar').value, {})
        self.assertEqual(val, 'Bar Attribute')
        self.assertEqual(len(errs), 0)

    def test_can_be_formatted_directly_for_entities_with_string_values(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('foo').attributes['attr'], {})
        self.assertEqual(val, 'Foo Attribute')
        self.assertEqual(len(errs), 0)

    def test_can_be_formatted_directly_for_entities_with_pattern_values(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('bar').attributes['attr'], {})
        self.assertEqual(val, 'Bar Attribute')
        self.assertEqual(len(errs), 0)
Пример #4
0
class TestNumbers(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(FluentResource(dedent_ftl("""
            one           =  { 1 }
            one_point_two =  { 1.2 }
            select        =  { 1 ->
               *[0] Zero
                [1] One
             }
        """)))

    def test_int_number_used_in_placeable(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('one').value, {})
        self.assertEqual(val, '1')
        self.assertEqual(len(errs), 0)

    def test_float_number_used_in_placeable(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('one_point_two').value, {})
        self.assertEqual(val, '1.2')
        self.assertEqual(len(errs), 0)

    def test_can_be_used_as_a_selector(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('select').value, {})
        self.assertEqual(val, 'One')
        self.assertEqual(len(errs), 0)
Пример #5
0
class TestSelectExpressionWithStrings(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)

    def test_with_a_matching_selector(self):
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = { "a" ->
                [a] A
               *[b] B
             }
        """)))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {})
        self.assertEqual(val, "A")
        self.assertEqual(len(errs), 0)

    def test_with_a_non_matching_selector(self):
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = { "c" ->
                [a] A
               *[b] B
             }
        """)))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {})
        self.assertEqual(val, "B")
        self.assertEqual(len(errs), 0)

    def test_with_a_missing_selector(self):
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = { $none ->
                [a] A
               *[b] B
             }
        """)))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {})
        self.assertEqual(val, "B")
        self.assertEqual(errs,
                         [FluentReferenceError("Unknown external: none")])

    def test_with_argument_expression(self):
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = { $arg ->
                [a] A
               *[b] B
             }
        """)))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {'arg': 'a'})
        self.assertEqual(val, "A")
class TestComplexStringValue(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo               = Foo
            bar               = { foo }Bar

            placeable-message = { bar }Baz

            baz =
                .attr = { bar }BazAttribute

            -qux = Qux
                .attr = { bar }QuxAttribute

            placeable-attr = { baz.attr }

            selector-attr = { -qux.attr ->
                [FooBarQuxAttribute] FooBarQux
               *[other] Other
             }
        """)))

    def test_can_be_used_as_a_value(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('bar').value, {})
        self.assertEqual(val, 'FooBar')
        self.assertEqual(len(errs), 0)

    def test_can_be_value_of_a_message_referenced_in_a_placeable(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('placeable-message').value, {})
        self.assertEqual(val, 'FooBarBaz')
        self.assertEqual(len(errs), 0)

    def test_can_be_used_as_an_attribute_value(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('baz').attributes['attr'], {})
        self.assertEqual(val, 'FooBarBazAttribute')
        self.assertEqual(len(errs), 0)

    def test_can_be_a_value_of_an_attribute_used_in_a_placeable(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('placeable-attr').value, {})
        self.assertEqual(val, 'FooBarBazAttribute')
        self.assertEqual(len(errs), 0)

    def test_can_be_a_value_of_an_attribute_used_as_a_selector(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('selector-attr').value, {})
        self.assertEqual(val, 'FooBarQux')
        self.assertEqual(len(errs), 0)
class TestNestedParameterizedTerms(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            -thing = { $article ->
                *[definite] { $first-letter ->
                    *[lower] the thing
                     [upper] The thing
                 }
                 [indefinite] { $first-letter ->
                    *[lower] a thing
                     [upper] A thing
                 }
             }

            both-args = { -thing(first-letter: "upper", article: "indefinite") }.
            outer-arg = This is { -thing(article: "indefinite") }.
            inner-arg = { -thing(first-letter: "upper") }.
            neither-arg = { -thing() }.
        """)))

    def test_both_args(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('both-args').value, {})
        self.assertEqual(val, 'A thing.')
        self.assertEqual(errs, [])

    def test_outer_arg(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('outer-arg').value, {})
        self.assertEqual(val, 'This is a thing.')
        self.assertEqual(errs, [])

    def test_inner_arg(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('inner-arg').value, {})
        self.assertEqual(val, 'The thing.')
        self.assertEqual(errs, [])

    def test_inner_arg_with_external_args(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('inner-arg').value,
            {'article': 'indefinite'})
        self.assertEqual(val, 'The thing.')
        self.assertEqual(errs, [])

    def test_neither_arg(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('neither-arg').value, {})
        self.assertEqual(val, 'the thing.')
        self.assertEqual(errs, [])
Пример #8
0
class TestKeywordArgs(unittest.TestCase):
    def setUp(self):
        self.args_passed = []

        def my_function(arg, kwarg1=None, kwarg2="default"):
            self.args_passed.append((arg, kwarg1, kwarg2))
            return arg

        self.bundle = FluentBundle(['en-US'],
                                   use_isolating=False,
                                   functions={'MYFUNC': my_function})
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            pass-arg        = { MYFUNC("a") }
            pass-kwarg1     = { MYFUNC("a", kwarg1: 1) }
            pass-kwarg2     = { MYFUNC("a", kwarg2: "other") }
            pass-kwargs     = { MYFUNC("a", kwarg1: 1, kwarg2: "other") }
            pass-user-arg   = { MYFUNC($arg) }
        """)))

    def test_defaults(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-arg').value, {})
        self.assertEqual(self.args_passed, [("a", None, "default")])
        self.assertEqual(len(errs), 0)

    def test_pass_kwarg1(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-kwarg1').value, {})
        self.assertEqual(self.args_passed, [("a", 1, "default")])
        self.assertEqual(len(errs), 0)

    def test_pass_kwarg2(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-kwarg2').value, {})
        self.assertEqual(self.args_passed, [("a", None, "other")])
        self.assertEqual(len(errs), 0)

    def test_pass_kwargs(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-kwargs').value, {})
        self.assertEqual(self.args_passed, [("a", 1, "other")])
        self.assertEqual(len(errs), 0)

    def test_missing_arg(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-user-arg').value, {})
        self.assertEqual(self.args_passed,
                         [(FluentNone('arg'), None, "default")])
        self.assertEqual(len(errs), 1)
Пример #9
0
class TestSelectExpressionWithTerms(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            -my-term = term
                 .attr = termattribute

            ref-term-attr = { -my-term.attr ->
                    [termattribute]   Term Attribute
                   *[other]           Other
            }

            ref-term-attr-other = { -my-term.attr ->
                    [x]      Term Attribute
                   *[other]  Other
            }

            ref-term-attr-missing = { -my-term.missing ->
                    [x]      Term Attribute
                   *[other]  Other
            }
        """)))

    def test_ref_term_attribute(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('ref-term-attr').value)
        self.assertEqual(val, "Term Attribute")
        self.assertEqual(len(errs), 0)

    def test_ref_term_attribute_fallback(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('ref-term-attr-other').value)
        self.assertEqual(val, "Other")
        self.assertEqual(len(errs), 0)

    def test_ref_term_attribute_missing(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('ref-term-attr-missing').value)
        self.assertEqual(val, "Other")
        self.assertEqual(len(errs), 1)
        self.assertEqual(
            errs,
            [FluentReferenceError('Unknown attribute: -my-term.missing')])
Пример #10
0
class TestDatetimeBuiltin(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            implicit-call    = { $date }
            explicit-call    = { DATETIME($date) }
            call-with-arg    = { DATETIME($date, dateStyle: "long") }
        """)))

    def test_implicit_call_date(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('implicit-call').value,
            {'date': date(2018, 2, 1)})
        self.assertEqual(val, "Feb 1, 2018")
        self.assertEqual(len(errs), 0)

    def test_implicit_call_datetime(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('implicit-call').value,
            {'date': datetime(2018, 2, 1, 14, 15, 16)})
        self.assertEqual(val, "Feb 1, 2018")
        self.assertEqual(len(errs), 0)

    def test_explicit_call_date(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('explicit-call').value,
            {'date': date(2018, 2, 1)})
        self.assertEqual(val, "Feb 1, 2018")
        self.assertEqual(len(errs), 0)

    def test_explicit_call_datetime(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('explicit-call').value,
            {'date': datetime(2018, 2, 1, 14, 15, 16)})
        self.assertEqual(val, "Feb 1, 2018")
        self.assertEqual(len(errs), 0)

    def test_explicit_call_date_fluent_date(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('explicit-call').value,
            {'date': fluent_date(date(2018, 2, 1), dateStyle='short')})
        self.assertEqual(val, "2/1/18")
        self.assertEqual(len(errs), 0)

    def test_arg(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('call-with-arg').value,
            {'date': date(2018, 2, 1)})
        self.assertEqual(val, "February 1, 2018")
        self.assertEqual(len(errs), 0)

    def test_arg_overrides_fluent_date(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('call-with-arg').value,
            {'date': fluent_date(date(2018, 2, 1), dateStyle='short')})
        self.assertEqual(val, "February 1, 2018")
        self.assertEqual(len(errs), 0)
Пример #11
0
class TestStrings(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(FluentResource(dedent_ftl("""
            foo = { $arg }
        """)))

    def test_can_be_a_string(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('foo').value, {'arg': 'Argument'})
        self.assertEqual(val, 'Argument')
        self.assertEqual(len(errs), 0)
class TestParameterizedTermAttributes(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            -brand = Cool Thing
                .status = { $version ->
                    [v2]     available
                   *[v1]     deprecated
                }

            attr-with-arg = { -brand } is { -brand.status(version: "v2") ->
                 [available]   available, yay!
                *[deprecated]  deprecated, sorry
            }

            -other = { $arg ->
                        [a]  ABC
                       *[d]  DEF
                     }

            missing-attr-ref = { -other.missing(arg: "a") ->
                 [ABC]  ABC option
                *[DEF]  DEF option
            }
        """)))

    def test_with_argument(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('attr-with-arg').value, {})
        self.assertEqual(val, 'Cool Thing is available, yay!')
        self.assertEqual(errs, [])

    def test_missing_attr(self):
        # We don't fall back from attributes, get default.
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('missing-attr-ref').value, {})
        self.assertEqual(val, 'DEF option')
        self.assertEqual(
            errs, [FluentReferenceError('Unknown attribute: -other.missing')])
Пример #13
0
class TestSelectExpressionWithNumbers(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = { 1 ->
               *[0] A
                [1] B
             }

            bar = { 2 ->
               *[0] A
                [1] B
             }

            baz = { $num ->
               *[0] A
                [1] B
             }

            qux = { 1.0 ->
               *[0] A
                [1] B
             }
        """)))

    def test_selects_the_right_variant(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {})
        self.assertEqual(val, "B")
        self.assertEqual(len(errs), 0)

    def test_with_a_non_matching_selector(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('bar').value, {})
        self.assertEqual(val, "A")
        self.assertEqual(len(errs), 0)

    def test_with_a_missing_selector(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('baz').value, {})
        self.assertEqual(val, "A")
        self.assertEqual(errs, [FluentReferenceError("Unknown external: num")])

    def test_with_argument_int(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('baz').value, {'num': 1})
        self.assertEqual(val, "B")

    def test_with_argument_float(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('baz').value, {'num': 1.0})
        self.assertEqual(val, "B")

    def test_with_float(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('qux').value, {})
        self.assertEqual(val, "B")
Пример #14
0
class TestSkipIsolating(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'])
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            -brand-short-name = Amaya
            foo = { -brand-short-name }
            with-arg = { $arg }
        """)))

    def test_skip_isolating_chars_if_just_one_message_ref(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {})
        self.assertEqual(val, 'Amaya')
        self.assertEqual(len(errs), 0)

    def test_skip_isolating_chars_if_just_one_placeable_arg(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('with-arg').value, {'arg': 'Arg'})
        self.assertEqual(val, 'Arg')
        self.assertEqual(len(errs), 0)
Пример #15
0
class TestBillionLaughs(unittest.TestCase):
    def setUp(self):
        self.ctx = FluentBundle(['en-US'], use_isolating=False)
        self.ctx.add_resource(
            FluentResource(
                dedent_ftl("""
            lol0 = 01234567890123456789012345678901234567890123456789
            lol1 = {lol0}{lol0}{lol0}{lol0}{lol0}{lol0}{lol0}{lol0}{lol0}{lol0}
            lol2 = {lol1}{lol1}{lol1}{lol1}{lol1}{lol1}{lol1}{lol1}{lol1}{lol1}
            lol3 = {lol2}{lol2}{lol2}{lol2}{lol2}{lol2}{lol2}{lol2}{lol2}{lol2}
            lol4 = {lol3}{lol3}{lol3}{lol3}{lol3}{lol3}{lol3}{lol3}{lol3}{lol3}
            lolz = {lol4}

            elol0 = { "" }
            elol1 = {elol0}{elol0}{elol0}{elol0}{elol0}{elol0}{elol0}{elol0}{elol0}{elol0}
            elol2 = {elol1}{elol1}{elol1}{elol1}{elol1}{elol1}{elol1}{elol1}{elol1}{elol1}
            elol3 = {elol2}{elol2}{elol2}{elol2}{elol2}{elol2}{elol2}{elol2}{elol2}{elol2}
            elol4 = {elol3}{elol3}{elol3}{elol3}{elol3}{elol3}{elol3}{elol3}{elol3}{elol3}
            elol5 = {elol4}{elol4}{elol4}{elol4}{elol4}{elol4}{elol4}{elol4}{elol4}{elol4}
            elol6 = {elol5}{elol5}{elol5}{elol5}{elol5}{elol5}{elol5}{elol5}{elol5}{elol5}
            emptylolz = {elol6}

        """)))

    def test_max_length_protection(self):
        val, errs = self.ctx.format_pattern(self.ctx.get_message('lolz').value)
        self.assertEqual(val, '{???}')
        self.assertNotEqual(len(errs), 0)
        self.assertIn('Too many characters', str(errs[-1]))

    def test_max_expansions_protection(self):
        # Without protection, emptylolz will take a really long time to
        # evaluate, although it generates an empty message.
        val, errs = self.ctx.format_pattern(
            self.ctx.get_message('emptylolz').value)
        self.assertEqual(val, '{???}')
        self.assertEqual(len(errs), 1)
        self.assertIn('Too many parts', str(errs[-1]))
Пример #16
0
class TestUseIsolating(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'])
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = Foo
            bar = { foo } Bar
            baz = { $arg } Baz
            qux = { bar } { baz }
        """)))

    def test_isolates_interpolated_message_references(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('bar').value, {})
        self.assertEqual(val, FSI + "Foo" + PDI + " Bar")
        self.assertEqual(len(errs), 0)

    def test_isolates_interpolated_string_typed_variable_references(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('baz').value, {'arg': 'Arg'})
        self.assertEqual(val, FSI + "Arg" + PDI + " Baz")
        self.assertEqual(len(errs), 0)

    def test_isolates_interpolated_number_typed_variable_references(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('baz').value, {'arg': 1})
        self.assertEqual(val, FSI + "1" + PDI + " Baz")
        self.assertEqual(len(errs), 0)

    def test_isolates_complex_interpolations(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('qux').value, {'arg': 'Arg'})
        expected_bar = FSI + FSI + "Foo" + PDI + " Bar" + PDI
        expected_baz = FSI + FSI + "Arg" + PDI + " Baz" + PDI
        self.assertEqual(val, expected_bar + " " + expected_baz)
        self.assertEqual(len(errs), 0)
class TestTermsCalledFromTerms(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            -foo = {$a} {$b}
            -bar = {-foo(b: 2)}
            -baz = {-foo}
            ref-bar = {-bar(a: 1)}
            ref-baz = {-baz(a: 1)}
        """)))

    def test_term_args_isolated_with_call_syntax(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('ref-bar').value, {})
        self.assertEqual(val, 'a 2')
        self.assertEqual(errs, [])

    def test_term_args_isolated_without_call_syntax(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('ref-baz').value, {})
        self.assertEqual(val, 'a b')
        self.assertEqual(errs, [])
Пример #18
0
class TestMissing(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(FluentResource(dedent_ftl("""
            foo = Foo
            bar = Bar
                .attr = Bar Attribute
            baz = { foo } Baz
            qux = { foo } Qux
                .attr = Qux Attribute
            ref-foo = { foo.missing }
            ref-bar = { bar.missing }
            ref-baz = { baz.missing }
            ref-qux = { qux.missing }
            attr-only =
                     .attr  = Attr Only Attribute
            ref-double-missing = { missing.attr }
        """)))

    def test_msg_with_string_value_and_no_attributes(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('ref-foo').value, {})
        self.assertEqual(val, '{foo.missing}')
        self.assertEqual(errs,
                         [FluentReferenceError(
                             'Unknown attribute: foo.missing')])

    def test_msg_with_string_value_and_other_attributes(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('ref-bar').value, {})
        self.assertEqual(val, '{bar.missing}')
        self.assertEqual(errs,
                         [FluentReferenceError(
                             'Unknown attribute: bar.missing')])

    def test_msg_with_pattern_value_and_no_attributes(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('ref-baz').value, {})
        self.assertEqual(val, '{baz.missing}')
        self.assertEqual(errs,
                         [FluentReferenceError(
                             'Unknown attribute: baz.missing')])

    def test_msg_with_pattern_value_and_other_attributes(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('ref-qux').value, {})
        self.assertEqual(val, '{qux.missing}')
        self.assertEqual(errs,
                         [FluentReferenceError(
                             'Unknown attribute: qux.missing')])

    def test_attr_only_attribute(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('attr-only').attributes['attr'], {})
        self.assertEqual(val, 'Attr Only Attribute')
        self.assertEqual(len(errs), 0)

    def test_missing_message_and_attribute(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('ref-double-missing').value, {})
        self.assertEqual(val, '{missing.attr}')
        self.assertEqual(errs, [FluentReferenceError('Unknown attribute: missing.attr')])
Пример #19
0
class TestMissing(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            missing = { MISSING(1) }
        """)))

    def test_falls_back_to_name_of_function(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('missing').value, {})
        self.assertEqual(val, "MISSING()")
        self.assertEqual(errs,
                         [FluentReferenceError("Unknown function: MISSING")])
class TestMessagesCalledFromTerms(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            msg = Msg is {$arg}
            -foo = {msg}
            ref-foo = {-foo(arg: 1)}
        """)))

    def test_messages_inherit_term_args(self):
        # This behaviour may change in future, message calls might be
        # disallowed from inside terms
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('ref-foo').value, {'arg': 2})
        self.assertEqual(val, 'Msg is 1')
        self.assertEqual(errs, [])
Пример #21
0
class TestSingleElementPattern(unittest.TestCase):
    def test_single_literal_number_isolating(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=True)
        self.bundle.add_resource(FluentResource('foo = { 1 }'))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value)
        self.assertEqual(val, '1')
        self.assertEqual(errs, [])

    def test_single_literal_number_non_isolating(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(FluentResource('foo = { 1 }'))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value)
        self.assertEqual(val, '1')
        self.assertEqual(errs, [])

    def test_single_arg_number_isolating(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=True)
        self.bundle.add_resource(FluentResource('foo = { $arg }'))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {'arg': 1})
        self.assertEqual(val, '1')
        self.assertEqual(errs, [])

    def test_single_arg_number_non_isolating(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(FluentResource('foo = { $arg }'))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {'arg': 1})
        self.assertEqual(val, '1')
        self.assertEqual(errs, [])

    def test_single_arg_missing_isolating(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=True)
        self.bundle.add_resource(FluentResource('foo = { $arg }'))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value)
        self.assertEqual(val, 'arg')
        self.assertEqual(len(errs), 1)

    def test_single_arg_missing_non_isolating(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(FluentResource('foo = { $arg }'))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value)
        self.assertEqual(val, 'arg')
        self.assertEqual(len(errs), 1)
Пример #22
0
class TestSelectExpressionWithPluralCategories(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = { 1 ->
                [one] A
               *[other] B
             }

            bar = { 1 ->
                [1] A
               *[other] B
             }

            baz = { "not a number" ->
                [one] A
               *[other] B
             }

            qux = { $num ->
                [one] A
               *[other] B
             }
        """)))

    def test_selects_the_right_category(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {})
        self.assertEqual(val, "A")
        self.assertEqual(len(errs), 0)

    def test_selects_exact_match(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('bar').value, {})
        self.assertEqual(val, "A")
        self.assertEqual(len(errs), 0)

    def test_selects_default_with_invalid_selector(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('baz').value, {})
        self.assertEqual(val, "B")
        self.assertEqual(len(errs), 0)

    def test_with_a_missing_selector(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('qux').value, {})
        self.assertEqual(val, "B")
        self.assertEqual(errs, [FluentReferenceError("Unknown external: num")])

    def test_with_argument_integer(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('qux').value, {'num': 1})
        self.assertEqual(val, "A")
        self.assertEqual(len(errs), 0)

        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('qux').value, {'num': 2})
        self.assertEqual(val, "B")
        self.assertEqual(len(errs), 0)

    def test_with_argument_float(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('qux').value, {'num': 1.0})
        self.assertEqual(val, "A")
        self.assertEqual(len(errs), 0)
class TestParameterizedTerms(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            -thing = { $article ->
                  *[definite] the thing
                   [indefinite] a thing
                   [none] thing
            }
            thing-no-arg = { -thing }
            thing-no-arg-alt = { -thing() }
            thing-with-arg = { -thing(article: "indefinite") }
            thing-positional-arg = { -thing("foo") }
            thing-fallback = { -thing(article: "somethingelse") }
            bad-term = { -missing() }
        """)))

    def test_argument_omitted(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('thing-no-arg').value, {})
        self.assertEqual(val, 'the thing')
        self.assertEqual(errs, [])

    def test_argument_omitted_alt(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('thing-no-arg-alt').value, {})
        self.assertEqual(val, 'the thing')
        self.assertEqual(errs, [])

    def test_with_argument(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('thing-with-arg').value, {})
        self.assertEqual(val, 'a thing')
        self.assertEqual(errs, [])

    def test_positional_arg(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('thing-positional-arg').value, {})
        self.assertEqual(val, 'the thing')
        self.assertEqual(errs, [
            FluentFormatError(
                "Ignored positional arguments passed to term '-thing'")
        ])

    def test_fallback(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('thing-fallback').value, {})
        self.assertEqual(val, 'the thing')
        self.assertEqual(errs, [])

    def test_no_implicit_access_to_external_args(self):
        # The '-thing' term should not get passed article="indefinite"
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('thing-no-arg').value,
            {'article': 'indefinite'})
        self.assertEqual(val, 'the thing')
        self.assertEqual(errs, [])

    def test_no_implicit_access_to_external_args_but_term_args_still_passed(
            self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('thing-with-arg').value,
            {'article': 'none'})
        self.assertEqual(val, 'a thing')
        self.assertEqual(errs, [])

    def test_bad_term(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('bad-term').value, {})
        self.assertEqual(val, '{-missing}')
        self.assertEqual(errs,
                         [FluentReferenceError('Unknown term: -missing')])
Пример #24
0
class TestSimpleStringValue(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(FluentResource(dedent_ftl(r"""
            foo               = Foo
            placeable-literal = { "Foo" } Bar
            placeable-message = { foo } Bar
            selector-literal = { "Foo" ->
                [Foo] Member 1
               *[Bar] Member 2
             }
            bar =
                .attr = Bar Attribute
            placeable-attr   = { bar.attr }
            -baz = Baz
                .attr = BazAttribute
            selector-attr    = { -baz.attr ->
                [BazAttribute] Member 3
               *[other]        Member 4
             }
            escapes = {"    "}stuff{"\u0258}\"\\end"}
        """)))

    def test_can_be_used_as_a_value(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('foo').value, {})
        self.assertEqual(val, 'Foo')
        self.assertEqual(len(errs), 0)

    def test_can_be_used_in_a_placeable(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('placeable-literal').value, {})
        self.assertEqual(val, 'Foo Bar')
        self.assertEqual(len(errs), 0)

    def test_can_be_a_value_of_a_message_referenced_in_a_placeable(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('placeable-message').value, {})
        self.assertEqual(val, 'Foo Bar')
        self.assertEqual(len(errs), 0)

    def test_can_be_a_selector(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('selector-literal').value, {})
        self.assertEqual(val, 'Member 1')
        self.assertEqual(len(errs), 0)

    def test_can_be_used_as_an_attribute_value(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('bar').attributes['attr'], {})
        self.assertEqual(val, 'Bar Attribute')
        self.assertEqual(len(errs), 0)

    def test_can_be_a_value_of_an_attribute_used_in_a_placeable(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('placeable-attr').value, {})
        self.assertEqual(val, 'Bar Attribute')
        self.assertEqual(len(errs), 0)

    def test_can_be_a_value_of_an_attribute_used_as_a_selector(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('selector-attr').value, {})
        self.assertEqual(val, 'Member 3')
        self.assertEqual(len(errs), 0)

    def test_escapes(self):
        val, errs = self.bundle.format_pattern(self.bundle.get_message('escapes').value, {})
        self.assertEqual(val, r'    stuffɘ}"\end')
        self.assertEqual(len(errs), 0)
Пример #25
0
class TestFluentBundle(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'])

    def test_add_resource(self):
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = Foo
            bar = Bar
            -baz = Baz
        """)))
        self.assertIn('foo', self.bundle._messages)
        self.assertIn('bar', self.bundle._messages)
        self.assertIn('baz', self.bundle._terms)

    def test_has_message(self):
        self.bundle.add_resource(
            FluentResource(dedent_ftl("""
            foo = Foo
        """)))

        self.assertTrue(self.bundle.has_message('foo'))
        self.assertFalse(self.bundle.has_message('bar'))

    def test_has_message_for_term(self):
        self.bundle.add_resource(
            FluentResource(dedent_ftl("""
            -foo = Foo
        """)))

        self.assertFalse(self.bundle.has_message('-foo'))

    def test_has_message_with_attribute(self):
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = Foo
                .attr = Foo Attribute
        """)))

        self.assertTrue(self.bundle.has_message('foo'))
        self.assertFalse(self.bundle.has_message('foo.attr'))
        self.assertFalse(self.bundle.has_message('foo.other-attribute'))

    def test_plural_form_english_ints(self):
        bundle = FluentBundle(['en-US'])
        self.assertEqual(bundle._plural_form(0), 'other')
        self.assertEqual(bundle._plural_form(1), 'one')
        self.assertEqual(bundle._plural_form(2), 'other')

    def test_plural_form_english_floats(self):
        bundle = FluentBundle(['en-US'])
        self.assertEqual(bundle._plural_form(0.0), 'other')
        self.assertEqual(bundle._plural_form(1.0), 'one')
        self.assertEqual(bundle._plural_form(2.0), 'other')
        self.assertEqual(bundle._plural_form(0.5), 'other')

    def test_plural_form_french(self):
        # Just spot check one other, to ensure that we
        # are not getting the EN locale by accident or
        bundle = FluentBundle(['fr'])
        self.assertEqual(bundle._plural_form(0), 'one')
        self.assertEqual(bundle._plural_form(1), 'one')
        self.assertEqual(bundle._plural_form(2), 'other')

    def test_format_args(self):
        self.bundle.add_resource(FluentResource('foo = Foo'))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value)
        self.assertEqual(val, 'Foo')

        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {})
        self.assertEqual(val, 'Foo')

    def test_format_missing(self):
        self.assertRaises(LookupError, self.bundle.get_message,
                          'a-missing-message')

    def test_format_term(self):
        self.bundle.add_resource(
            FluentResource(dedent_ftl("""
            -foo = Foo
        """)))
        self.assertRaises(LookupError, self.bundle.get_message, '-foo')
        self.assertRaises(LookupError, self.bundle.get_message, 'foo')

    def test_message_and_term_separate(self):
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = Refers to { -foo }
            -foo = Foo
        """)))
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('foo').value, {})
        self.assertEqual(val, 'Refers to \u2068Foo\u2069')
        self.assertEqual(errs, [])
Пример #26
0
class TestFunctionCalls(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'],
                                   use_isolating=False,
                                   functions={'IDENTITY': lambda x: x})
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            foo = Foo
                .attr = Attribute
            pass-nothing       = { IDENTITY() }
            pass-string        = { IDENTITY("a") }
            pass-number        = { IDENTITY(1) }
            pass-message       = { IDENTITY(foo) }
            pass-attr          = { IDENTITY(foo.attr) }
            pass-external      = { IDENTITY($ext) }
            pass-function-call = { IDENTITY(IDENTITY(1)) }
        """)))

    def test_accepts_strings(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-string').value, {})
        self.assertEqual(val, "a")
        self.assertEqual(len(errs), 0)

    def test_accepts_numbers(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-number').value, {})
        self.assertEqual(val, "1")
        self.assertEqual(len(errs), 0)

    def test_accepts_entities(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-message').value, {})
        self.assertEqual(val, "Foo")
        self.assertEqual(len(errs), 0)

    def test_accepts_attributes(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-attr').value, {})
        self.assertEqual(val, "Attribute")
        self.assertEqual(len(errs), 0)

    def test_accepts_externals(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-external').value, {'ext': 'Ext'})
        self.assertEqual(val, "Ext")
        self.assertEqual(len(errs), 0)

    def test_accepts_function_calls(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-function-call').value, {})
        self.assertEqual(val, "1")
        self.assertEqual(len(errs), 0)

    def test_wrong_arity(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('pass-nothing').value, {})
        self.assertEqual(val, "IDENTITY()")
        self.assertEqual(len(errs), 1)
        self.assertEqual(type(errs[0]), TypeError)
Пример #27
0
class TestNumberBuiltin(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            implicit-call    = { 123456 }
            implicit-call2   = { $arg }
            defaults         = { NUMBER(123456) }
            percent-style    = { NUMBER(1.234, style: "percent") }
            currency-style   = { NUMBER(123456, style: "currency", currency: "USD") }
            from-arg         = { NUMBER($arg) }
            merge-params     = { NUMBER($arg, useGrouping: 0) }
        """)))

    def test_implicit_call(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('implicit-call').value, {})
        self.assertEqual(val, "123,456")
        self.assertEqual(len(errs), 0)

    def test_implicit_call2_int(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('implicit-call2').value, {'arg': 123456})
        self.assertEqual(val, "123,456")
        self.assertEqual(len(errs), 0)

    def test_implicit_call2_float(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('implicit-call2').value, {'arg': 123456.0})
        self.assertEqual(val, "123,456")
        self.assertEqual(len(errs), 0)

    def test_implicit_call2_decimal(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('implicit-call2').value,
            {'arg': Decimal('123456.0')})
        self.assertEqual(val, "123,456")
        self.assertEqual(len(errs), 0)

    def test_defaults(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('defaults').value, {})
        self.assertEqual(val, "123,456")
        self.assertEqual(len(errs), 0)

    def test_percent_style(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('percent-style').value, {})
        self.assertEqual(val, "123%")
        self.assertEqual(len(errs), 0)

    def test_currency_style(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('currency-style').value, {})
        self.assertEqual(val, "$123,456.00")
        self.assertEqual(len(errs), 0)

    def test_from_arg_int(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('from-arg').value, {'arg': 123456})
        self.assertEqual(val, "123,456")
        self.assertEqual(len(errs), 0)

    def test_from_arg_float(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('from-arg').value, {'arg': 123456.0})
        self.assertEqual(val, "123,456")
        self.assertEqual(len(errs), 0)

    def test_from_arg_decimal(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('from-arg').value,
            {'arg': Decimal('123456.0')})
        self.assertEqual(val, "123,456")
        self.assertEqual(len(errs), 0)

    def test_from_arg_missing(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('from-arg').value, {})
        self.assertEqual(val, "arg")
        self.assertEqual(len(errs), 1)
        self.assertEqual(errs, [FluentReferenceError('Unknown external: arg')])

    def test_partial_application(self):
        number = fluent_number(123456.78, currency="USD", style="currency")
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('from-arg').value, {'arg': number})
        self.assertEqual(val, "$123,456.78")
        self.assertEqual(len(errs), 0)

    def test_merge_params(self):
        number = fluent_number(123456.78, currency="USD", style="currency")
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('merge-params').value, {'arg': number})
        self.assertEqual(val, "$123456.78")
        self.assertEqual(len(errs), 0)
Пример #28
0
class TestPlaceables(unittest.TestCase):
    def setUp(self):
        self.bundle = FluentBundle(['en-US'], use_isolating=False)
        self.bundle.add_resource(
            FluentResource(
                dedent_ftl("""
            message = Message
                    .attr = Message Attribute
            -term = Term
                  .attr = Term Attribute
            -term2 = {
               *[variant1] Term Variant 1
                [variant2] Term Variant 2
             }

            uses-message = { message }
            uses-message-attr = { message.attr }
            uses-term = { -term }

            bad-message-ref = Text { not-a-message }
            bad-message-attr-ref = Text { message.not-an-attr }
            bad-term-ref = Text { -not-a-term }

            self-referencing-message = Text { self-referencing-message }
            cyclic-msg1 = Text1 { cyclic-msg2 }
            cyclic-msg2 = Text2 { cyclic-msg1 }
            self-cyclic-message = Parent { self-cyclic-message.attr }
                                .attr = Attribute { self-cyclic-message }

            self-attribute-ref-ok = Parent { self-attribute-ref-ok.attr }
                                  .attr = Attribute
            self-parent-ref-ok = Parent
                               .attr =  Attribute { self-parent-ref-ok }
        """)))

    def test_placeable_message(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('uses-message').value, {})
        self.assertEqual(val, 'Message')
        self.assertEqual(len(errs), 0)

    def test_placeable_message_attr(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('uses-message-attr').value, {})
        self.assertEqual(val, 'Message Attribute')
        self.assertEqual(len(errs), 0)

    def test_placeable_term(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('uses-term').value, {})
        self.assertEqual(val, 'Term')
        self.assertEqual(len(errs), 0)

    def test_placeable_bad_message(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('bad-message-ref').value, {})
        self.assertEqual(val, 'Text {not-a-message}')
        self.assertEqual(len(errs), 1)
        self.assertEqual(
            errs, [FluentReferenceError("Unknown message: not-a-message")])

    def test_placeable_bad_message_attr(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('bad-message-attr-ref').value, {})
        self.assertEqual(val, 'Text {message.not-an-attr}')
        self.assertEqual(len(errs), 1)
        self.assertEqual(
            errs,
            [FluentReferenceError("Unknown attribute: message.not-an-attr")])

    def test_placeable_bad_term(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('bad-term-ref').value, {})
        self.assertEqual(val, 'Text {-not-a-term}')
        self.assertEqual(len(errs), 1)
        self.assertEqual(errs,
                         [FluentReferenceError("Unknown term: -not-a-term")])

    def test_cycle_detection(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('self-referencing-message').value, {})
        self.assertEqual(val, 'Text ???')
        self.assertEqual(len(errs), 1)
        self.assertEqual(errs,
                         [FluentCyclicReferenceError("Cyclic reference")])

    def test_mutual_cycle_detection(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('cyclic-msg1').value, {})
        self.assertEqual(val, 'Text1 Text2 ???')
        self.assertEqual(len(errs), 1)
        self.assertEqual(errs,
                         [FluentCyclicReferenceError("Cyclic reference")])

    def test_allowed_self_reference(self):
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('self-attribute-ref-ok').value, {})
        self.assertEqual(val, 'Parent Attribute')
        self.assertEqual(len(errs), 0)
        val, errs = self.bundle.format_pattern(
            self.bundle.get_message('self-parent-ref-ok').attributes['attr'],
            {})
        self.assertEqual(val, 'Attribute Parent')
        self.assertEqual(len(errs), 0)