Best Python code snippet using pandera_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!!