3
dC                 @   sv   d dl Z d dlZd dlmZ d dlmZmZmZ ddlm	Z	m
Z
 e
rPd dlmZ e jje
 ddG d	d
 d
e	ZdS )    N)	MagicMock)CSSBeautifulSoup	ResultSet   )SoupTestSOUP_SIEVE_PRESENT)SelectorSyntaxErrorzSoup Sieve not installed)reasonc               @   s  e Zd ZdZdZdd Zdd ZeZdd Zd	d
 Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Z d9d: Z!d;d< Z"d=d> Z#d?d@ Z$dAdB Z%dCdD Z&dEdF Z'dGdH Z(dIdJ Z)dKdL Z*dMdN Z+dOdP Z,dQdR Z-dSdT Z.dUdV Z/dWdX Z0dYdZ Z1d[d\ Z2d]d^ Z3d_d` Z4dadb Z5dcdd Z6dedf Z7dgdh Z8didj Z9dkdl Z:dmdn Z;dodp Z<dqdr Z=dsdt Z>dudv Z?dwdx Z@dydz ZAd{d| ZBd}d~ ZCdd ZDdS )TestCSSSelectorszTest basic CSS selector functionality.

    This functionality is implemented in soupsieve, which has a much
    more comprehensive test suite, so this is basically an extra check
    that soupsieve works as expected.
    a  
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>The title</title>
<link rel="stylesheet" href="blah.css" type="text/css" id="l1">
</head>
<body>
<custom-dashed-tag class="dashed" id="dash1">Hello there.</custom-dashed-tag>
<div id="main" class="fancy">
<div id="inner">
<h1 id="header1">An H1</h1>
<p>Some text</p>
<p class="onep" id="p1">Some more text</p>
<h2 id="header2">An H2</h2>
<p class="class1 class2 class3" id="pmulti">Another</p>
<a href="http://bob.example.org/" rel="friend met" id="bob">Bob</a>
<h2 id="header3">Another H2</h2>
<a id="me" href="http://simonwillison.net/" rel="me">me</a>
<span class="s1">
<a href="#" id="s1a1">span1a1</a>
<a href="#" id="s1a2">span1a2 <span id="s1a2s1">test</span></a>
<span class="span2">
<a href="#" id="s2a1">span2a1</a>
</span>
<span class="span3"></span>
<custom-dashed-tag class="dashed" id="dash2"/>
<div data-tag="dashedvalue" id="data1"/>
</span>
</div>
<x id="xid">
<z id="zida"/>
<z id="zidab"/>
<z id="zidac"/>
</x>
<y id="yid">
<z id="zidb"/>
</y>
<p lang="en" id="lang-en">English</p>
<p lang="en-gb" id="lang-en-gb">English UK</p>
<p lang="en-us" id="lang-en-us">English US</p>
<p lang="fr" id="lang-fr">French</p>
</div>

<div id="footer">
</div>
c             C   s   t | jd| _d S )Nzhtml.parser)r   HTMLsoup)self r   </tmp/pip-build-8z3xcdsh/beautifulsoup4/bs4/tests/test_css.pysetup_methodN   s    zTestCSSSelectors.setup_methodc             K   sf   | j j|f|}t|tstdd |D }|j  |j  ||ksbtd|dj|dj|f d S )Nc             S   s   g | ]}|d  qS )idr   ).0elr   r   r   
<listcomp>T   s    z3TestCSSSelectors.assert_selects.<locals>.<listcomp>z$Selector %s, expected [%s], got [%s]z, )r   select
isinstancer   AssertionErrorsortjoin)r   selectorexpected_idskwargsresultsZel_idsr   r   r   assert_selectsQ   s    zTestCSSSelectors.assert_selectsc             G   s"   x|D ]\}}| j || qW d S )N)r   )r   testsr   r   r   r   r   assert_select_multiple]   s    z'TestCSSSelectors.assert_select_multiplec             C   sf   | j jjd}| j j|}t|dks*tx|D ]}|jdks0tq0W | j j|}d|d ksbtd S )Ndiv   mainr   )r   csscompiler   lenr   name
select_one)r   selelsr"   r   r   r   r   test_precompileda   s    
z!TestCSSSelectors.test_precompiledc             C   sF   | j jd}t|dkst|d jdks.t|d jdgksBtd S )Ntitler   r   z	The title)r   r   r'   r   r(   contents)r   r+   r   r   r   test_one_tag_onel   s    z!TestCSSSelectors.test_one_tag_onec             C   sX   | j jd}t|dkstx|D ]}|jdks"tq"W | j jd}d|d ksTtd S )Nr"   r#   r$   r   )r   r   r'   r   r(   r)   )r   r+   r"   r   r   r   r   test_one_tag_manyr   s    
z"TestCSSSelectors.test_one_tag_manyc             C   s   | j jd}d |kstd S )NZnonexistenttag)r   r)   r   )r   matchr   r   r   (test_select_one_returns_none_if_no_match{   s    z9TestCSSSelectors.test_select_one_returns_none_if_no_matchc             C   s    | j jd}| jdddg d S )Nzdiv divinnerdata1)r   r   r   )r   r+   r   r   r   test_tag_in_tag_one   s    z$TestCSSSelectors.test_tag_in_tag_onec             C   s&   x dD ]}| j |ddddg qW d S )	Nhtml divhtml body divbody divr4   r$   r3   footer)r6   r7   r8   )r   )r   r   r   r   r   test_tag_in_tag_many   s    
z%TestCSSSelectors.test_tag_in_tag_manyc             C   sB   | j ddgdd | j dddgdd | j dd	ddd
gdd d S )Nzhtml divr$   r   )limitzhtml body divr3      zbody divr4   r9   
   )r   )r   r   r   r   
test_limit   s    zTestCSSSelectors.test_limitc             C   s   t | jjddkstd S )Ndelr   )r'   r   r   r   )r   r   r   r   test_tag_no_match   s    z"TestCSSSelectors.test_tag_no_matchc          	   C   s&   t jt | jjd W d Q R X d S )Nztag%t)pytestraisesr	   r   r   )r   r   r   r   test_invalid_tag   s    z!TestCSSSelectors.test_invalid_tagc             C   s   | j dddg d S )Nzcustom-dashed-tagdash1dash2)r   )r   r   r   r   test_select_dashed_tag_ids   s    z+TestCSSSelectors.test_select_dashed_tag_idsc             C   s6   | j jd}|d jdkst|d d dks2td S )Nzcustom-dashed-tag[id="dash2"]r   zcustom-dashed-tagr   rE   )r   r   r(   r   )r   Zdashedr   r   r   test_select_dashed_by_id   s    z)TestCSSSelectors.test_select_dashed_by_idc             C   s   | j jdd jdkstd S )Nzbody > custom-dashed-tagr   zHello there.)r   r   textr   )r   r   r   r   test_dashed_tag_text   s    z%TestCSSSelectors.test_dashed_tag_textc             C   s    | j jd| j jdkstd S )Nzcustom-dashed-tag)r   r   find_allr   )r   r   r   r   #test_select_dashed_matches_find_all   s    z4TestCSSSelectors.test_select_dashed_matches_find_allc             C   s   | j ddgfdddgf d S )Nh1header1h2header2header3)r!   )r   r   r   r   test_header_tags   s    z!TestCSSSelectors.test_header_tagsc             C   sV   xPd	D ]H}| j j|}t|dks&t|d jdks8t|d d dgkstqW d S )
N.onepp.onephtml p.onepr   r   pclassonep)rR   rS   rT   )r   r   r'   r   r(   )r   r   r+   r   r   r   test_class_one   s
    
zTestCSSSelectors.test_class_onec             C   s    | j jd}t|dkstd S )Nzdiv.onepr   )r   r   r'   r   )r   r+   r   r   r   test_class_mismatched_tag   s    z*TestCSSSelectors.test_class_mismatched_tagc             C   s    xdD ]}| j |dg qW d S )N	div#inner#innerdiv div#innerr3   )rZ   r[   r\   )r   )r   r   r   r   r   test_one_id   s    
zTestCSSSelectors.test_one_idc             C   s    | j jd}t|dkstd S )Nz#doesnotexistr   )r   r   r'   r   )r   r+   r   r   r   test_bad_id   s    zTestCSSSelectors.test_bad_idc             C   sf   | j jd}t|dkstx|D ]}|jdks"tq"W |d d dgksNt|d jd sbtd S )Nzdiv#inner p   rU   r   rV   rW   r   )r   r   r'   r   r(   Zhas_attr)r   r+   r   r   r   r   test_items_in_id   s    
z!TestCSSSelectors.test_items_in_idc             C   s*   x$dD ]}t | jj|dkstqW d S )Ndiv#main deldiv#main div.oopsdiv div#mainr   )ra   rb   rc   )r'   r   r   r   )r   r   r   r   r   test_a_bunch_of_emptys   s    
z'TestCSSSelectors.test_a_bunch_of_emptysc             C   s    xd
D ]}| j |d	g qW d S )N.class1p.class1.class2p.class2.class3p.class3html p.class2div#inner .class2pmulti)re   rf   rg   rh   ri   rj   rk   rl   )r   )r   r   r   r   r   test_multi_class_support   s    z)TestCSSSelectors.test_multi_class_supportc             C   s    xdD ]}| j |dg qW d S )N.class1.class3.class3.class2.class1.class2.class3rm   )ro   rp   rq   )r   )r   r   r   r   r   test_multi_class_selection   s    z+TestCSSSelectors.test_multi_class_selectionc             C   s"   | j dddg | j ddg d S )Nz.s1 > as1a1s1a2z.s1 > a spans1a2s1)r   )r   r   r   r   test_child_selector   s    z$TestCSSSelectors.test_child_selectorc             C   s   | j ddg d S )Nz.s1 > a#s1a2 spanru   )r   )r   r   r   r   test_child_selector_id   s    z'TestCSSSelectors.test_child_selector_idc             C   st   | j ddgfddgfddgfddgfddgfddgfd	dgfd
g fddgfddgfddgfdg fdg fdg f d S )Nzp[class="onep"]p1z
p[id="p1"]z[class="onep"]z	[id="p1"]zlink[rel="stylesheet"]l1zlink[type="text/css"]zlink[href="blah.css"]zlink[href="no-blah.css"]z[rel="stylesheet"]z[type="text/css"]z[href="blah.css"]z[href="no-blah.css"]zp[href="no-blah.css"])r!   )r   r   r   r   test_attribute_equals   s    z&TestCSSSelectors.test_attribute_equalsc             C   s\   | j ddgfddgfddgfddgfddgfddgfdd	gfd
d	gfdd	gfdd	gf
 d S )Nzp[class~="class1"]rm   zp[class~="class2"]zp[class~="class3"]z[class~="class1"]z[class~="class2"]z[class~="class3"]za[rel~="friend"]bobza[rel~="met"]z[rel~="friend"]z[rel~="met"])r!   )r   r   r   r   test_attribute_tilde   s    z%TestCSSSelectors.test_attribute_tildec             C   sv   | j ddgfddgfdg fdg fdg fddgfdd	d
gfdd	d
gfdddgfdd
dgfddgfdd
gfddgf d S )Nz[rel^="style"]ry   zlink[rel^="style"]znotlink[rel^="notstyle"]z[rel^="notstyle"]zlink[rel^="notstyle"]zlink[href^="bla"]za[href^="http://"]r{   mez[href^="http://"]z	[id^="p"]rm   rx   z	[id^="m"]r$   zdiv[id^="m"]z
a[id^="m"]zdiv[data-tag^="dashed"]r4   )r!   )r   r   r   r   test_attribute_startswith   s    



z*TestCSSSelectors.test_attribute_startswithc             C   sH   | j ddgfddgfddgfdddddd	d
ddgfddgfdg f d S )Nz[href$=".css"]ry   zlink[href$=".css"]zlink[id$="1"]z	[id$="1"]r4   rx   rM   rs   s2a1ru   rD   zdiv[id$="1"]z[id$="noending"])r!   )r   r   r   r   test_attribute_endswith  s    z(TestCSSSelectors.test_attribute_endswithc             C   s   | j ddgfddgfdg fdg fdg fddgfdd	d
gfdddgfddgfdd
gfddgfddgfddgfddddddddddg	fddgfdg fdd	d
dgfdd	d
gfd dgfd!dd"gfd#d"gfd$dgf d S )%Nz[rel*="style"]ry   zlink[rel*="style"]znotlink[rel*="notstyle"]z[rel*="notstyle"]zlink[rel*="notstyle"]zlink[href*="bla"]z[href*="http://"]r{   r}   z	[id*="p"]rm   rx   zdiv[id*="m"]r$   z
a[id*="m"]z[href*=".css"]zlink[href*=".css"]zlink[id*="1"]z	[id*="1"]r4   rM   rs   rt   r   ru   rD   zdiv[id*="1"]z[id*="noending"]z[href*="."]za[href*="."]zlink[href*="."]zdiv[id*="n"]r3   zdiv[id*="nn"]zdiv[data-tag*="edval"])r!   )r   r   r   r   test_attribute_contains  s.    



z(TestCSSSelectors.test_attribute_containsc             C   s2   | j ddddgfddddgfddgfdg f d S )	Nzp[lang|="en"]zlang-enz
lang-en-gbz
lang-en-usz[lang|="en"]zp[lang|="fr"]zlang-frzp[lang|="gb"])r!   )r   r   r   r   test_attribute_exact_or_hypen2  s
    z.TestCSSSelectors.test_attribute_exact_or_hypenc          
   C   sV   | j ddddgfddgfdddgfddd	d
dgfdddgfdg fdg fddgf d S )Nz[rel]ry   r{   r}   z	link[rel]za[rel]z[lang]zlang-enz
lang-en-gbz
lang-en-uszlang-frzp[class]rx   rm   z[blah]zp[blah]zdiv[data-tag]r4   )r!   )r   r   r   r   test_attribute_exists:  s    

z&TestCSSSelectors.test_attribute_existsc             C   s,   d}t |d}|jd\}d|jks(td S )Nz]<div style="display: wrong">nope</div>
        <div style="display: right">yes</div>
        zhtml.parserzdiv[style="display: right"]yes)r   r   stringr   )r   htmlr   Zchosenr   r   r   "test_quoted_space_in_selector_nameF  s    
z3TestCSSSelectors.test_quoted_space_in_selector_namec             C   sH   t jt | jjd W d Q R X t jt | jjd W d Q R X d S )Nza:no-such-pseudoclassza:nth-of-type(a))rA   rB   NotImplementedErrorr   r   r	   )r   r   r   r   test_unsupported_pseudoclassN  s    z-TestCSSSelectors.test_unsupported_pseudoclassc             C   s   | j jd}t|dkst|d jdks.t| j jd}t|dksJt|d jdks\t| j jd}t|dksxt| j jd}t|dkstd S )	Nzdiv#inner p:nth-of-type(1)r   r   z	Some textzdiv#inner p:nth-of-type(3)ZAnotherzdiv#inner p:nth-of-type(4)zdiv p:nth-of-type(0))r   r   r'   r   r   )r   r+   r   r   r   test_nth_of_typeU  s    z!TestCSSSelectors.test_nth_of_typec             C   s2   | j jd}t|dkst|d jdks.td S )Nzdiv#inner > p:nth-of-type(1)r   r   z	Some text)r   r   r'   r   r   )r   r+   r   r   r   "test_nth_of_type_direct_descendanth  s    z3TestCSSSelectors.test_nth_of_type_direct_descendantc             C   s   | j ddg d S )Nz#inner > p:nth-of-type(2)rx   )r   )r   r   r   r   "test_id_child_selector_nth_of_typem  s    z3TestCSSSelectors.test_id_child_selector_nth_of_typec             C   s.   | j jddd}|jd}| j|ddg d S )Nr"   r$   )r   r3   r4   )r   findr   Zassert_selects_ids)r   r3   selectedr   r   r   test_select_on_elementp  s    
z'TestCSSSelectors.test_select_on_elementc             C   s   | j ddg | j dg  d S )Nz.fancy #innerr3   z.normal #inner)r   )r   r   r   r   test_overspecified_child_idy  s    z,TestCSSSelectors.test_overspecified_child_idc             C   sB   | j ddg | j ddg | j ddg g | jjdks>td S )Nz#p1 + h2rO   z#p1 + h2 + prm   z#p1 + #header2 + .class1z#p1 + p)r   r   r   r   )r   r   r   r   test_adjacent_sibling_selector}  s    z/TestCSSSelectors.test_adjacent_sibling_selectorc             C   sR   | j dddg | j ddg | j ddg | j ddg g | jjdksNtd S )	Nz#p1 ~ h2rO   rP   z#p1 ~ #header2z#p1 ~ h2 + ar}   z#p1 ~ h2 + [rel="me"]z#inner ~ h2)r   r   r   r   )r   r   r   r   test_general_sibling_selector  s
    z.TestCSSSelectors.test_general_sibling_selectorc          	   C   s&   t jt | jjd W d Q R X d S )Nzh1 >)rA   rB   r	   r   r   )r   r   r   r   test_dangling_combinator  s    z)TestCSSSelectors.test_dangling_combinatorc             C   s   | j ddddg d S )Nzp[lang] ~ pz
lang-en-gbz
lang-en-uszlang-fr)r   )r   r   r   r   2test_sibling_combinator_wont_select_same_tag_twice  s    zCTestCSSSelectors.test_sibling_combinator_wont_select_same_tag_twicec             C   s   | j dddg d S )Nzx, yxidyid)r   )r   r   r   r   test_multiple_select  s    z%TestCSSSelectors.test_multiple_selectc             C   s   | j dddg d S )Nzx,yr   r   )r   )r   r   r   r   "test_multiple_select_with_no_space  s    z3TestCSSSelectors.test_multiple_select_with_no_spacec             C   s   | j dddg d S )Nzx,    yr   r   )r   )r   r   r   r   $test_multiple_select_with_more_space  s    z5TestCSSSelectors.test_multiple_select_with_more_spacec             C   s   | j ddg d S )Nzx, xr   )r   )r   r   r   r   test_multiple_select_duplicated  s    z0TestCSSSelectors.test_multiple_select_duplicatedc             C   s   | j dddg d S )Nzx, y ~ p[lang=fr]r   zlang-fr)r   )r   r   r   r   test_multiple_select_sibling  s    z-TestCSSSelectors.test_multiple_select_siblingc             C   s   | j dddg d S )Nzx, y > zr   zidb)r   )r   r   r   r   .test_multiple_select_tag_and_direct_descendant  s    z?TestCSSSelectors.test_multiple_select_tag_and_direct_descendantc             C   s   | j dddddddg d S )Nzdiv > x, y, zr   r   zidar   zidabzidac)r   )r   r   r   r   /test_multiple_select_direct_descendant_and_tags  s    z@TestCSSSelectors.test_multiple_select_direct_descendant_and_tagsc             C   s   | j dddddddg d S )Nzdiv x,y,  zr   r   r   r   r   r   )r   )r   r   r   r   (test_multiple_select_indirect_descendant  s    z9TestCSSSelectors.test_multiple_select_indirect_descendantc             C   sH   t jt | jjd W d Q R X t jt | jjd W d Q R X d S )Nz,x, yzx,,y)rA   rB   r	   r   r   )r   r   r   r   test_invalid_multiple_select  s    z-TestCSSSelectors.test_invalid_multiple_selectc             C   s   | j dddg d S )Nzp[lang=en], p[lang=en-gb]zlang-enz
lang-en-gb)r   )r   r   r   r   test_multiple_select_attrs  s    z+TestCSSSelectors.test_multiple_select_attrsc             C   s   | j ddddg d S )Nz*x, y > z[id=zida], z[id=zidab], z[id=zidb]r   r   r   )r   )r   r   r   r   test_multiple_select_ids  s    z)TestCSSSelectors.test_multiple_select_idsc             C   s   | j dddg d S )Nzbody > div > x, y > zr   r   )r   )r   r   r   r   test_multiple_select_nested  s    z,TestCSSSelectors.test_multiple_select_nestedc             C   sR   d}t |d}|jd}dt|ks(tx$|jddgdD ]}||ks:tq:W d S )Nz3<div class="c1"/><div class="c2"/><div class="c1"/>zhtml.parserz.c1, .c2r_   c1c2)class_)r   r   r'   r   rJ   )r   Zmarkupr   r   elementr   r   r   test_select_duplicate_elements  s    

z/TestCSSSelectors.test_select_duplicate_elementsc             C   s8   | j jddd}|jjd}|| j jdddks4td S )Nr"   r3   )r   zdiv[id=main]r$   )r   r   r%   closestr   )r   r3   r   r   r   r   test_closest  s    zTestCSSSelectors.test_closestc             C   sL   | j jddd}| j jddd}|jjddks4t|jjddksHtd S )Nr"   r3   )r   r$   zdiv[id=main]FT)r   r   r%   r1   r   )r   r3   r$   r   r   r   
test_match  s    zTestCSSSelectors.test_matchc             C   sJ   | j jjd}t|tjst|\}}|d dks6t|d dksFtd S )NrN   r   rO   rP   )r   r%   Ziselectr   typesGeneratorTyper   )r   genrO   rP   r   r   r   test_iselect  s
    zTestCSSSelectors.test_iselectc             C   sh   | j jddd}|jjd}t|jjddks4t|jjd}t|tsNt|\}|d dksdtd S )	Nr"   r3   )r   rN   r<   zh2[id=header3]r   rP   )r   r   r%   filterr'   r   r   r   )r   r3   r   resultr   r   r   test_filter  s    zTestCSSSelectors.test_filterc             C   sH   | j jj}|ddkst|ddks*t|d| j jjdksDtd S )Nz.foo#barz
\.foo\#barz()[]{}z\(\)\[\]\{\}z.foo)r   r%   escaper   )r   mr   r   r   test_escape  s    
zTestCSSSelectors.test_escapeN)E__name__
__module____qualname____doc__r   r   r   ZassertSelectr!   r,   r/   r0   r2   r5   r:   r>   r@   rC   rF   rG   rI   rK   rQ   rX   rY   r]   r^   r`   rd   rn   rr   rv   rw   rz   r|   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r      s   1
	
	
r   )rA   r   Zunittest.mockr   Zbs4r   r   r    r   r   Z	soupsiever	   markZskipifr   r   r   r   r   <module>   s   