Best Python code snippet using assertpy_python
test_extend.py
Source:test_extend.py  
1from __future__ import absolute_import2from __future__ import unicode_literals3from scss import Scss4import pytest5# py.test bug: unicode literals not allowed here, so cast to native str type6pytestmark = pytest.mark.skipif(str("not config.getoption('include_ruby')"))7# TODO undupe8def assert_rendering(input, expected, **kwargs):9    compiler = Scss(scss_opts=dict(compress=False), **kwargs)10    css = compiler.compile(input)11    # TODO chumptastic hack; sass and pyscss have slightly different12    # "non-compressed" output13    import re14    css = re.sub(r'(?m)\n *[}]$', ' }\n', css).rstrip("\n") + "\n"15    #css = re.sub(r'; [}]', ';\n  }', css)16    #css = re.sub(r'\n *[}]$', ' }', css)17    assert expected == css18def test_basic():19    assert_rendering('''\20.foo {a: b}21.bar {@extend .foo}22''', '''\23.foo, .bar {24  a: b; }25''')26    assert_rendering('''\27.bar {@extend .foo}28.foo {a: b}29''', '''\30.foo, .bar {31  a: b; }32''')33    assert_rendering('''\34.foo {a: b}35.bar {c: d; @extend .foo}36''', '''\37.foo, .bar {38  a: b; }39.bar {40  c: d; }41''')42    assert_rendering('''\43.foo {a: b}44.bar {@extend .foo; c: d}45''', '''\46.foo, .bar {47  a: b; }48.bar {49  c: d; }50''')51def test_multiple_targets():52    assert_rendering('''\53.foo {a: b}54.bar {@extend .foo}55.blip .foo {c: d}56''', '''\57.foo, .bar {58  a: b; }59.blip .foo, .blip .bar {60  c: d; }61''')62def test_multiple_extendees():63    assert_rendering('''\64.foo {a: b}65.bar {c: d}66.baz {@extend .foo; @extend .bar}67''', '''\68.foo, .baz {69  a: b; }70.bar, .baz {71  c: d; }72''')73def test_multiple_extends_with_single_extender_and_single_target():74    assert_extends(75        '.foo .bar',76        '.baz {@extend .foo; @extend .bar}',77        '.foo .bar, .baz .bar, .foo .baz, .baz .baz')78    assert_extends(79        '.foo.bar',80        '.baz {@extend .foo; @extend .bar}',81        '.foo.bar, .baz')82def test_multiple_extends_with_multiple_extenders_and_single_target():83    assert_rendering('''\84.foo .bar {a: b}85.baz {@extend .foo}86.bang {@extend .bar}87''', '''\88.foo .bar, .baz .bar, .foo .bang, .baz .bang {89  a: b; }90''')91    assert_rendering('''\92.foo.bar {a: b}93.baz {@extend .foo}94.bang {@extend .bar}95''', '''\96.foo.bar, .bar.baz, .baz.bang, .foo.bang {97  a: b; }98''')99def test_chained_extends():100    assert_rendering('''\101.foo {a: b}102.bar {@extend .foo}103.baz {@extend .bar}104.bip {@extend .bar}105''', '''\106.foo, .bar, .baz, .bip {107  a: b; }108''')109def test_dynamic_extendee():110    assert_extends(111        '.foo',112        '.bar {@extend #{".foo"}}',113        '.foo, .bar')114    assert_extends(115        '[baz^="blip12px"]',116        '.bar {@extend [baz^="blip#{12px}"]}',117        '[baz^="blip12px"], .bar')118def test_nested_target():119    assert_extends(120        '.foo .bar',121        '.baz {@extend .bar}',122        '.foo .bar, .foo .baz')123def test_target_with_child():124    assert_extends(125        '.foo .bar',126        '.baz {@extend .foo}',127        '.foo .bar, .baz .bar')128def test_class_unification():129    assert_unification(130        '.foo.bar',131        '.baz {@extend .foo}',132        '.foo.bar, .bar.baz')133    assert_unification(134        '.foo.baz',135        '.baz {@extend .foo}',136        '.baz')137def test_id_unification():138    assert_unification(139        '.foo.bar',140        '#baz {@extend .foo}',141        '.foo.bar, .bar#baz')142    assert_unification(143        '.foo#baz',144        '#baz {@extend .foo}',145        '#baz')146    # XXX assert_extend_doesnt_match('#bar', '.foo', :failed_to_unify, 2) do147    assert_unification(148        '.foo#baz',149        '#bar {@extend .foo}',150        '.foo#baz')151def test_universal_unification_with_simple_target():152    assert_unification(153        '.foo',154        '* {@extend .foo}',155        '.foo, *')156    assert_unification(157        '.foo',158        '*|* {@extend .foo}',159        '.foo, *|*')160    assert_unification(161        '.foo.bar',162        '* {@extend .foo}',163        '.bar')164    assert_unification(165        '.foo.bar',166        '*|* {@extend .foo}',167        '.bar')168    assert_unification(169        '.foo.bar',170        'ns|* {@extend .foo}',171        '.foo.bar, ns|*.bar')172def test_universal_unification_with_namespaceless_universal_target():173    assert_unification(174        '*.foo',175        '* {@extend .foo}',176        '*')177    assert_unification(178        '*.foo',179        '*|* {@extend .foo}',180        '*')181    assert_unification(182        '*|*.foo',183        '* {@extend .foo}',184        '*|*.foo, *')185    assert_unification(186        '*|*.foo',187        '*|* {@extend .foo}',188        '*|*')189    assert_unification(190        '*.foo',191        'ns|* {@extend .foo}',192        '*.foo, ns|*')193    assert_unification(194        '*|*.foo',195        'ns|* {@extend .foo}',196        '*|*.foo, ns|*')197def test_universal_unification_with_namespaced_universal_target():198    assert_unification(199        'ns|*.foo',200        '* {@extend .foo}',201        'ns|*')202    assert_unification(203        'ns|*.foo',204        '*|* {@extend .foo}',205        'ns|*')206    # XXX assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do207    assert_unification(208        'ns1|*.foo',209        'ns2|* {@extend .foo}',210        'ns1|*.foo')211    assert_unification(212        'ns|*.foo',213        'ns|* {@extend .foo}',214        'ns|*')215def test_universal_unification_with_namespaceless_element_target():216    assert_unification(217        'a.foo',218        '* {@extend .foo}',219        'a')220    assert_unification(221        'a.foo',222        '*|* {@extend .foo}',223        'a')224    assert_unification(225        '*|a.foo',226        '* {@extend .foo}',227        '*|a.foo, a')228    assert_unification(229        '*|a.foo',230        '*|* {@extend .foo}',231        '*|a')232    assert_unification(233        'a.foo',234        'ns|* {@extend .foo}',235        'a.foo, ns|a')236    assert_unification(237        '*|a.foo',238        'ns|* {@extend .foo}',239        '*|a.foo, ns|a')240def test_universal_unification_with_namespaced_element_target():241    assert_unification(242        'ns|a.foo',243        '* {@extend .foo}',244        'ns|a')245    assert_unification(246        'ns|a.foo',247        '*|* {@extend .foo}',248        'ns|a')249    # XXX assert_extend_doesnt_match('ns2|*', '.foo', :failed_to_unify, 2) do250    assert_unification(251        'ns1|a.foo',252        'ns2|* {@extend .foo}',253        'ns1|a.foo')254    assert_unification(255        'ns|a.foo',256        'ns|* {@extend .foo}',257        'ns|a')258def test_element_unification_with_simple_target():259    assert_unification(260        '.foo',261        'a {@extend .foo}',262        '.foo, a')263    assert_unification(264        '.foo.bar',265        'a {@extend .foo}',266        '.foo.bar, a.bar')267    assert_unification(268        '.foo.bar',269        '*|a {@extend .foo}',270        '.foo.bar, *|a.bar')271    assert_unification(272        '.foo.bar',273        'ns|a {@extend .foo}',274        '.foo.bar, ns|a.bar')275def test_element_unification_with_namespaceless_universal_target():276    assert_unification(277        '*.foo',278        'a {@extend .foo}',279        '*.foo, a')280    assert_unification(281        '*.foo',282        '*|a {@extend .foo}',283        '*.foo, a')284    assert_unification(285        '*|*.foo',286        'a {@extend .foo}',287        '*|*.foo, a')288    assert_unification(289        '*|*.foo',290        '*|a {@extend .foo}',291        '*|*.foo, *|a')292    assert_unification(293        '*.foo',294        'ns|a {@extend .foo}',295        '*.foo, ns|a')296    assert_unification(297        '*|*.foo',298        'ns|a {@extend .foo}',299        '*|*.foo, ns|a')300def test_element_unification_with_namespaced_universal_target():301    assert_unification(302        'ns|*.foo',303        'a {@extend .foo}',304        'ns|*.foo, ns|a')305    assert_unification(306        'ns|*.foo',307        '*|a {@extend .foo}',308        'ns|*.foo, ns|a')309    # XXX assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do310    assert_unification(311        'ns1|*.foo',312        'ns2|a {@extend .foo}',313        'ns1|*.foo')314    assert_unification(315        'ns|*.foo',316        'ns|a {@extend .foo}',317        'ns|*.foo, ns|a')318def test_element_unification_with_namespaceless_element_target():319    assert_unification(320        'a.foo',321        'a {@extend .foo}',322        'a')323    assert_unification(324        'a.foo',325        '*|a {@extend .foo}',326        'a')327    assert_unification(328        '*|a.foo',329        'a {@extend .foo}',330        '*|a.foo, a')331    assert_unification(332        '*|a.foo',333        '*|a {@extend .foo}',334        '*|a')335    assert_unification(336        'a.foo',337        'ns|a {@extend .foo}',338        'a.foo, ns|a')339    assert_unification(340        '*|a.foo',341        'ns|a {@extend .foo}',342        '*|a.foo, ns|a')343    # XXX assert_extend_doesnt_match('h1', '.foo', :failed_to_unify, 2) do344    assert_unification(345        'a.foo',346        'h1 {@extend .foo}',347        'a.foo')348def test_element_unification_with_namespaced_element_target():349    assert_unification(350        'ns|a.foo',351        'a {@extend .foo}',352        'ns|a')353    assert_unification(354        'ns|a.foo',355        '*|a {@extend .foo}',356        'ns|a')357    # XXX assert_extend_doesnt_match('ns2|a', '.foo', :failed_to_unify, 2) do358    assert_unification(359        'ns1|a.foo',360        'ns2|a {@extend .foo}',361        'ns1|a.foo')362    assert_unification(363        'ns|a.foo',364        'ns|a {@extend .foo}',365        'ns|a')366def test_attribute_unification():367    assert_unification(368        '[foo=bar].baz',369        '[foo=baz] {@extend .baz}',370        '[foo=bar].baz, [foo=bar][foo=baz]')371    assert_unification(372        '[foo=bar].baz',373        '[foo^=bar] {@extend .baz}',374        '[foo=bar].baz, [foo=bar][foo^=bar]')375    assert_unification(376        '[foo=bar].baz',377        '[foot=bar] {@extend .baz}',378        '[foo=bar].baz, [foo=bar][foot=bar]')379    assert_unification(380        '[foo=bar].baz',381        '[ns|foo=bar] {@extend .baz}',382        '[foo=bar].baz, [foo=bar][ns|foo=bar]')383    assert_unification(384        '%-a [foo=bar].bar',385        '[foo=bar] {@extend .bar}',386        '-a [foo=bar]')387def test_pseudo_unification():388    assert_unification(389        ':foo.baz',390        ':foo(2n+1) {@extend .baz}',391        ':foo.baz, :foo:foo(2n+1)')392    assert_unification(393        ':foo.baz',394        '::foo {@extend .baz}',395        ':foo.baz, :foo::foo')396    # XXX assert_extend_doesnt_match('::bar', '.baz', :failed_to_unify, 2) do397    assert_unification(398        '::foo.baz',399        '::bar {@extend .baz}',400        '::foo.baz')401    # XXX assert_extend_doesnt_match('::foo(2n+1)', '.baz', :failed_to_unify, 2) do402    assert_unification(403        '::foo.baz',404        '::foo(2n+1) {@extend .baz}',405        '::foo.baz')406    assert_unification(407        '::foo.baz',408        '::foo {@extend .baz}',409        '::foo')410    assert_unification(411        '::foo(2n+1).baz',412        '::foo(2n+1) {@extend .baz}',413        '::foo(2n+1)')414    assert_unification(415        ':foo.baz',416        ':bar {@extend .baz}',417        ':foo.baz, :foo:bar')418    assert_unification(419        '.baz:foo',420        ':after {@extend .baz}',421        '.baz:foo, :foo:after')422    assert_unification(423        '.baz:after',424        ':foo {@extend .baz}',425        '.baz:after, :foo:after')426    assert_unification(427        ':foo.baz',428        ':foo {@extend .baz}',429        ':foo')430def test_pseudoelement_remains_at_end_of_selector():431    assert_extends(432        '.foo::bar',433        '.baz {@extend .foo}',434        '.foo::bar, .baz::bar')435    assert_extends(436        'a.foo::bar',437        '.baz {@extend .foo}',438        'a.foo::bar, a.baz::bar')439def test_pseudoclass_remains_at_end_of_selector():440    assert_extends(441        '.foo:bar',442        '.baz {@extend .foo}',443        '.foo:bar, .baz:bar')444    assert_extends(445        'a.foo:bar',446        '.baz {@extend .foo}',447        'a.foo:bar, a.baz:bar')448def test_not_remains_at_end_of_selector():449    assert_extends(450        '.foo:not(.bar)',451        '.baz {@extend .foo}',452        '.foo:not(.bar), .baz:not(.bar)')453def test_pseudoelement_goes_lefter_than_pseudoclass():454    assert_extends(455        '.foo::bar',456        '.baz:bang {@extend .foo}',457        '.foo::bar, .baz:bang::bar')458    assert_extends(459        '.foo:bar',460        '.baz::bang {@extend .foo}',461        '.foo:bar, .baz:bar::bang')462def test_pseudoelement_goes_lefter_than_not():463    assert_extends(464        '.foo::bar',465        '.baz:not(.bang) {@extend .foo}',466        '.foo::bar, .baz:not(.bang)::bar')467    assert_extends(468        '.foo:not(.bang)',469        '.baz::bar {@extend .foo}',470        '.foo:not(.bang), .baz:not(.bang)::bar')471def test_negation_unification():472    assert_unification(473        ':not(.foo).baz',474        ':not(.bar) {@extend .baz}',475        ':not(.foo).baz, :not(.foo):not(.bar)')476    assert_unification(477        ':not(.foo).baz',478        ':not(.foo) {@extend .baz}',479        ':not(.foo)')480    assert_unification(481        ':not([a=b]).baz',482        ':not([a = b]) {@extend .baz}',483        ':not([a=b])')484def test_comma_extendee():485    assert_rendering('''\486.foo {a: b}487.bar {c: d}488.baz {@extend .foo, .bar}489''', '''\490.foo, .baz {491  a: b; }492.bar, .baz {493  c: d; }494''')495def test_redundant_selector_elimination():496    assert_rendering('''\497.foo.bar {a: b}498.x {@extend .foo, .bar}499.y {@extend .foo, .bar}500''', '''\501.foo.bar, .x, .y {502  a: b; }503''')504  ## Long Extendees505def test_long_extendee():506    assert_extends(507        '.foo.bar',508        '.baz {@extend .foo.bar}',509        '.foo.bar, .baz')510def test_long_extendee_requires_all_selectors():511    # XXX assert_extend_doesnt_match('.baz', '.foo.bar', :not_found, 2) do512    assert_extends(513        '.foo',514        '.baz {@extend .foo.bar}',515        '.foo')516def test_long_extendee_matches_supersets():517    assert_extends(518        '.foo.bar.bap',519        '.baz {@extend .foo.bar}',520        '.foo.bar.bap, .bap.baz')521def test_long_extendee_runs_unification():522    assert_extends(523        'ns|*.foo.bar',524        'a.baz {@extend .foo.bar}',525        'ns|*.foo.bar, ns|a.baz')526  ## Long Extenders527def test_long_extender():528    assert_extends(529        '.foo.bar',530        '.baz.bang {@extend .foo}',531        '.foo.bar, .bar.baz.bang')532def test_long_extender_runs_unification():533    assert_extends(534        'ns|*.foo.bar',535        'a.baz {@extend .foo}',536        'ns|*.foo.bar, ns|a.bar.baz')537def test_long_extender_aborts_unification():538    # XXX assert_extend_doesnt_match('h1.baz', '.foo', :failed_to_unify, 2) do539    assert_extends(540        'a.foo#bar',541        'h1.baz {@extend .foo}',542        'a.foo#bar')543    # XXX assert_extend_doesnt_match('.bang#baz', '.foo', :failed_to_unify, 2) do544    assert_extends(545        'a.foo#bar',546        '.bang#baz {@extend .foo}',547        'a.foo#bar')548  ## Nested Extenders549def test_nested_extender():550    assert_extends(551        '.foo',552        'foo bar {@extend .foo}',553        '.foo, foo bar')554def test_nested_extender_runs_unification():555    assert_extends(556        '.foo.bar',557        'foo bar {@extend .foo}',558        '.foo.bar, foo bar.bar')559def test_nested_extender_aborts_unification():560    # XXX assert_extend_doesnt_match('foo bar', '.foo', :failed_to_unify, 2) do561    assert_extends(562        'baz.foo',563        'foo bar {@extend .foo}',564        'baz.foo')565def test_nested_extender_alternates_parents():566    assert_extends('.baz .bip .foo', 'foo .grank bar {@extend .foo}',567      '.baz .bip .foo, .baz .bip foo .grank bar, foo .grank .baz .bip bar')568def test_nested_extender_unifies_identical_parents():569    assert_extends('.baz .bip .foo', '.baz .bip bar {@extend .foo}',570      '.baz .bip .foo, .baz .bip bar')571def test_nested_extender_unifies_common_substring():572    assert_extends('.baz .bip .bap .bink .foo', '.brat .bip .bap bar {@extend .foo}',573      '.baz .bip .bap .bink .foo, .baz .brat .bip .bap .bink bar, .brat .baz .bip .bap .bink bar')574def test_nested_extender_unifies_common_subseq():575    assert_extends('.a .x .b .y .foo', '.a .n .b .m bar {@extend .foo}',576      '.a .x .b .y .foo, .a .x .n .b .y .m bar, .a .n .x .b .y .m bar, .a .x .n .b .m .y bar, .a .n .x .b .m .y bar')577def test_nested_extender_chooses_first_subseq():578    assert_extends('.a .b .c .d .foo', '.c .d .a .b .bar {@extend .foo}',579      '.a .b .c .d .foo, .a .b .c .d .a .b .bar')580def test_nested_extender_counts_extended_subselectors():581    assert_extends('.a .bip.bop .foo', '.b .bip .bar {@extend .foo}',582      '.a .bip.bop .foo, .a .b .bip.bop .bar, .b .a .bip.bop .bar')583def test_nested_extender_counts_extended_superselectors():584    assert_extends('.a .bip .foo', '.b .bip.bop .bar {@extend .foo}',585      '.a .bip .foo, .a .b .bip.bop .bar, .b .a .bip.bop .bar')586def test_nested_extender_with_child_selector():587    assert_extends(588        '.baz .foo',589        'foo > bar {@extend .foo}',590        '.baz .foo, .baz foo > bar')591def test_nested_extender_finds_common_selectors_around_child_selector():592    assert_extends(593        'a > b c .c1',594        'a c .c2 {@extend .c1}',595        'a > b c .c1, a > b c .c2')596    assert_extends(597        'a > b c .c1',598        'b c .c2 {@extend .c1}',599        'a > b c .c1, a > b c .c2')600def test_nested_extender_doesnt_find_common_selectors_around_adjacent_sibling_selector():601    assert_extends(602        'a + b c .c1',603        'a c .c2 {@extend .c1}',604        'a + b c .c1, a + b a c .c2, a a + b c .c2')605    assert_extends(606        'a + b c .c1',607        'a b .c2 {@extend .c1}',608        'a + b c .c1, a a + b c .c2')609    assert_extends(610        'a + b c .c1',611        'b c .c2 {@extend .c1}',612        'a + b c .c1, a + b c .c2')613def test_nested_extender_doesnt_find_common_selectors_around_sibling_selector():614    assert_extends(615        'a ~ b c .c1',616        'a c .c2 {@extend .c1}',617        'a ~ b c .c1, a ~ b a c .c2, a a ~ b c .c2')618    assert_extends(619        'a ~ b c .c1',620        'a b .c2 {@extend .c1}',621        'a ~ b c .c1, a a ~ b c .c2')622    assert_extends(623        'a ~ b c .c1',624        'b c .c2 {@extend .c1}',625        'a ~ b c .c1, a ~ b c .c2')626def test_nested_extender_doesnt_find_common_selectors_around_reference_selector():627    assert_extends(628        'a /for/ b c .c1',629        'a c .c2 {@extend .c1}',630        'a /for/ b c .c1, a /for/ b a c .c2, a a /for/ b c .c2')631    assert_extends(632        'a /for/ b c .c1',633        'a b .c2 {@extend .c1}',634        'a /for/ b c .c1, a a /for/ b c .c2')635    assert_extends(636        'a /for/ b c .c1',637        'b c .c2 {@extend .c1}',638        'a /for/ b c .c1, a /for/ b c .c2')639def test_nested_extender_with_early_child_selectors_doesnt_subseq_them():640    assert_extends('.bip > .bap .foo', '.grip > .bap .bar {@extend .foo}',641      '.bip > .bap .foo, .bip > .bap .grip > .bap .bar, .grip > .bap .bip > .bap .bar')642    assert_extends('.bap > .bip .foo', '.bap > .grip .bar {@extend .foo}',643      '.bap > .bip .foo, .bap > .bip .bap > .grip .bar, .bap > .grip .bap > .bip .bar')644def test_nested_extender_with_child_selector_unifies():645    assert_extends(646        '.baz.foo',647        'foo > bar {@extend .foo}',648        '.baz.foo, foo > bar.baz')649    assert_rendering('''\650.baz > {651  .foo {a: b}652  .bar {@extend .foo}653}654''', '''\655.baz > .foo, .baz > .bar {656  a: b; }657''')658    assert_rendering('''\659.foo {660  .bar {a: b}661  > .baz {@extend .bar}662}663''', '''\664.foo .bar, .foo > .baz {665  a: b; }666''')667def test_nested_extender_with_early_child_selectors_doesnt_subseq_them():668    assert_rendering('''\669.foo {670  .bar {a: b}671  .bip > .baz {@extend .bar}672}673''', '''\674.foo .bar, .foo .bip > .baz {675  a: b; }676''')677    assert_rendering('''\678.foo {679  .bip .bar {a: b}680  > .baz {@extend .bar}681}682''', '''\683.foo .bip .bar, .foo .bip .foo > .baz {684  a: b; }685''')686    assert_extends(687        '.foo > .bar',688        '.bip + .baz {@extend .bar}',689        '.foo > .bar, .foo > .bip + .baz')690    assert_extends(691        '.foo + .bar',692        '.bip > .baz {@extend .bar}',693        '.foo + .bar, .bip > .foo + .baz')694    assert_extends(695        '.foo > .bar',696        '.bip > .baz {@extend .bar}',697        '.foo > .bar, .bip.foo > .baz')698def test_nested_extender_with_trailing_child_selector():699    with pytest.raises(SyntaxError):700        # "bar > can't extend: invalid selector"701        render("bar > {@extend .baz}")702def test_nested_extender_with_sibling_selector():703    assert_extends(704        '.baz .foo',705        'foo + bar {@extend .foo}',706        '.baz .foo, .baz foo + bar')707def test_nested_extender_with_hacky_selector():708    assert_extends('.baz .foo', 'foo + > > + bar {@extend .foo}',709      '.baz .foo, .baz foo + > > + bar, foo .baz + > > + bar')710    assert_extends(711        '.baz .foo',712        '> > bar {@extend .foo}',713        '.baz .foo, > > .baz bar')714def test_nested_extender_merges_with_same_selector():715    assert_rendering('''\716.foo {717  .bar {a: b}718  .baz {@extend .bar} }719''', '''\720.foo .bar, .foo .baz {721  a: b; }722''')723def test_nested_extender_with_child_selector_merges_with_same_selector():724    assert_extends('.foo > .bar .baz', '.foo > .bar .bang {@extend .baz}',725      '.foo > .bar .baz, .foo > .bar .bang')726  # Combinator Unification727def test_combinator_unification_for_hacky_combinators():728    assert_extends(729        '.a > + x',730        '.b y {@extend x}',731        '.a > + x, .a .b > + y, .b .a > + y')732    assert_extends(733        '.a x',734        '.b > + y {@extend x}',735        '.a x, .a .b > + y, .b .a > + y')736    assert_extends(737        '.a > + x',738        '.b > + y {@extend x}',739        '.a > + x, .a .b > + y, .b .a > + y')740    assert_extends(741        '.a ~ > + x',742        '.b > + y {@extend x}',743        '.a ~ > + x, .a .b ~ > + y, .b .a ~ > + y')744    assert_extends(745        '.a + > x',746        '.b > + y {@extend x}',747        '.a + > x')748    assert_extends(749        '.a + > x',750        '.b > + y {@extend x}',751        '.a + > x')752    assert_extends(753        '.a ~ > + .b > x',754        '.c > + .d > y {@extend x}',755        '.a ~ > + .b > x, .a .c ~ > + .d.b > y, .c .a ~ > + .d.b > y')756def test_combinator_unification_double_tilde():757    assert_extends(758        '.a.b ~ x',759        '.a ~ y {@extend x}',760        '.a.b ~ x, .a.b ~ y')761    assert_extends(762        '.a ~ x',763        '.a.b ~ y {@extend x}',764        '.a ~ x, .a.b ~ y')765    assert_extends(766        '.a ~ x',767        '.b ~ y {@extend x}',768        '.a ~ x, .a ~ .b ~ y, .b ~ .a ~ y, .b.a ~ y')769    assert_extends(770        'a.a ~ x',771        'b.b ~ y {@extend x}',772        'a.a ~ x, a.a ~ b.b ~ y, b.b ~ a.a ~ y')773def test_combinator_unification_tilde_plus():774    assert_extends(775        '.a.b + x',776        '.a ~ y {@extend x}',777        '.a.b + x, .a.b + y')778    assert_extends(779        '.a + x',780        '.a.b ~ y {@extend x}',781        '.a + x, .a.b ~ .a + y, .a.b + y')782    assert_extends(783        '.a + x',784        '.b ~ y {@extend x}',785        '.a + x, .b ~ .a + y, .b.a + y')786    assert_extends(787        'a.a + x',788        'b.b ~ y {@extend x}',789        'a.a + x, b.b ~ a.a + y')790    assert_extends(791        '.a.b ~ x',792        '.a + y {@extend x}',793        '.a.b ~ x, .a.b ~ .a + y, .a.b + y')794    assert_extends(795        '.a ~ x',796        '.a.b + y {@extend x}',797        '.a ~ x, .a.b + y')798    assert_extends(799        '.a ~ x',800        '.b + y {@extend x}',801        '.a ~ x, .a ~ .b + y, .a.b + y')802    assert_extends(803        'a.a ~ x',804        'b.b + y {@extend x}',805        'a.a ~ x, a.a ~ b.b + y')806def test_combinator_unification_angle_sibling():807    assert_extends(808        '.a > x',809        '.b ~ y {@extend x}',810        '.a > x, .a > .b ~ y')811    assert_extends(812        '.a > x',813        '.b + y {@extend x}',814        '.a > x, .a > .b + y')815    assert_extends(816        '.a ~ x',817        '.b > y {@extend x}',818        '.a ~ x, .b > .a ~ y')819    assert_extends(820        '.a + x',821        '.b > y {@extend x}',822        '.a + x, .b > .a + y')823def test_combinator_unification_double_angle():824    assert_extends(825        '.a.b > x',826        '.b > y {@extend x}',827        '.a.b > x, .b.a > y')828    assert_extends(829        '.a > x',830        '.a.b > y {@extend x}',831        '.a > x, .a.b > y')832    assert_extends(833        '.a > x',834        '.b > y {@extend x}',835        '.a > x, .b.a > y')836    assert_extends(837        'a.a > x',838        'b.b > y {@extend x}',839        'a.a > x')840def test_combinator_unification_double_plus():841    assert_extends(842        '.a.b + x',843        '.b + y {@extend x}',844        '.a.b + x, .b.a + y')845    assert_extends(846        '.a + x',847        '.a.b + y {@extend x}',848        '.a + x, .a.b + y')849    assert_extends(850        '.a + x',851        '.b + y {@extend x}',852        '.a + x, .b.a + y')853    assert_extends(854        'a.a + x',855        'b.b + y {@extend x}',856        'a.a + x')857def test_combinator_unification_angle_space():858    assert_extends(859        '.a.b > x',860        '.a y {@extend x}',861        '.a.b > x, .a.b > y')862    assert_extends(863        '.a > x',864        '.a.b y {@extend x}',865        '.a > x, .a.b .a > y')866    assert_extends(867        '.a > x',868        '.b y {@extend x}',869        '.a > x, .b .a > y')870    assert_extends(871        '.a.b x',872        '.a > y {@extend x}',873        '.a.b x, .a.b .a > y')874    assert_extends(875        '.a x',876        '.a.b > y {@extend x}',877        '.a x, .a.b > y')878    assert_extends(879        '.a x',880        '.b > y {@extend x}',881        '.a x, .a .b > y')882def test_combinator_unification_plus_space():883    assert_extends(884        '.a.b + x',885        '.a y {@extend x}',886        '.a.b + x, .a .a.b + y')887    assert_extends(888        '.a + x',889        '.a.b y {@extend x}',890        '.a + x, .a.b .a + y')891    assert_extends(892        '.a + x',893        '.b y {@extend x}',894        '.a + x, .b .a + y')895    assert_extends(896        '.a.b x',897        '.a + y {@extend x}',898        '.a.b x, .a.b .a + y')899    assert_extends(900        '.a x',901        '.a.b + y {@extend x}',902        '.a x, .a .a.b + y')903    assert_extends(904        '.a x',905        '.b + y {@extend x}',906        '.a x, .a .b + y')907def test_combinator_unification_nested():908    assert_extends(909        '.a > .b + x',910        '.c > .d + y {@extend x}',911        '.a > .b + x, .c.a > .d.b + y')912    assert_extends(913        '.a > .b + x',914        '.c > y {@extend x}',915        '.a > .b + x, .c.a > .b + y')916def test_combinator_unification_with_newlines():917    assert_rendering('''\918.a >919.b920+ x {a: b}921.c922> .d +923y {@extend x}924''', '''\925.a >926.b927+ x, .c.a > .d.b + y {928  a: b; }929''')930  # Loops931def test_extend_self_loop():932    assert_rendering('''\933.foo {a: b; @extend .foo}934''', '''\935.foo {936  a: b; }937''')938def test_basic_extend_loop():939    assert_rendering('''\940.foo {a: b; @extend .bar}941.bar {c: d; @extend .foo}942''', '''\943.bar, .foo {944  a: b; }945.foo, .bar {946  c: d; }947''')948def test_three_level_extend_loop():949    assert_rendering('''\950.foo {a: b; @extend .bar}951.bar {c: d; @extend .baz}952.baz {e: f; @extend .foo}953''', '''\954.baz, .bar, .foo {955  a: b; }956.foo, .baz, .bar {957  c: d; }958.bar, .foo, .baz {959  e: f; }960''')961def test_nested_extend_loop():962    assert_rendering('''\963.bar {964  a: b;965  .foo {c: d; @extend .bar}966}967''', '''\968.bar, .bar .foo {969  a: b; }970  .bar .foo {971    c: d; }972''')973def test_multiple_extender_merges_with_superset_selector():974    assert_rendering('''\975.foo {@extend .bar; @extend .baz}976a.bar.baz {a: b}977''', '''\978a.bar.baz, a.foo {979  a: b; }980''')981def test_control_flow_if():982    assert_rendering('''\983.true  { color: green; }984.false { color: red;   }985.also-true {986  @if true { @extend .true;  }987  @else    { @extend .false; }988}989.also-false {990  @if false { @extend .true;  }991  @else     { @extend .false; }992}993''', '''\994.true, .also-true {995  color: green; }996.false, .also-false {997  color: red; }998''')999def test_control_flow_for():1000    assert_rendering('''\1001.base-0  { color: green; }1002.base-1  { display: block; }1003.base-2  { border: 1px solid blue; }1004.added {1005  @for $i from 0 to 3 {1006    @extend .base-\#{$i};1007  }1008}1009''', '''\1010.base-0, .added {1011  color: green; }1012.base-1, .added {1013  display: block; }1014.base-2, .added {1015  border: 1px solid blue; }1016''')1017def test_control_flow_while():1018    assert_rendering('''\1019.base-0  { color: green; }1020.base-1  { display: block; }1021.base-2  { border: 1px solid blue; }1022.added {1023  $i : 0;1024  @while $i < 3 {1025    @extend .base-\#{$i};1026    $i : $i + 1;1027  }1028}1029''', '''\1030.base-0, .added {1031  color: green; }1032.base-1, .added {1033  display: block; }1034.base-2, .added {1035  border: 1px solid blue; }1036''')1037def test_basic_placeholder_selector():1038    assert_extends(1039        '%foo',1040        '.bar {@extend %foo}',1041        '.bar')1042def test_unused_placeholder_selector():1043    assert_rendering('''\1044%foo {color: blue}1045%bar {color: red}1046.baz {@extend %foo}1047''', '''\1048.baz {1049  color: blue; }1050''')1051def test_placeholder_descendant_selector():1052    assert_extends(1053        '#context %foo a',1054        '.bar {@extend %foo}',1055        '#context .bar a')1056def test_semi_placeholder_selector():1057    assert_rendering('''\1058#context %foo, .bar .baz {color: blue}1059''', '''\1060.bar .baz {1061  color: blue; }1062''')1063def test_placeholder_selector_with_multiple_extenders():1064    assert_rendering('''\1065%foo {color: blue}1066.bar {@extend %foo}1067.baz {@extend %foo}1068''', '''\1069.bar, .baz {1070  color: blue; }1071''')1072def test_placeholder_selector_as_modifier():1073    # XXX assert_extend_doesnt_match('div', '%foo', :failed_to_unify, 3) do1074    assert_rendering('''\1075a%foo.baz {color: blue}1076.bar {@extend %foo}1077div {@extend %foo}1078''', '''\1079a.baz.bar {1080  color: blue; }1081''')1082def test_placeholder_interpolation():1083    assert_rendering('''\1084$foo: foo;1085%\#{$foo} {color: blue}1086.bar {@extend %foo}1087''', '''\1088.bar {1089  color: blue; }1090''')1091def test_media_in_placeholder_selector():1092    assert_rendering('''\1093%foo {bar {@media screen {a: b}}}1094.baz {c: d}1095''', '''\1096.baz {1097  c: d; }1098''')1099"""1100def test_extend_out_of_media():1101    assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}1102DEPRECATION WARNING on line 3 of test_extend_out_of_media_inline.scss:1103  @extending an outer selector from within @media is deprecated.1104  You may only @extend selectors within the same directive.1105  This will be an error in Sass 3.3.1106  It can only work once @extend is supported natively in the browser.1107WARN1108.foo {1109  a: b; }1110CSS1111.foo {a: b}1112@media screen {1113  .bar {@extend .foo}1114}1115SCSS1116def test_extend_out_of_unknown_directive():1117    assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}1118DEPRECATION WARNING on line 3 of test_extend_out_of_unknown_directive_inline.scss:1119  @extending an outer selector from within @flooblehoof is deprecated.1120  You may only @extend selectors within the same directive.1121  This will be an error in Sass 3.3.1122  It can only work once @extend is supported natively in the browser.1123WARN1124.foo {1125  a: b; }1126@flooblehoof {}1127CSS1128.foo {a: b}1129@flooblehoof {1130  .bar {@extend .foo}1131}1132SCSS1133def test_extend_out_of_nested_directives():1134    assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}1135DEPRECATION WARNING on line 4 of test_extend_out_of_nested_directives_inline.scss:1136  @extending an outer selector from within @flooblehoof is deprecated.1137  You may only @extend selectors within the same directive.1138  This will be an error in Sass 3.3.1139  It can only work once @extend is supported natively in the browser.1140WARN1141@media screen {1142  .foo {1143    a: b; }1144  @flooblehoof {} }1145CSS1146@media screen {1147  .foo {a: b}1148  @flooblehoof {1149    .bar {@extend .foo}1150  }1151}1152SCSS1153"""1154def test_extend_within_media():1155    assert_rendering('''\1156@media screen {1157  .foo {a: b}1158  .bar {@extend .foo}1159}1160''', '''\1161@media screen {1162  .foo, .bar {1163    a: b; } }1164''')1165def test_extend_within_unknown_directive():1166    assert_rendering('''\1167@flooblehoof {1168  .foo {a: b}1169  .bar {@extend .foo}1170}1171''', '''\1172@flooblehoof {1173  .foo, .bar {1174    a: b; } }1175''')1176def test_extend_within_nested_directives():1177    assert_rendering('''\1178@media screen {1179  @flooblehoof {1180    .foo {a: b}1181    .bar {@extend .foo}1182  }1183}1184''', '''\1185@media screen {1186  @flooblehoof {1187    .foo, .bar {1188      a: b; } } }1189''')1190def test_extend_within_disparate_media():1191    assert_rendering('''\1192@media screen {.foo {a: b}}1193@media screen {.bar {@extend .foo}}1194''', '''\1195@media screen {1196  .foo, .bar {1197    a: b; } }1198''')1199def test_extend_within_disparate_unknown_directive():1200    assert_rendering('''\1201@flooblehoof {.foo {a: b}}1202@flooblehoof {.bar {@extend .foo}}1203''', '''\1204@flooblehoof {1205  .foo, .bar {1206    a: b; } }1207@flooblehoof {}1208''')1209def test_extend_within_disparate_nested_directives():1210    assert_rendering('''\1211@media screen {@flooblehoof {.foo {a: b}}}1212@media screen {@flooblehoof {.bar {@extend .foo}}}1213''', '''\1214@media screen {1215  @flooblehoof {1216    .foo, .bar {1217      a: b; } } }1218@media screen {1219  @flooblehoof {} }1220''')1221"""1222def test_extend_within_and_without_media():1223    assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}1224DEPRECATION WARNING on line 4 of test_extend_within_and_without_media_inline.scss:1225  @extending an outer selector from within @media is deprecated.1226  You may only @extend selectors within the same directive.1227  This will be an error in Sass 3.3.1228  It can only work once @extend is supported natively in the browser.1229WARN1230.foo {1231  a: b; }1232@media screen {1233  .foo, .bar {1234    c: d; } }1235CSS1236.foo {a: b}1237@media screen {1238  .foo {c: d}1239  .bar {@extend .foo}1240}1241SCSS1242def test_extend_within_and_without_unknown_directive():1243    assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}1244DEPRECATION WARNING on line 4 of test_extend_within_and_without_unknown_directive_inline.scss:1245  @extending an outer selector from within @flooblehoof is deprecated.1246  You may only @extend selectors within the same directive.1247  This will be an error in Sass 3.3.1248  It can only work once @extend is supported natively in the browser.1249WARN1250.foo {1251  a: b; }1252@flooblehoof {1253  .foo, .bar {1254    c: d; } }1255CSS1256.foo {a: b}1257@flooblehoof {1258  .foo {c: d}1259  .bar {@extend .foo}1260}1261SCSS1262def test_extend_within_and_without_nested_directives():1263    assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}1264DEPRECATION WARNING on line 5 of test_extend_within_and_without_nested_directives_inline.scss:1265  @extending an outer selector from within @flooblehoof is deprecated.1266  You may only @extend selectors within the same directive.1267  This will be an error in Sass 3.3.1268  It can only work once @extend is supported natively in the browser.1269WARN1270@media screen {1271  .foo {1272    a: b; }1273  @flooblehoof {1274    .foo, .bar {1275      c: d; } } }1276CSS1277@media screen {1278  .foo {a: b}1279  @flooblehoof {1280    .foo {c: d}1281    .bar {@extend .foo}1282  }1283}1284SCSS1285"""1286def test_extend_with_subject_transfers_subject_to_extender():1287    assert_rendering('''\1288foo bar! baz {a: b}1289.bip .bap {@extend bar}1290''', '''\1291foo bar! baz, foo .bip .bap! baz, .bip foo .bap! baz {1292  a: b; }1293''')1294    assert_rendering('''\1295foo.x bar.y! baz.z {a: b}1296.bip .bap {@extend .y}1297''', '''\1298foo.x bar.y! baz.z, foo.x .bip bar.bap! baz.z, .bip foo.x bar.bap! baz.z {1299  a: b; }1300''')1301def test_extend_with_subject_retains_subject_on_target():1302    assert_rendering('''\1303.foo! .bar {a: b}1304.bip .bap {@extend .bar}1305''', '''\1306.foo! .bar, .foo! .bip .bap, .bip .foo! .bap {1307  a: b; }1308''')1309def test_extend_with_subject_transfers_subject_to_target():1310    assert_rendering('''\1311a.foo .bar {a: b}1312.bip .bap! {@extend .foo}1313''', '''\1314a.foo .bar, .bip a.bap! .bar {1315  a: b; }1316''')1317def test_extend_with_subject_retains_subject_on_extender():1318    assert_rendering('''\1319.foo .bar {a: b}1320.bip! .bap {@extend .bar}1321''', '''\1322.foo .bar, .foo .bip! .bap, .bip! .foo .bap {1323  a: b; }1324''')1325def test_extend_with_subject_fails_with_conflicting_subject():1326    assert_rendering('''\1327x! .bar {a: b}1328y! .bap {@extend .bar}1329''', '''\1330x! .bar {1331  a: b; }1332''')1333"""1334def test_extend_warns_when_extendee_doesnt_exist():1335    assert_warning(<<WARN) {assert_equal("", render(<<SCSS))}1336WARNING on line 1 of test_extend_warns_when_extendee_doesnt_exist_inline.scss: ".foo" failed to @extend ".bar".1337  The selector ".bar" was not found.1338  This will be an error in future releases of Sass.1339  Use "@extend .bar !optional" if the extend should be able to fail.1340WARN1341.foo {@extend .bar}1342SCSS1343def test_extend_warns_when_extension_fails():1344    assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SCSS))}1345WARNING on line 2 of test_extend_warns_when_extension_fails_inline.scss: "b.foo" failed to @extend ".bar".1346  No selectors matching ".bar" could be unified with "b.foo".1347  This will be an error in future releases of Sass.1348  Use "@extend .bar !optional" if the extend should be able to fail.1349WARN1350a.bar {1351  a: b; }1352CSS1353a.bar {a: b}1354b.foo {@extend .bar}1355SCSS1356def test_extend_does_not_warn_when_one_extension_fails_but_others_dont():1357    assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}1358a.bar {1359  a: b; }1360.bar, b.foo {1361  c: d; }1362CSS1363a.bar {a: b}1364.bar {c: d}1365b.foo {@extend .bar}1366SCSS1367def test_extend_does_not_warn_when_one_extension_fails_but_others_dont():1368    assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}1369a.bar {1370  a: b; }1371.bar, b.foo {1372  c: d; }1373CSS1374a.bar {a: b}1375.bar {c: d}1376b.foo {@extend .bar}1377SCSS1378def test_optional_extend_does_not_warn_when_extendee_doesnt_exist():1379    assert_no_warning {assert_equal("", render(<<SCSS))}1380.foo {@extend .bar !optional}1381SCSS1382def test_optional_extend_does_not_warn_when_extension_fails():1383    assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}1384a.bar {1385  a: b; }1386CSS1387a.bar {a: b}1388b.foo {@extend .bar !optional}1389SCSS1390"""1391### Regression Tests1392def test_nested_extend_specificity():1393    assert_rendering('''\1394%foo {a: b}1395a {1396  :b {@extend %foo}1397  :b:c {@extend %foo}1398}1399''', '''\1400a :b, a :b:c {1401  a: b; }1402''')1403def test_nested_double_extend_optimization():1404    assert_rendering('''\1405%foo %bar {1406  a: b;1407}1408.parent1 {1409  @extend %foo;1410  .child {1411    @extend %bar;1412  }1413}1414.parent2 {1415  @extend %foo;1416}1417''', '''\1418.parent1 .child {1419  a: b; }1420''')1421def test_extend_in_double_nested_media_query():1422    assert_rendering('''\1423@media all {1424  @media (orientation: landscape) {1425    %foo {color: blue}1426    .bar {@extend %foo}1427  }1428}1429''', '''\1430@media all and (orientation: landscape) {1431  .bar {1432    color: blue; } }1433''')1434"""1435def test_partially_failed_extend():1436    assert_no_warning {assert_equal(<<CSS, render(<<SCSS))}1437.rc, test {1438  color: white; }1439.prices span.pill span.rc {1440  color: red; }1441CSS1442test { @extend .rc; }1443.rc {color: white;}1444.prices span.pill span.rc {color: red;}1445SCSS1446"""1447def test_newline_near_combinator():1448    assert_rendering('''\1449.a +1450.b x {a: b}1451.c y {@extend x}1452''', '''\1453.a +1454.b x, .a +1455.b .c y, .c .a +1456.b y {1457  a: b; }1458''')1459def test_duplicated_selector_with_newlines():1460    assert_rendering('''\1461.example-1-1,1462.example-1-2,1463.example-1-3 {1464  a: b;1465}1466.my-page-1 .my-module-1-1 {@extend .example-1-2}1467''', '''\1468.example-1-1,1469.example-1-2,1470.my-page-1 .my-module-1-1,1471.example-1-3 {1472  a: b; }1473''')1474def test_nested_selector_with_child_selector_hack_extendee():1475    assert_extends(1476        '> .foo',1477        'foo bar {@extend .foo}',1478        '> .foo, > foo bar')1479def test_nested_selector_with_child_selector_hack_extender():1480    assert_extends(1481        '.foo .bar',1482        '> foo bar {@extend .bar}',1483        '.foo .bar, > .foo foo bar, > foo .foo bar')1484def test_nested_selector_with_child_selector_hack_extender_and_extendee():1485    assert_extends(1486        '> .foo',1487        '> foo bar {@extend .foo}',1488        '> .foo, > foo bar')1489def test_nested_selector_with_child_selector_hack_extender_and_sibling_selector_extendee():1490    assert_extends(1491        '~ .foo',1492        '> foo bar {@extend .foo}',1493        '~ .foo')1494def test_nested_selector_with_child_selector_hack_extender_and_extendee_and_newline():1495    assert_rendering('''\1496> .foo {a: b}1497flip,1498> foo bar {@extend .foo}1499''', '''\1500> .foo, > flip,1501> foo bar {1502  a: b; }1503''')1504def test_extended_parent_and_child_redundancy_elimination():1505    assert_rendering('''\1506a {1507  b {a: b}1508  c {@extend b}1509}1510d {@extend a}1511''', '''\1512a b, d b, a c, d c {1513  a: b; }1514''')1515def test_extend_redundancy_elimination_when_it_would_reduce_specificity():1516    assert_extends(1517        'a',1518        'a.foo {@extend a}',1519        'a, a.foo')1520def test_extend_redundancy_elimination_when_it_would_preserve_specificity():1521    assert_extends(1522        '.bar a',1523        'a.foo {@extend a}',1524        '.bar a')1525def test_extend_redundancy_elimination_never_eliminates_base_selector():1526    assert_extends(1527        'a.foo',1528        '.foo {@extend a}',1529        'a.foo, .foo')1530def test_extend_cross_branch_redundancy_elimination():1531    assert_rendering('''\1532%x c %y {a: b}1533a, b {@extend %x}1534a d {@extend %y}1535''', '''\1536a c d, b c a d {1537  a: b; }1538''')1539    assert_rendering('''\1540e %z {a: b}1541%x c %y {@extend %z}1542a, b {@extend %x}1543a d {@extend %y}1544''', '''\1545e a c d, a c e d, e b c a d, b c a e d {1546  a: b; }1547''')1548"""1549def assert_extend_doesnt_match(extender, target, reason, line, syntax = :scss):1550    warn = "\"#{extender}\" failed to @extend \"#{target}\"."1551    reason =1552      if reason == :not_found1553        "The selector \"#{target}\" was not found."1554      else1555        "No selectors matching \"#{target}\" could be unified with \"#{extender}\"."1556    assert_warning(<<WARNING) {yield}1557WARNING on line #{line} of #{filename_for_test syntax}: #{warn}1558  #{reason}1559  This will be an error in future releases of Sass.1560  Use "@extend #{target} !optional" if the extend should be able to fail.1561WARNING1562"""1563def assert_unification(selector, extension, unified):1564    # Do some trickery so the first law of extend doesn't get in our way.1565    assert_extends(1566      "%-a {0}".format(selector),1567      extension + " -a {@extend %-a}",1568      ', '.join('-a ' + s for s in unified.split(', ')))1569def assert_extends(selector, extension, result):1570    assert_rendering(1571        "{0} {{a: b}}\n{1}\n".format(selector, extension),...InfoBar.py
Source:InfoBar.py  
1from Tools.Profile import profile2from Tools.BoundFunction import boundFunction3from enigma import eServiceReference4# workaround for required config entry dependencies.5import Screens.MovieSelection6from Screen import Screen7from Screens.MessageBox import MessageBox8profile("LOAD:enigma")9import enigma10profile("LOAD:InfoBarGenerics")11from Screens.InfoBarGenerics import InfoBarShowHide, \12	InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarRdsDecoder, \13	InfoBarEPG, InfoBarSeek, InfoBarInstantRecord, InfoBarRedButton, InfoBarTimerButton, InfoBarVmodeButton, \14	InfoBarAudioSelection, InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarUnhandledKey, \15	InfoBarSubserviceSelection, InfoBarShowMovies, InfoBarTimeshift,  \16	InfoBarServiceNotifications, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarBuffer, \17	InfoBarSummarySupport, InfoBarMoviePlayerSummarySupport, InfoBarTimeshiftState, InfoBarTeletextPlugin, InfoBarExtensions, \18	InfoBarSubtitleSupport, InfoBarPiP, InfoBarPlugins, InfoBarServiceErrorPopupSupport, InfoBarJobman, InfoBarPowersaver, \19	InfoBarHDMI, setResumePoint, delResumePoint20from Screens.Hotkey import InfoBarHotkey21profile("LOAD:InitBar_Components")22from Components.ActionMap import HelpableActionMap23from Components.config import config24from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase25profile("LOAD:HelpableScreen")26from Screens.HelpMenu import HelpableScreen27#DE Patch28from DE.DEManager import DEManagerOpen29from DE.DEManager import DEPluginsPanelOpen30class InfoBar(InfoBarBase, InfoBarShowHide,31	InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRdsDecoder,DEManagerOpen, DEPluginsPanelOpen, 32	InfoBarInstantRecord, InfoBarAudioSelection, InfoBarRedButton, InfoBarTimerButton, InfoBarVmodeButton,33	HelpableScreen, InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarUnhandledKey,34	InfoBarSubserviceSelection, InfoBarTimeshift, InfoBarSeek, InfoBarCueSheetSupport, InfoBarBuffer,35	InfoBarSummarySupport, InfoBarTimeshiftState, InfoBarTeletextPlugin, InfoBarExtensions,36	InfoBarPiP, InfoBarPlugins, InfoBarSubtitleSupport, InfoBarServiceErrorPopupSupport, InfoBarJobman, InfoBarPowersaver,37	InfoBarHDMI, InfoBarHotkey, Screen):38	ALLOW_SUSPEND = True39	instance = None40	def __init__(self, session):41		Screen.__init__(self, session)42		self["actions"] = HelpableActionMap(self, "InfobarActions",43			{44				"showMovies": (self.showMovies, _("Play recorded movies...")),45				"showRadio": (self.showRadio, _("Show the radio player...")),46				"showTv": (self.showTv, _("Show the tv player...")),47				"toggleTvRadio": (self.toggleTvRadio, _("Toggle the tv and the radio player...")),48			}, prio=2)49		self.radioTV = 050		self.allowPiP = True51		for x in HelpableScreen, \52				InfoBarBase, InfoBarShowHide, \53				InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRdsDecoder, DEManagerOpen, DEPluginsPanelOpen, \54				InfoBarInstantRecord, InfoBarAudioSelection, InfoBarRedButton, InfoBarTimerButton, InfoBarUnhandledKey, InfoBarVmodeButton,\55				InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarSubserviceSelection, InfoBarBuffer, \56				InfoBarTimeshift, InfoBarSeek, InfoBarCueSheetSupport, InfoBarSummarySupport, InfoBarTimeshiftState, \57				InfoBarTeletextPlugin, InfoBarExtensions, InfoBarPiP, InfoBarSubtitleSupport, InfoBarJobman, InfoBarPowersaver, \58				InfoBarPlugins, InfoBarServiceErrorPopupSupport, InfoBarHotkey:59			x.__init__(self)60		self.helpList.append((self["actions"], "InfobarActions", [("showMovies", _("Watch recordings..."))]))61		self.helpList.append((self["actions"], "InfobarActions", [("showRadio", _("Listen to the radio..."))]))62		self.__event_tracker = ServiceEventTracker(screen=self, eventmap=63			{64				enigma.iPlayableService.evUpdatedEventInfo: self.__eventInfoChanged65			})66		self.current_begin_time=067		assert InfoBar.instance is None, "class InfoBar is a singleton class and just one instance of this class is allowed!"68		InfoBar.instance = self69	def __onClose(self):70		InfoBar.instance = None71	def __eventInfoChanged(self):72		if self.execing:73			service = self.session.nav.getCurrentService()74			old_begin_time = self.current_begin_time75			info = service and service.info()76			ptr = info and info.getEvent(0)77			self.current_begin_time = ptr and ptr.getBeginTime() or 078			if config.usage.show_infobar_on_event_change.value:79				if old_begin_time and old_begin_time != self.current_begin_time:80					self.doShow()81	def __checkServiceStarted(self):82		self.__serviceStarted(True)83		self.onExecBegin.remove(self.__checkServiceStarted)84	def serviceStarted(self):  #override from InfoBarShowHide85		new = self.servicelist.newServicePlayed()86		if self.execing:87			InfoBarShowHide.serviceStarted(self)88			self.current_begin_time=089		elif not self.__checkServiceStarted in self.onShown and new:90			self.onShown.append(self.__checkServiceStarted)91	def __checkServiceStarted(self):92		self.serviceStarted()93		self.onShown.remove(self.__checkServiceStarted)94	def showTv(self):95		self.showTvChannelList(True)96	def showRadio(self):97		if config.usage.e1like_radio_mode.value:98			self.showRadioChannelList(True)99		else:100			self.rds_display.hide() # in InfoBarRdsDecoder101			from Screens.ChannelSelection import ChannelSelectionRadio102			self.session.openWithCallback(self.ChannelSelectionRadioClosed, ChannelSelectionRadio, self)103	def toggleTvRadio(self):104		if self.radioTV == 1:105			self.radioTV = 0106			self.showTv()107		else:108			self.radioTV = 1109			self.showRadio()110	def ChannelSelectionRadioClosed(self, *arg):111		self.rds_display.show()  # in InfoBarRdsDecoder112		self.servicelist.correctChannelNumber()113	def showMovies(self, defaultRef=None):114		self.lastservice = self.session.nav.getCurrentlyPlayingServiceOrGroup()115		self.session.openWithCallback(self.movieSelected, Screens.MovieSelection.MovieSelection, defaultRef or eServiceReference(config.usage.last_movie_played.value), timeshiftEnabled = self.timeshiftEnabled())116	def movieSelected(self, service):117		ref = self.lastservice118		del self.lastservice119		if service is None:120			if ref and not self.session.nav.getCurrentlyPlayingServiceOrGroup():121				self.session.nav.playService(ref)122		else:123			from Components.ParentalControl import parentalControl124			if parentalControl.isServicePlayable(service, self.openMoviePlayer):125				self.openMoviePlayer(service)126	def openMoviePlayer(self, ref):127		self.session.open(MoviePlayer, ref, slist=self.servicelist, lastservice=self.session.nav.getCurrentlyPlayingServiceOrGroup(), infobar=self)128class MoviePlayer(InfoBarBase, InfoBarShowHide, InfoBarMenu, InfoBarSeek, InfoBarShowMovies, InfoBarInstantRecord,129		InfoBarAudioSelection, HelpableScreen, InfoBarNotifications, InfoBarServiceNotifications, InfoBarPVRState,130		InfoBarCueSheetSupport, InfoBarMoviePlayerSummarySupport, InfoBarSubtitleSupport, Screen, InfoBarTeletextPlugin,131		InfoBarServiceErrorPopupSupport, InfoBarExtensions, InfoBarPlugins, InfoBarPiP, InfoBarHDMI, InfoBarHotkey):132	ENABLE_RESUME_SUPPORT = True133	ALLOW_SUSPEND = True134	def __init__(self, session, service, slist=None, lastservice=None, infobar=None):135		Screen.__init__(self, session)136		self["actions"] = HelpableActionMap(self, "MoviePlayerActions",137			{138				"leavePlayer": (self.leavePlayer, _("leave movie player...")),139				"leavePlayerOnExit": (self.leavePlayerOnExit, _("leave movie player...")),140				"channelUp": (self.channelUp, _("when PiPzap enabled zap channel up...")),141				"channelDown": (self.channelDown, _("when PiPzap enabled zap channel down...")),142			})143		self["DirectionActions"] = HelpableActionMap(self, "DirectionActions",144			{145				"left": self.left,146				"right": self.right147			}, prio = -2)148		self.allowPiP = True149		for x in HelpableScreen, InfoBarShowHide, InfoBarMenu, \150				InfoBarBase, InfoBarSeek, InfoBarShowMovies, InfoBarInstantRecord, \151				InfoBarAudioSelection, InfoBarNotifications, \152				InfoBarServiceNotifications, InfoBarPVRState, InfoBarCueSheetSupport, \153				InfoBarMoviePlayerSummarySupport, InfoBarSubtitleSupport, \154				InfoBarTeletextPlugin, InfoBarServiceErrorPopupSupport, InfoBarExtensions, \155				InfoBarPlugins, InfoBarPiP, InfoBarHotkey:156			x.__init__(self)157		self.servicelist = slist158		self.infobar = infobar159		self.lastservice = lastservice or session.nav.getCurrentlyPlayingServiceOrGroup()160		session.nav.playService(service)161		self.cur_service = service162		self.returning = False163		self.onClose.append(self.__onClose)164		config.misc.standbyCounter.addNotifier(self.standbyCountChanged, initial_call=False)165	def __onClose(self):166		config.misc.standbyCounter.removeNotifier(self.standbyCountChanged)167		from Screens.MovieSelection import playlist168		del playlist[:]169		if not config.movielist.stop_service.value:170			Screens.InfoBar.InfoBar.instance.callServiceStarted()171		self.session.nav.playService(self.lastservice)172		config.usage.last_movie_played.value = self.cur_service and self.cur_service.toString() or ""173		config.usage.last_movie_played.save()174	def standbyCountChanged(self, value):175		if config.ParentalControl.servicepinactive.value:176			from Components.ParentalControl import parentalControl177			if parentalControl.isProtected(self.cur_service):178				self.close()179	def handleLeave(self, how):180		self.is_closing = True181		if how == "ask":182			if config.usage.setup_level.index < 2: # -expert183				list = (184					(_("Yes"), "quit"),185					(_("No"), "continue")186				)187			else:188				list = (189					(_("Yes"), "quit"),190					(_("Yes, returning to movie list"), "movielist"),191					(_("Yes, and delete this movie"), "quitanddelete"),192					(_("Yes, delete this movie and return to movie list"), "deleteandmovielist"),193					(_("No"), "continue"),194					(_("No, but restart from begin"), "restart")195				)196			from Screens.ChoiceBox import ChoiceBox197			self.session.openWithCallback(self.leavePlayerConfirmed, ChoiceBox, title=_("Stop playing this movie?"), list = list)198		else:199			self.leavePlayerConfirmed([True, how])200	def leavePlayer(self):201		setResumePoint(self.session)202		self.handleLeave(config.usage.on_movie_stop.value)203	def leavePlayerOnExit(self):204		if self.shown:205			self.hide()206		elif self.session.pipshown and "popup" in config.usage.pip_hideOnExit.value:207			if config.usage.pip_hideOnExit.value == "popup":208				self.session.openWithCallback(self.hidePipOnExitCallback, MessageBox, _("Disable Picture in Picture"), simple=True)209			else:210				self.hidePipOnExitCallback(True)211		elif config.usage.leave_movieplayer_onExit.value == "movielist":212			self.leavePlayer()213		elif config.usage.leave_movieplayer_onExit.value == "popup":214			self.session.openWithCallback(self.leavePlayerOnExitCallback, MessageBox, _("Exit movie player?"), simple=True)215		elif config.usage.leave_movieplayer_onExit.value == "without popup":216			self.leavePlayerOnExitCallback(True)217	def leavePlayerOnExitCallback(self, answer):218		if answer == True:219			setResumePoint(self.session)220			self.handleLeave("quit")221	def hidePipOnExitCallback(self, answer):222		if answer == True:223			self.showPiP()224	def deleteConfirmed(self, answer):225		if answer:226			self.leavePlayerConfirmed((True, "quitanddeleteconfirmed"))227	def deleteAndMovielistConfirmed(self, answer):228		if answer:229			self.leavePlayerConfirmed((True, "deleteandmovielistconfirmed"))230	def movielistAgain(self):231		from Screens.MovieSelection import playlist232		del playlist[:]233		self.leavePlayerConfirmed((True, "movielist"))234	def leavePlayerConfirmed(self, answer):235		answer = answer and answer[1]236		if answer is None:237			return238		if answer in ("quitanddelete", "quitanddeleteconfirmed", "deleteandmovielist", "deleteandmovielistconfirmed"):239			ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()240			serviceHandler = enigma.eServiceCenter.getInstance()241			if answer in ("quitanddelete", "deleteandmovielist"):242				msg = ''243				if config.usage.movielist_trashcan.value:244					import Tools.Trashcan245					try:246						trash = Tools.Trashcan.createTrashFolder(ref.getPath())247						Screens.MovieSelection.moveServiceFiles(ref, trash)248						# Moved to trash, okay249						if answer == "quitanddelete":250							self.close()251						else:252							self.movielistAgain()253						return254					except Exception, e:255						print "[InfoBar] Failed to move to .Trash folder:", e256						msg = _("Cannot move to trash can") + "\n" + str(e) + "\n"257				info = serviceHandler.info(ref)258				name = info and info.getName(ref) or _("this recording")259				msg += _("Do you really want to delete %s?") % name260				if answer == "quitanddelete":261					self.session.openWithCallback(self.deleteConfirmed, MessageBox, msg)262				elif answer == "deleteandmovielist":263					self.session.openWithCallback(self.deleteAndMovielistConfirmed, MessageBox, msg)264				return265			elif answer in ("quitanddeleteconfirmed", "deleteandmovielistconfirmed"):266				offline = serviceHandler.offlineOperations(ref)267				if offline.deleteFromDisk(0):268					self.session.openWithCallback(self.close, MessageBox, _("You cannot delete this!"), MessageBox.TYPE_ERROR)269					if answer == "deleteandmovielistconfirmed":270						self.movielistAgain()271					return272		if answer in ("quit", "quitanddeleteconfirmed"):273			self.close()274		elif answer in ("movielist", "deleteandmovielistconfirmed"):275			ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()276			self.returning = True277			self.session.openWithCallback(self.movieSelected, Screens.MovieSelection.MovieSelection, ref)278			self.session.nav.stopService()279			if not config.movielist.stop_service.value:280				self.session.nav.playService(self.lastservice)281		elif answer == "restart":282			self.doSeek(0)283			self.setSeekState(self.SEEK_STATE_PLAY)284		elif answer in ("playlist","playlistquit","loop"):285			( next_service, item , lenght ) = self.getPlaylistServiceInfo(self.cur_service)286			if next_service is not None:287				if config.usage.next_movie_msg.value:288					self.displayPlayedName(next_service, item, lenght)289				self.session.nav.playService(next_service)290				self.cur_service = next_service291			else:292				if answer == "playlist":293					self.leavePlayerConfirmed([True,"movielist"])294				elif answer == "loop" and lenght > 0:295					self.leavePlayerConfirmed([True,"loop"])296				else:297					self.leavePlayerConfirmed([True,"quit"])298		elif answer in ("repeatcurrent"):299			if config.usage.next_movie_msg.value:300				(item, lenght) = self.getPlaylistServiceInfo(self.cur_service)301				self.displayPlayedName(self.cur_service, item, lenght)302			self.session.nav.stopService()303			self.session.nav.playService(self.cur_service)304	def doEofInternal(self, playing):305		if not self.execing:306			return307		if not playing :308			return309		ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()310		if ref:311			delResumePoint(ref)312		self.handleLeave(config.usage.on_movie_eof.value)313	def up(self):314		if self.servicelist and self.servicelist.dopipzap:315			if config.usage.oldstyle_zap_controls.value:316				self.zapDown()317			else:318				self.switchChannelUp()319		else:320			self.showMovies()321	def down(self):322		if self.servicelist and self.servicelist.dopipzap:323			if config.usage.oldstyle_zap_controls.value:324				self.zapUp()325			else:326				self.switchChannelDown()327		else:328			self.showMovies()329	def right(self):330		if self.servicelist and self.servicelist.dopipzap:331			if config.usage.oldstyle_zap_controls.value:332				self.switchChannelDown()333			else:334				self.zapDown()335		else:336			InfoBarSeek.seekFwd(self)337	def left(self):338		if self.servicelist and self.servicelist.dopipzap:339			if config.usage.oldstyle_zap_controls.value:340				self.switchChannelUp()341			else:342				self.zapUp()343		else:344			InfoBarSeek.seekBack(self)345	def channelUp(self):346		if config.usage.zap_with_ch_buttons.value and self.servicelist and self.servicelist.dopipzap:347			self.zapDown()348		else:349			return 0350	def channelDown(self):351		if config.usage.zap_with_ch_buttons.value and self.servicelist and self.servicelist.dopipzap:352			self.zapUp()353		else:354			return 0355	def switchChannelDown(self):356		if self.servicelist:357			if "keep" not in config.usage.servicelist_cursor_behavior.value:358				self.servicelist.moveDown()359			self.session.execDialog(self.servicelist)360	def switchChannelUp(self):361		if self.servicelist:362			if "keep" not in config.usage.servicelist_cursor_behavior.value:363				self.servicelist.moveUp()364			self.session.execDialog(self.servicelist)365	def zapUp(self):366		slist = self.servicelist367		if slist:368			if slist.inBouquet():369				prev = slist.getCurrentSelection()370				if prev:371					prev = prev.toString()372					while True:373						if config.usage.quickzap_bouquet_change.value:374							if slist.atBegin():375								slist.prevBouquet()376						slist.moveUp()377						cur = slist.getCurrentSelection()378						if cur:379							playable = not (cur.flags & (64|8)) and hasattr(self.session, "pip") and self.session.pip.isPlayableForPipService(cur)380							if cur.toString() == prev or playable:381								break382			else:383				slist.moveUp()384			slist.zap(enable_pipzap = True)385	def zapDown(self):386		slist = self.servicelist387		if slist:388			if slist.inBouquet():389				prev = slist.getCurrentSelection()390				if prev:391					prev = prev.toString()392					while True:393						if config.usage.quickzap_bouquet_change.value and slist.atEnd():394							slist.nextBouquet()395						else:396							slist.moveDown()397						cur = slist.getCurrentSelection()398						if cur:399							playable = not (cur.flags & (64|8)) and hasattr(self.session, "pip") and self.session.pip.isPlayableForPipService(cur)400							if cur.toString() == prev or playable:401								break402			else:403				slist.moveDown()404			slist.zap(enable_pipzap = True)405	def showPiP(self):406		slist = self.servicelist407		if self.session.pipshown:408			if slist and slist.dopipzap:409				slist.togglePipzap()410			if self.session.pipshown:411				del self.session.pip412				self.session.pipshown = False413		elif slist:414			from Screens.PictureInPicture import PictureInPicture415			self.session.pip = self.session.instantiateDialog(PictureInPicture)416			self.session.pip.show()417			if self.session.pip.playService(slist.getCurrentSelection()):418				self.session.pipshown = True419				self.session.pip.servicePath = slist.getCurrentServicePath()420			else:421				self.session.pipshown = False422				del self.session.pip423	def movePiP(self):424		if self.session.pipshown:425			InfoBarPiP.movePiP(self)426	def swapPiP(self):427		pass428	def showDefaultEPG(self):429		self.infobar and self.infobar.showMultiEPG()430	def openEventView(self):431		self.infobar and self.infobar.showDefaultEPG()432	def showEventInfoPlugins(self):433		self.infobar and self.infobar.showEventInfoPlugins()434	def showEventGuidePlugins(self):435		self.infobar and self.infobar.showEventGuidePlugins()436	def openSingleServiceEPG(self):437		self.infobar and self.infobar.openSingleServiceEPG()438	def openMultiServiceEPG(self):439		self.infobar and self.infobar.openMultiServiceEPG()440	def showMovies(self):441		ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()442		self.playingservice = ref # movie list may change the currently playing443		self.session.openWithCallback(self.movieSelected, Screens.MovieSelection.MovieSelection, ref)444	def movieSelected(self, service):445		if service is not None:446			self.cur_service = service447			self.is_closing = False448			self.session.nav.playService(service)449			self.returning = False450		elif self.returning:451			self.close()452		else:453			self.is_closing = False454			ref = self.playingservice455			del self.playingservice456			# no selection? Continue where we left off457			if ref and not self.session.nav.getCurrentlyPlayingServiceOrGroup():458				self.session.nav.playService(ref)459	def getPlaylistServiceInfo(self, service):460		from MovieSelection import playlist461		for i, item in enumerate(playlist):462			if item == service:463				if config.usage.on_movie_eof.value == "repeatcurrent":464					return (i+1, len(playlist))465				i += 1466				if i < len(playlist):467					return (playlist[i], i+1, len(playlist))468				elif config.usage.on_movie_eof.value == "loop":469					return (playlist[0], 1, len(playlist))470		return ( None, 0, 0 )471	def displayPlayedName(self, ref, index, n):472		from Tools import Notifications473		Notifications.AddPopup(text = _("%s/%s: %s") % (index, n, self.ref2HumanName(ref)), type = MessageBox.TYPE_INFO, timeout = 5)474	def ref2HumanName(self, ref):...project_id.py
Source:project_id.py  
1#!/usr/bin/python2# Copyright (C) 2012. Jurko Gospodnetic3# Distributed under the Boost Software License, Version 1.0.4# (See accompanying file LICENSE.txt or copy at5# https://www.bfgroup.xyz/b2/LICENSE.txt)6# Tests Boost Build's project-id handling.7import BoostBuild8import sys9def test_assigning_project_ids():10    t = BoostBuild.Tester(pass_toolset=False)11    t.write("jamroot.jam", """\12import assert ;13import modules ;14import notfile ;15import project ;16rule assert-project-id ( id ? : module-name ? )17{18    module-name ?= [ CALLER_MODULE ] ;19    assert.result $(id) : project.attribute $(module-name) id ;20}21# Project rule modifies the main project id.22assert-project-id ;  # Initial project id is empty23project foo  ; assert-project-id /foo ;24project      ; assert-project-id /foo ;25project foo  ; assert-project-id /foo ;26project bar  ; assert-project-id /bar ;27project /foo ; assert-project-id /foo ;28project ""   ; assert-project-id /foo ;29# Calling the use-project rule does not modify the project's main id.30use-project id1 : a ;31# We need to load the 'a' Jamfile module manually as the use-project rule will32# only schedule the load to be done after the current module load finishes.33a-module = [ project.load a ] ;34assert-project-id : $(a-module) ;35use-project id2 : a ;36assert-project-id : $(a-module) ;37modules.call-in $(a-module) : project baz ;38assert-project-id /baz : $(a-module) ;39use-project id3 : a ;40assert-project-id /baz : $(a-module) ;41# Make sure the project id still holds after all the scheduled use-project loads42# complete. We do this by scheduling the assert for the Jam action scheduling43# phase.44notfile x : @assert-a-rule ;45rule assert-a-rule ( target : : properties * )46{47    assert-project-id /baz : $(a-module) ;48}49""")50    t.write("a/jamfile.jam", """\51# Initial project id for this module is empty.52assert-project-id ;53""")54    t.run_build_system()55    t.cleanup()56def test_using_project_ids_in_target_references():57    t = BoostBuild.Tester()58    __write_appender(t, "appender.jam")59    t.write("jamroot.jam", """\60import type ;61type.register AAA : _a ;62type.register BBB : _b ;63import appender ;64appender.register aaa-to-bbb : AAA : BBB ;65use-project id1 : a ;66use-project /id2 : a ;67bbb b1 : /id1//target ;68bbb b2 : /id2//target ;69bbb b3 : /id3//target ;70bbb b4 : a//target ;71bbb b5 : /project-a1//target ;72bbb b6 : /project-a2//target ;73bbb b7 : /project-a3//target ;74use-project id3 : a ;75""")76    t.write("a/source._a", "")77    t.write("a/jamfile.jam", """\78project project-a1 ;79project /project-a2 ;80import alias ;81alias target : source._a ;82project /project-a3 ;83""")84    t.run_build_system()85    t.expect_addition("bin/b%d._b" % x for x in range(1, 8))86    t.expect_nothing_more()87    t.cleanup()88def test_repeated_ids_for_different_projects():89    t = BoostBuild.Tester()90    t.write("a/jamfile.jam", "")91    t.write("jamroot.jam", "project foo ; use-project foo : a ;")92    t.run_build_system(status=1)93    t.expect_output_lines("""\94error: Attempt to redeclare already registered project id '/foo'.95error: Original project:96error:     Name: Jamfile<*>97error:     Module: Jamfile<*>98error:     Main id: /foo99error:     File: jamroot.jam100error:     Location: .101error: New project:102error:     Module: Jamfile<*>103error:     File: a*jamfile.jam104error:     Location: a""")105    t.write("jamroot.jam", "use-project foo : a ; project foo ;")106    t.run_build_system(status=1)107    t.expect_output_lines("""\108error: Attempt to redeclare already registered project id '/foo'.109error: Original project:110error:     Name: Jamfile<*>111error:     Module: Jamfile<*>112error:     Main id: /foo113error:     File: jamroot.jam114error:     Location: .115error: New project:116error:     Module: Jamfile<*>117error:     File: a*jamfile.jam118error:     Location: a""")119    t.write("jamroot.jam", """\120import modules ;121import project ;122modules.call-in [ project.load a ] : project foo ;123project foo ;124""")125    t.run_build_system(status=1)126    t.expect_output_lines("""\127error: at jamroot.jam:4128error: Attempt to redeclare already registered project id '/foo'.129error: Original project:130error:     Name: Jamfile<*>131error:     Module: Jamfile<*>132error:     Main id: /foo133error:     File: a*jamfile.jam134error:     Location: a135error: New project:136error:     Module: Jamfile<*>137error:     File: jamroot.jam138error:     Location: .""")139    t.cleanup()140def test_repeated_ids_for_same_project():141    t = BoostBuild.Tester()142    t.write("jamroot.jam", "project foo ; project foo ;")143    t.run_build_system()144    t.write("jamroot.jam", "project foo ; use-project foo : . ;")145    t.run_build_system()146    t.write("jamroot.jam", "project foo ; use-project foo : ./. ;")147    t.run_build_system()148    t.write("jamroot.jam", """\149project foo ;150use-project foo : . ;151use-project foo : ./aaa/.. ;152use-project foo : ./. ;153""")154    t.run_build_system()155    # On Windows we have a case-insensitive file system and we can use156    # backslashes as path separators.157    # FIXME: Make a similar test pass on Cygwin.158    if sys.platform in ['win32']:159        t.write("a/fOo bAr/b/jamfile.jam", "")160        t.write("jamroot.jam", r"""161use-project bar : "a/foo bar/b" ;162use-project bar : "a/foO Bar/b" ;163use-project bar : "a/foo BAR/b/" ;164use-project bar : "a\\.\\FOO bar\\b\\" ;165""")166        t.run_build_system()167        t.rm("a")168    t.write("bar/jamfile.jam", "")169    t.write("jamroot.jam", """\170use-project bar : bar ;171use-project bar : bar/ ;172use-project bar : bar// ;173use-project bar : bar/// ;174use-project bar : bar//// ;175use-project bar : bar/. ;176use-project bar : bar/./ ;177use-project bar : bar/////./ ;178use-project bar : bar/../bar/xxx/.. ;179use-project bar : bar/..///bar/xxx///////.. ;180use-project bar : bar/./../bar/xxx/.. ;181use-project bar : bar/.////../bar/xxx/.. ;182use-project bar : bar/././../bar/xxx/.. ;183use-project bar : bar/././//////////../bar/xxx/.. ;184use-project bar : bar/.///.////../bar/xxx/.. ;185use-project bar : bar/./././xxx/.. ;186use-project bar : bar/xxx////.. ;187use-project bar : bar/xxx/.. ;188use-project bar : bar///////xxx/.. ;189""")190    t.run_build_system()191    t.rm("bar")192    # On Windows we have a case-insensitive file system and we can use193    # backslashes as path separators.194    # FIXME: Make a similar test pass on Cygwin.195    if sys.platform in ['win32']:196        t.write("baR/jamfile.jam", "")197        t.write("jamroot.jam", r"""198use-project bar : bar ;199use-project bar : BAR ;200use-project bar : bAr ;201use-project bar : bAr/ ;202use-project bar : bAr\\ ;203use-project bar : bAr\\\\ ;204use-project bar : bAr\\\\///// ;205use-project bar : bAr/. ;206use-project bar : bAr/./././ ;207use-project bar : bAr\\.\\.\\.\\ ;208use-project bar : bAr\\./\\/.\\.\\ ;209use-project bar : bAr/.\\././ ;210use-project bar : Bar ;211use-project bar : BaR ;212use-project bar : BaR/./../bAr/xxx/.. ;213use-project bar : BaR/./..\\bAr\\xxx/.. ;214use-project bar : BaR/xxx/.. ;215use-project bar : BaR///\\\\\\//xxx/.. ;216use-project bar : Bar\\xxx/.. ;217use-project bar : BAR/xXx/.. ;218use-project bar : BAR/xXx\\\\/\\/\\//\\.. ;219""")220        t.run_build_system()221        t.rm("baR")222    t.cleanup()223def test_unresolved_project_references():224    t = BoostBuild.Tester()225    __write_appender(t, "appender.jam")226    t.write("a/source._a", "")227    t.write("a/jamfile.jam", "import alias ; alias target : source._a ;")228    t.write("jamroot.jam", """\229import type ;230type.register AAA : _a ;231type.register BBB : _b ;232import appender ;233appender.register aaa-to-bbb : AAA : BBB ;234use-project foo : a ;235bbb b1 : a//target ;236bbb b2 : /foo//target ;237bbb b-invalid : invalid//target ;238bbb b-root-invalid : /invalid//target ;239bbb b-missing-root : foo//target ;240bbb b-invalid-target : /foo//invalid ;241""")242    t.run_build_system(["b1", "b2"])243    t.expect_addition("bin/b%d._b" % x for x in range(1, 3))244    t.expect_nothing_more()245    t.run_build_system(["b-invalid"], status=1)246    t.expect_output_lines("""\247error: Unable to find file or target named248error:     'invalid//target'249error: referred to from project at250error:     '.'251error: could not resolve project reference 'invalid'""")252    t.run_build_system(["b-root-invalid"], status=1)253    t.expect_output_lines("""\254error: Unable to find file or target named255error:     '/invalid//target'256error: referred to from project at257error:     '.'258error: could not resolve project reference '/invalid'""")259    t.run_build_system(["b-missing-root"], status=1)260    t.expect_output_lines("""\261error: Unable to find file or target named262error:     'foo//target'263error: referred to from project at264error:     '.'265error: could not resolve project reference 'foo' - possibly missing a """266    "leading slash ('/') character.")267    t.run_build_system(["b-invalid-target"], status=1)268    t.expect_output_lines("""\269error: Unable to find file or target named270error:     '/foo//invalid'271error: referred to from project at272error:     '.'""")273    t.expect_output_lines("*could not resolve project reference*", False)274    t.cleanup()275def __write_appender(t, name):276    t.write(name,277r"""# Copyright 2012 Jurko Gospodnetic278# Distributed under the Boost Software License, Version 1.0.279# (See accompanying file LICENSE.txt or copy at280# https://www.bfgroup.xyz/b2/LICENSE.txt)281#   Support for registering test generators that construct their targets by282# simply appending their given input data, e.g. list of sources & targets.283import "class" : new ;284import generators ;285import modules ;286import sequence ;287rule register ( id composing ? : source-types + : target-types + )288{289    local caller-module = [ CALLER_MODULE ] ;290    id = $(caller-module).$(id) ;291    local g = [ new generator $(id) $(composing) : $(source-types) :292        $(target-types) ] ;293    $(g).set-rule-name $(__name__).appender ;294    generators.register $(g) ;295    return $(id) ;296}297if [ modules.peek : NT ]298{299    X = ")" ;300    ECHO_CMD = (echo. ;301}302else303{304    X = \" ;305    ECHO_CMD = "echo $(X)" ;306}307local appender-runs ;308# We set up separate actions for building each target in order to avoid having309# to iterate over them in action (i.e. shell) code. We have to be extra careful310# though to achieve the exact same effect as if doing all the work in just one311# action. Otherwise Boost Jam might, under some circumstances, run only some of312# our actions. To achieve this we register a series of actions for all the313# targets (since they all have the same target list - either all or none of them314# get run independent of which target actually needs to get built), each315# building only a single target. Since all our actions use the same targets, we316# can not use 'on-target' parameters to pass data to a specific action so we317# pass them using the second 'sources' parameter which our actions then know how318# to interpret correctly. This works well since Boost Jam does not automatically319# add dependency relations between specified action targets & sources and so the320# second argument, even though most often used to pass in a list of sources, can321# actually be used for passing in any type of information.322rule appender ( targets + : sources + : properties * )323{324    appender-runs = [ CALC $(appender-runs:E=0) + 1 ] ;325    local target-index = 0 ;326    local target-count = [ sequence.length $(targets) ] ;327    local original-targets ;328    for t in $(targets)329    {330        target-index = [ CALC $(target-index) + 1 ] ;331        local appender-run = $(appender-runs) ;332        if $(targets[2])-defined333        {334            appender-run += [$(target-index)/$(target-count)] ;335        }336        append $(targets) : $(appender-run:J=" ") $(t) $(sources) ;337    }338}339actions append340{341    $(ECHO_CMD)-------------------------------------------------$(X)342    $(ECHO_CMD)Appender run: $(>[1])$(X)343    $(ECHO_CMD)Appender run: $(>[1])$(X)>> "$(>[2])"344    $(ECHO_CMD)Target group: $(<:J=' ')$(X)345    $(ECHO_CMD)Target group: $(<:J=' ')$(X)>> "$(>[2])"346    $(ECHO_CMD)      Target: '$(>[2])'$(X)347    $(ECHO_CMD)      Target: '$(>[2])'$(X)>> "$(>[2])"348    $(ECHO_CMD)     Sources: '$(>[3-]:J=' ')'$(X)349    $(ECHO_CMD)     Sources: '$(>[3-]:J=' ')'$(X)>> "$(>[2])"350    $(ECHO_CMD)=================================================$(X)351    $(ECHO_CMD)-------------------------------------------------$(X)>> "$(>[2])"352}353""")354test_assigning_project_ids()355test_using_project_ids_in_target_references()356test_repeated_ids_for_same_project()357test_repeated_ids_for_different_projects()...test_pure_resource_path.py
Source:test_pure_resource_path.py  
1from sublime_lib import ResourcePath2from unittest import TestCase3class TestPureResourcePath(TestCase):4    def test_empty_error(self):5        with self.assertRaises(ValueError):6            ResourcePath("")7    def test_eq(self):8        self.assertEqual(9            ResourcePath("Packages/Foo/bar.py"),10            ResourcePath("Packages/Foo/bar.py")11        )12    def test_ordering_error(self):13        with self.assertRaises(TypeError):14            ResourcePath("Packages") < 'Packages'15    def test_hash(self):16        self.assertIsInstance(17            hash(ResourcePath("Packages/Foo/bar.py")),18            int19        )20    def test_eq_false(self):21        self.assertNotEqual(22            ResourcePath("Packages/Foo/bar.py"),23            "Packages/Foo/bar.py"24        )25    def test_eq_slash(self):26        self.assertEqual(27            ResourcePath("Packages/Foo/bar.py"),28            ResourcePath("Packages/Foo/bar.py///")29        )30    def test_str(self):31        self.assertEqual(32            str(ResourcePath("Packages/Foo/bar.py")),33            "Packages/Foo/bar.py"34        )35    def test_repr(self):36        self.assertEqual(37            repr(ResourcePath("Packages/Foo/bar.py")),38            "ResourcePath('Packages/Foo/bar.py')"39        )40    def test_parts(self):41        path = ResourcePath("Packages/Foo/bar.py")42        self.assertEqual(path.parts, ("Packages", "Foo", "bar.py"))43    def test_parent(self):44        self.assertEqual(45            ResourcePath("Packages/Foo/bar.py").parent,46            ResourcePath("Packages/Foo")47        )48    def test_top_parent(self):49        self.assertEqual(50            ResourcePath("Packages").parent,51            ResourcePath("Packages")52        )53    def test_parents(self):54        self.assertEqual(55            ResourcePath("Packages/Foo/bar.py").parents,56            (57                ResourcePath("Packages/Foo"),58                ResourcePath("Packages")59            )60        )61    def test_parents_root(self):62        self.assertEqual(63            ResourcePath("Packages").parents,64            ()65        )66    def test_name(self):67        self.assertEqual(68            ResourcePath("Packages/Foo/bar.py").name,69            'bar.py'70        )71    def test_name_directory(self):72        self.assertEqual(73            ResourcePath("Packages/Foo/").name,74            'Foo'75        )76    def test_suffix(self):77        self.assertEqual(78            ResourcePath("Packages/Foo/bar.py").suffix,79            '.py'80        )81    def test_suffix_none(self):82        self.assertEqual(83            ResourcePath("Packages/Foo/bar").suffix,84            ''85        )86    def test_suffix_dots_end(self):87        self.assertEqual(88            ResourcePath("foo...").suffix,89            ""90        )91    def test_suffix_multiple(self):92        self.assertEqual(93            ResourcePath("Packages/Foo/bar.tar.gz").suffix,94            '.gz'95        )96    def test_suffixes(self):97        self.assertEqual(98            ResourcePath("Packages/Foo/bar.tar.gz").suffixes,99            ['.tar', '.gz']100        )101    def test_suffixes_none(self):102        self.assertEqual(103            ResourcePath("Packages/Foo/bar").suffixes,104            []105        )106    def test_suffixes_dotend(self):107        self.assertEqual(108            ResourcePath("foo.bar.").suffixes,109            []110        )111    def test_suffixes_dots(self):112        self.assertEqual(113            ResourcePath("foo.bar...baz").suffixes,114            ['.bar', '.', '.', '.baz']115        )116    def test_stem(self):117        self.assertEqual(118            ResourcePath("Packages/Foo/bar.py").stem,119            'bar'120        )121    def test_stem_dots_end(self):122        self.assertEqual(123            ResourcePath("foo...").stem,124            "foo..."125        )126    def test_stem_multiple(self):127        self.assertEqual(128            ResourcePath("Packages/Foo/bar.tar.gz").stem,129            'bar.tar'130        )131    def test_stem_none(self):132        self.assertEqual(133            ResourcePath("Packages/Foo/bar").stem,134            'bar'135        )136    def test_root(self):137        self.assertEqual(138            ResourcePath("Packages/Foo/bar").root,139            'Packages'140        )141    def test_package(self):142        self.assertEqual(143            ResourcePath("Packages/Foo/bar").package,144            'Foo'145        )146    def test_package_none(self):147        self.assertEqual(148            ResourcePath("Packages").package,149            None150        )151    def test_package_cache(self):152        self.assertEqual(153            ResourcePath("Cache/Foo").package,154            'Foo'155        )156    def test_match(self):157        path = ResourcePath("Packages/Foo/bar")158        self.assertTrue(path.match('bar'))159        self.assertTrue(path.match('Foo/bar'))160        self.assertTrue(path.match('Foo/*'))161        self.assertTrue(path.match('Packages/*/bar'))162        self.assertTrue(path.match('Packages/Foo/**/bar'))163        self.assertTrue(path.match("/Packages/Foo/bar"))164        self.assertFalse(path.match('baz'))165        self.assertFalse(path.match('Foo'))166        self.assertFalse(path.match('Packages/*/*/bar'))167        self.assertFalse(path.match('/Foo/bar'))168        self.assertFalse(path.match('ar'))169    def test_joinpath(self):170        self.assertEqual(171            ResourcePath("Packages/Foo/").joinpath('bar/', 'baz/xyzzy'),172            ResourcePath("Packages/Foo/bar/baz/xyzzy")173        )174    def test_joinpath_operator(self):175        self.assertEqual(176            ResourcePath("Packages/Foo/") / 'bar/' / 'baz/xyzzy',177            ResourcePath("Packages/Foo/bar/baz/xyzzy")178        )179    def test_relative_to(self):180        self.assertEqual(181            ResourcePath("Packages/Foo/baz/bar.py").relative_to(182                ResourcePath("Packages/Foo")183            ),184            ('baz', 'bar.py')185        )186    def test_relative_to_same(self):187        self.assertEqual(188            ResourcePath("Packages/Foo").relative_to(189                ResourcePath("Packages/Foo")190            ),191            ()192        )193    def test_relative_to_error(self):194        with self.assertRaises(ValueError):195            ResourcePath("Packages/Foo").relative_to(196                ResourcePath("Packages/Bar")197            )198    def test_with_name(self):199        self.assertEqual(200            ResourcePath("Packages/Foo/bar.py").with_name('baz.js'),201            ResourcePath("Packages/Foo/baz.js")202        )203    def test_with_name_root(self):204        self.assertEqual(205            ResourcePath("Packages").with_name('Cache'),206            ResourcePath("Cache")207        )208    def test_add_suffix(self):209        self.assertEqual(210            ResourcePath("Packages/Foo/bar").add_suffix('.py'),211            ResourcePath("Packages/Foo/bar.py")212        )213    def test_remove_suffix(self):214        self.assertEqual(215            ResourcePath("Packages/Foo/bar.py").remove_suffix(),216            ResourcePath("Packages/Foo/bar")217        )218    def test_remove_suffix_none(self):219        self.assertEqual(220            ResourcePath("Packages/Foo/bar").remove_suffix(must_remove=False),221            ResourcePath("Packages/Foo/bar")222        )223    def test_remove_suffix_none_error(self):224        with self.assertRaises(ValueError):225            ResourcePath("Packages/Foo/bar").remove_suffix()226    def test_remove_suffix_specified(self):227        self.assertEqual(228            ResourcePath("Packages/Foo/bar.py").remove_suffix('.py'),229            ResourcePath("Packages/Foo/bar")230        )231    def test_remove_suffix_specified_no_match(self):232        self.assertEqual(233            ResourcePath("Packages/Foo/bar.py").remove_suffix('.zip', must_remove=False),234            ResourcePath("Packages/Foo/bar.py")235        )236    def test_remove_suffix_specified_no_match_error(self):237        with self.assertRaises(ValueError):238            ResourcePath("Packages/Foo/bar.py").remove_suffix('.zip')239    def test_remove_suffix_specified_no_dot(self):240        self.assertEqual(241            ResourcePath("Packages/Foo/bar.py").remove_suffix('r.py'),242            ResourcePath("Packages/Foo/ba")243        )244    def test_remove_suffix_specified_entire_name(self):245        self.assertEqual(246            ResourcePath("Packages/Foo/bar.py").remove_suffix('bar.py', must_remove=False),247            ResourcePath("Packages/Foo/bar.py")248        )249    def test_remove_suffix_specified_entire_name_error(self):250        with self.assertRaises(ValueError):251            ResourcePath("Packages/Foo/bar.py").remove_suffix('bar.py')252    def test_remove_suffix_multiple(self):253        self.assertEqual(254            ResourcePath("Packages/Foo/bar.py").remove_suffix(['.zip', '.py']),255            ResourcePath("Packages/Foo/bar")256        )257    def test_remove_suffix_multiple_matches(self):258        self.assertEqual(259            ResourcePath("Packages/Foo/bar.tar.gz").remove_suffix(['.tar.gz', '.gz']),260            ResourcePath("Packages/Foo/bar")261        )262    def test_remove_suffix_multiple_matches_backward(self):263        self.assertEqual(264            ResourcePath("Packages/Foo/bar.tar.gz").remove_suffix(['.gz', '.tar.gz']),265            ResourcePath("Packages/Foo/bar")266        )267    def test_with_suffix(self):268        self.assertEqual(269            ResourcePath("Packages/Foo/bar.tar.gz").with_suffix('.bz2'),270            ResourcePath("Packages/Foo/bar.tar.bz2")271        )272    def test_with_suffix_empty(self):273        self.assertEqual(274            ResourcePath("Packages/Foo/bar").with_suffix('.py'),275            ResourcePath("Packages/Foo/bar.py")276        )277    def test_with_suffix_remove(self):278        self.assertEqual(279            ResourcePath("Packages/Foo/bar.py").with_suffix(''),280            ResourcePath("Packages/Foo/bar")281        )282    def test_with_suffix_root(self):283        self.assertEqual(284            ResourcePath("Packages").with_suffix('.bz2'),285            ResourcePath("Packages.bz2")...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
