
­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
3
6]8                @   s  d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
mZ ddlmZmZmZmZmZmZmZmZ ddlmZmZ e
jddk	Ze
jd	dk	ZG d
d deZG dd deZG dd deZG dd deZG dd deZG dd deZ G dd deZ!G dd deZ"G dd deZ#G dd de#Z$G dd de#Z%G d d! d!eZ&G d"d# d#e&Z'G d$d% d%e&Z(G d&d' d'eZ)G d(d) d)eZ*G d*d+ d+eZ+G d,d- d-eZ,G d.d/ d/eZ-G d0d1 d1eZ.G d2d3 d3eZ/G d4d5 d5eZ0G d6d7 d7eZ1dS )8a8  Tests for Beautiful Soup's tree traversal methods.

The tree traversal methods are the main advantage of using Beautiful
Soup over just using a parser.

Different parsers will build different Beautiful Soup trees given the
same markup, but all Beautiful Soup trees can be traversed with the
methods tested here.
    )	set_traceN)BeautifulSoup)builder_registryHTMLParserTreeBuilder)PY3KCDataCommentDeclarationDoctypeNavigableStringSoupStrainerTag)SoupTestskipIfZxmlZlxmlc               @   s   e Zd Zdd Zdd ZdS )TreeTestc             C   s   | j dd |D | dS )zMake sure that the given tags have the correct text.

        This is used in tests that define a bunch of tags, each
        containing a single string, and then select certain strings by
        some mechanism.
        c             S   s   g | ]
}|j qS  )string).0tagr   r   /usr/lib/python3.6/test_tree.py
<listcomp>2   s    z*TreeTest.assertSelects.<locals>.<listcomp>N)assertEqual)selftagsshould_matchr   r   r   assertSelects+   s    zTreeTest.assertSelectsc             C   s   | j dd |D | dS )zMake sure that the given tags have the correct IDs.

        This is used in tests that define a bunch of tags, each
        containing a single string, and then select certain strings by
        some mechanism.
        c             S   s   g | ]}|d  qS )idr   )r   r   r   r   r   r   ;   s    z-TreeTest.assertSelectsIDs.<locals>.<listcomp>N)r   )r   r   r   r   r   r   assertSelectsIDs4   s    zTreeTest.assertSelectsIDsN)__name__
__module____qualname__r   r   r   r   r   r   r   )   s   	r   c               @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )TestFindzBasic tests of the find() method.

    find() just calls find_all() with limit=1, so it's not tested all
    that thouroughly here.
    c             C   s"   | j d}| j|jdjd d S )Nz <a>1</a><b>2</b><a>3</a><b>4</b>b2)soupr   findr   )r   r$   r   r   r   test_find_tagE   s    
zTestFind.test_find_tagc             C   s"   | j d}| j|jddd d S )Nu   <h1>Räksmörgås</h1>u   Räksmörgås)r   )r$   r   r%   )r   r$   r   r   r   test_unicode_text_findI   s    
zTestFind.test_unicode_text_findc             C   s,   | j d}t| | jd|jddj d S )Nu&   <h1 id="Räksmörgås">here it is</h1>z
here it isu   Räksmörgås)r   )r$   strr   r%   text)r   r$   r   r   r   test_unicode_attribute_findM   s    
z$TestFind.test_unicode_attribute_findc             C   s"   | j d}| jdt|j  dS )z)Test an optimization that finds all tags.z<a>foo</a><b>bar</b>   N)r$   r   lenfind_all)r   r$   r   r   r   test_find_everythingS   s    
zTestFind.test_find_everythingc             C   s$   | j d}| jdt|jd dS )z;Test an optimization that finds all tags with a given name.z<a>foo</a><b>bar</b><a>baz</a>r+   aN)r$   r   r,   r-   )r   r$   r   r   r   test_find_everything_with_nameX   s    
z'TestFind.test_find_everything_with_nameN)	r   r   r    __doc__r&   r'   r*   r.   r0   r   r   r   r   r!   >   s   r!   c               @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )TestFindAllz%Basic tests of the find_all() method.c             C   s   | j d}| j|jdddg | j|jdddg | j|jddgdddg | j|jtjdddddg | j|jdddddg d	S )
z'You can search the tree for text nodes.u   <html>Foo<b>bar</b>»</html>bar)r   )r)   Fooz.*   »TN)r$   r   r-   recompile)r   r$   r   r   r   test_find_all_text_nodes`   s    
z$TestFindAll.test_find_all_text_nodesc             C   s   | j d}| j|jddddddg | j|jddddg | j|jdd	ddddd
dg | j|jddddddd
dg dS )z7You can limit the number of items returned by find_all.z(<a>1</a><a>2</a><a>3</a><a>4</a><a>5</a>r/      )limit1r#   3   
   45r   N)r$   r   r-   )r   r$   r   r   r   test_find_all_limitp   s    
zTestFindAll.test_find_all_limitc             C   s:   | j d}| j|ddddg | j|jdddg d S )	Nz!<a>1</a><b>2<a id='foo'>3</a></b>r/   r=   )r:   r;   foo)r   r<   )r$   r   r"   )r   r$   r   r   r   %test_calling_a_tag_is_calling_findall|   s    
z1TestFindAll.test_calling_a_tag_is_calling_findallc             C   s.   | j d}g }|j| | jg |j| d S )Nz<a></a>)r$   appendr   r-   )r   r$   lr   r   r   Ttest_find_all_with_self_referential_data_structure_does_not_cause_infinite_recursion   s    

z`TestFindAll.test_find_all_with_self_referential_data_structure_does_not_cause_infinite_recursionc             C   s^   | j d}|jd}| jt|d |jd}| jt|d |jdd}| jt|d dS )z%All find_all calls return a ResultSetz<a></a>r/   sourceTrB   )r)   N)r$   r-   
assertTruehasattr)r   r$   resultr   r   r   test_find_all_resultset   s    


z#TestFindAll.test_find_all_resultsetN)	r   r   r    r1   r8   rA   rC   rF   rK   r   r   r   r   r2   ]   s   
r2   c               @   s   e Zd Zdd ZdS )TestFindAllBasicNamespacesc             C   s<   | j d}| jd|jdj | jd|jddidj d S )Nz0<mathml:msqrt>4</mathml:msqrt><a svg:fill="red">r?   zmathml:msqrtr/   zsvg:fillZred)attrs)r$   r   r%   r   name)r   r$   r   r   r   test_find_by_namespaced_name   s    
z7TestFindAllBasicNamespaces.test_find_by_namespaced_nameN)r   r   r    rO   r   r   r   r   rL      s   rL   c                   sp   e Zd ZdZ f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  ZS )TestFindAllByNamez&Test ways of finding tags by tag name.c                s   t t| j  | jd| _d S )Nz<a>First tag.</a>
                                  <b>Second tag.</b>
                                  <c>Third <a>Nested tag.</a> tag.</c>)superr   setUpr$   tree)r   )	__class__r   r   rR      s    zTestFindAllByName.setUpc             C   s   | j | jjdddg d S )Nr/   z
First tag.zNested tag.)r   rS   r-   )r   r   r   r   test_find_all_by_tag_name   s    z+TestFindAllByName.test_find_all_by_tag_namec             C   s\   | j | jjddddg | j | jjdddddg | j | jjdtjddddg d S )Nr/   z
First tag.)r)   TzNested tag.r   )r   rS   r-   r6   r7   )r   r   r   r   test_find_all_by_name_and_text   s    z0TestFindAllByName.test_find_all_by_name_and_textc             C   s   | j | jjjddg d S )Nr/   zNested tag.)r   rS   cr-   )r   r   r   r   !test_find_all_on_non_root_element   s    z3TestFindAllByName.test_find_all_on_non_root_elementc             C   s   | j | jdddg d S )Nr/   z
First tag.zNested tag.)r   rS   )r   r   r   r   %test_calling_element_invokes_find_all   s    z7TestFindAllByName.test_calling_element_invokes_find_allc             C   s    | j | jjtdddg d S )Nr/   z
First tag.zNested tag.)r   rS   r-   r   )r   r   r   r   test_find_all_by_tag_strainer   s    z/TestFindAllByName.test_find_all_by_tag_strainerc             C   s"   | j | jjddgdddg d S )Nr/   r"   z
First tag.zSecond tag.zNested tag.)r   rS   r-   )r   r   r   r   test_find_all_by_tag_names   s    z,TestFindAllByName.test_find_all_by_tag_namesc             C   s$   | j | jjddddddg d S )NT)r/   r"   z
First tag.zSecond tag.zNested tag.)r   rS   r-   )r   r   r   r   test_find_all_by_tag_dict   s    z+TestFindAllByName.test_find_all_by_tag_dictc             C   s$   | j | jjtjddddg d S )Nz^[ab]$z
First tag.zSecond tag.zNested tag.)r   rS   r-   r6   r7   )r   r   r   r   test_find_all_by_tag_re   s    z)TestFindAllByName.test_find_all_by_tag_rec             C   s,   dd }| j d}| j|j|ddg d S )Nc             S   s   | j | jdkS )Nr   )rN   get)r   r   r   r   id_matches_name   s    zRTestFindAllByName.test_find_all_with_tags_matching_method.<locals>.id_matches_namez<a id="a">Match 1.</a>
                            <a id="1">Does not match.</a>
                            <b id="b">Match 2.</a>zMatch 1.zMatch 2.)r$   r   r-   )r   r_   rS   r   r   r   'test_find_all_with_tags_matching_method   s
    z9TestFindAllByName.test_find_all_with_tags_matching_methodc             C   sx   | j d}|jdd}|jdtjd}|jdddg\}}| jd|j | jd|j | jd|j | jd|j d S )NzH<div class='a b'>1</div><div class='a c'>2</div><div class='a d'>3</div>divza dza br<   r;   )r$   r%   r6   r7   r-   r   r   )r   r$   Zr1Zr2Zr3Zr4r   r   r   %test_find_with_multi_valued_attribute   s    z7TestFindAllByName.test_find_with_multi_valued_attribute)r   r   r    r1   rR   rU   rV   rX   rY   rZ   r[   r\   r]   r`   rb   __classcell__r   r   )rT   r   rP      s   rP   c               @   s   e Z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!S )"TestFindAllByAttributec             C   s&   | j d}| j|jddddg d S )Nz
                         <a id="first">Matching a.</a>
                         <a id="second">
                          Non-matching <b id="first">Matching b.</b>a.
                         </a>first)r   zMatching a.zMatching b.)r$   r   r-   )r   rS   r   r   r   test_find_all_by_attribute_name   s    z6TestFindAllByAttribute.test_find_all_by_attribute_namec             C   st   dj d}dj d}| j|}| j|jg|j|d | j|jg|j|jdd | j|jg|j|dgd d S )Nu   םולשutf8u   <a title="םולש"></a>)titlezsomething else)encoder$   r   r/   r-   decode)r   Zpeacedatar$   r   r   r   %test_find_all_by_utf8_attribute_value   s    


z<TestFindAllByAttribute.test_find_all_by_utf8_attribute_valuec             C   sX   | j d}| j|jdddg | j|jddiddg | j|jdd	idd
g d S )Na0  
                         <a name="name1" class="class1">Name match.</a>
                         <a name="name2" class="class2">Class match.</a>
                         <a name="name3" class="class3">Non-match.</a>
                         <name1>A tag called 'name1'.</name1>
                         Zname1)rN   zA tag called 'name1'.rN   )rM   zName match.classZclass2zClass match.)r$   r   r-   )r   rS   r   r   r   test_find_all_by_attribute_dict  s    z6TestFindAllByAttribute.test_find_all_by_attribute_dictc             C   s   | j d}| j|jddddg | j|jddddg | j|jdd	ddg | j|jdddg | j|jdd
ddg | j|jdddg | j|jdd	dg d S )Nz
                         <a class="1">Class 1.</a>
                         <a class="2">Class 2.</a>
                         <b class="1">Class 1.</b>
                         <c class="3 4">Class 3 and 4.</c>
                         r/   r;   )class_zClass 1.rW   r<   zClass 3 and 4.r?   )rM   )r$   r   r-   )r   rS   r   r   r   test_find_all_by_class  s    z-TestFindAllByAttribute.test_find_all_by_classc             C   st   | j d}|jdtjdd}| j|dg |jdtjdd}| j|dg |jdtjdd}| j|dg d S )Nz#<gar class='foo bar'>Found it</gar>Zgaro)ro   zFound itr/   zo b)r$   r-   r6   r7   r   )r   rS   fr   r   r   0test_find_by_class_when_multiple_classes_present-  s    
zGTestFindAllByAttribute.test_find_by_class_when_multiple_classes_presentc             C   sd   | j d}| j|jdtjddg dd }| j|jd|g  dd }| j|jd|dg d S )	Nz<a class='bar'>Found it</a>r/   ZbazFound itc             S   s   t | dkS )Nr9   )r,   )valuer   r   r   big_attribute_value@  s    znTestFindAllByAttribute.test_find_all_with_non_dictionary_for_attrs_finds_by_class.<locals>.big_attribute_valuec             S   s   t | dkS )Nr9   )r,   )rt   r   r   r   small_attribute_valueE  s    zpTestFindAllByAttribute.test_find_all_with_non_dictionary_for_attrs_finds_by_class.<locals>.small_attribute_value)r$   r   r-   r6   r7   )r   r$   ru   rv   r   r   r   :test_find_all_with_non_dictionary_for_attrs_finds_by_class;  s    
zQTestFindAllByAttribute.test_find_all_with_non_dictionary_for_attrs_finds_by_classc             C   s   | j d}|jd\}}| j||g|jdd | j|g|jdd | j|g|jddd | j|g|jdd | jg |jdd d S )Nz*<a class="foo bar"></a><a class="foo"></a>r/   rB   r3   zfoo bar)ro   zbar foo)r$   r-   r   )r   r$   r/   Za2r   r   r   :test_find_all_with_string_for_attrs_finds_multiple_classesK  s    
zQTestFindAllByAttribute.test_find_all_with_string_for_attrs_finds_multiple_classesc             C   s0   | j d}tddid}| j|j|dg d S )Nzi
                         <a id="first">Match.</a>
                         <a id="second">Non-match.</a>r   re   )rM   zMatch.)r$   r   r   r-   )r   rS   strainerr   r   r   'test_find_all_by_attribute_soupstrainerW  s    z>TestFindAllByAttribute.test_find_all_by_attribute_soupstrainerc             C   s&   | j d}| j|jdd ddg d S )Nz<a id="1">ID present.</a>
                            <a>No ID present.</a>
                            <a id="">ID is empty.</a>r/   )r   zNo ID present.)r$   r   r-   )r   rS   r   r   r   $test_find_all_with_missing_attribute_  s    z;TestFindAllByAttribute.test_find_all_with_missing_attributec             C   s&   | j d}| j|jddddg d S )Nz<a id="1">ID present.</a>
                            <a>No ID present.</a>
                            <a id="">ID is empty.</a>T)r   zID present.zID is empty.)r$   r   r-   )r   rS   r   r   r   $test_find_all_with_defined_attributeg  s    z;TestFindAllByAttribute.test_find_all_with_defined_attributec             C   s>   | j d}ddg}| j|jdd| | j|jdd| d S )Nz[<a id=1>Unquoted attribute.</a>
                            <a id="1">Quoted attribute.</a>zUnquoted attribute.zQuoted attribute.r=   )r   r;   )r$   r   r-   )r   rS   Zexpectedr   r   r   $test_find_all_with_numeric_attributep  s
    z;TestFindAllByAttribute.test_find_all_with_numeric_attributec             C   s,   | j d}| j|jdddgdddg d S )Nz<a id="1">1</a>
                            <a id="2">2</a>
                            <a id="3">3</a>
                            <a>No ID.</a>r;   r<   r?   )r   )r$   r   r-   )r   rS   r   r   r   (test_find_all_with_list_attribute_valuesy  s    z?TestFindAllByAttribute.test_find_all_with_list_attribute_valuesc             C   s,   | j d}| j|jtjddddg d S )Nz<a id="a">One a.</a>
                            <a id="aa">Two as.</a>
                            <a id="ab">Mixed as and bs.</a>
                            <a id="b">One b.</a>
                            <a>No ID.</a>z^a+$)r   zOne a.zTwo as.)r$   r   r-   r6   r7   )r   rS   r   r   r   5test_find_all_with_regular_expression_attribute_value  s    zLTestFindAllByAttribute.test_find_all_with_regular_expression_attribute_valuec             C   sX   | j d}|j}| j|g|jddd | jg |jddd | jg |jddd d S )Nz<b>foo</b><b>bar</b><a>foo</a>r/   rB   )r)   r3   )r$   r/   r   r-   )r   r$   r/   r   r   r   'test_find_by_name_and_containing_string  s
    
z>TestFindAllByAttribute.test_find_by_name_and_containing_stringc             C   s*   | j d}| j|jd|jddd d S )Nz"<a>foo</a><a><b><c>foo</c></b></a>r/   rB   )r)   )r$   r   r-   )r   r$   r   r   r   =test_find_by_name_and_containing_string_when_string_is_buried  s    
zTTestFindAllByAttribute.test_find_by_name_and_containing_string_when_string_is_buriedc             C   sB   | j d}|j}| j|g|jddd | jg |jddd d S )Nz"<b id="1">foo</b><a id="2">foo</a>r+   rB   )r   r)   r=   r3   )r$   r/   r   r-   )r   r$   r/   r   r   r   ,test_find_by_attribute_and_containing_string  s    
zCTestFindAllByAttribute.test_find_by_attribute_and_containing_stringN)r   r   r    rf   rl   rn   rp   rs   rw   rx   rz   r{   r|   r}   r~   r   r   r   r   r   r   r   r   rd      s    		
rd   c               @   s   e Zd ZdZdd ZdS )	TestIndexzTest Tag.indexc             C   sN   | j d}|j}x(t|jD ]\}}| j||j| qW | jt|jd d S )Nah  <div>
                            <a>Identical</a>
                            <b>Not identical</b>
                            <a>Identical</a>

                            <c><d>Identical with child</d></c>
                            <b>Also not identical</b>
                            <c><d>Identical with child</d></c>
                            </div>r=   )r$   ra   	enumeratecontentsr   indexassertRaises
ValueError)r   rS   ra   ielementr   r   r   
test_index  s    zTestIndex.test_indexN)r   r   r    r1   r   r   r   r   r   r     s   r   c                   s`   e Zd ZdZ f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  ZS )TestParentOperationsz;Test navigation and searching through an element's parents.c                s(   t t| j  | jd| _| jj| _d S )Na1  <ul id="empty"></ul>
                                 <ul id="top">
                                  <ul id="middle">
                                   <ul id="bottom">
                                    <b>Start here</b>
                                   </ul>
                                  </ul>)rQ   r   rR   r$   rS   r"   start)r   )rT   r   r   rR     s    zTestParentOperations.setUpc             C   sF   | j | jjd d | j | jjjd d | j | jjjjd d d S )Nr   bottommiddletop)r   r   parent)r   r   r   r   test_parent  s    z TestParentOperations.test_parentc             C   s    | j jd }| j|j| j  d S )Nr   )rS   r   r   r   )r   Ztop_tagr   r   r   %test_parent_of_top_tag_is_soup_object  s    z:TestParentOperations.test_parent_of_top_tag_is_soup_objectc             C   s   | j d | jj d S )N)r   rS   r   )r   r   r   r   test_soup_object_has_no_parent  s    z3TestParentOperations.test_soup_object_has_no_parentc             C   s8   | j | jjddddg | j | jjddddg d S )Nulr   r   r   )r   )r   r   Zfind_parents)r   r   r   r   test_find_parents  s    z&TestParentOperations.test_find_parentsc             C   s8   | j | jjdd d | j | jjdddd d d S )Nr   r   r   r   )r   )r   r   find_parent)r   r   r   r   test_find_parent  s    z%TestParentOperations.test_find_parentc             C   s"   | j jdd}| j|jjd d S )Nz
Start here)r)   r"   )rS   r%   r   r   rN   )r   r)   r   r   r   test_parent_of_text_element  s    z0TestParentOperations.test_parent_of_text_elementc             C   s(   | j jdd}| j|jdd d d S )Nz
Start here)r)   r   r   r   )rS   r%   r   r   )r   r)   r   r   r   test_text_element_find_parent  s    z2TestParentOperations.test_text_element_find_parentc             C   s(   dd | j jD }| j|dddg d S )Nc             S   s&   g | ]}|d k	rd|j kr|d qS )Nr   )rM   )r   r   r   r   r   r     s    z>TestParentOperations.test_parent_generator.<locals>.<listcomp>r   r   r   )r   parentsr   )r   r   r   r   r   test_parent_generator  s    z*TestParentOperations.test_parent_generator)r   r   r    r1   rR   r   r   r   r   r   r   r   r   rc   r   r   )rT   r   r     s   r   c                   s   e Zd Z fddZ  ZS )ProximityTestc                s   t t| j  | jd| _d S )Nzg<html id="start"><head></head><body><b id="1">One</b><b id="2">Two</b><b id="3">Three</b></body></html>)rQ   r   rR   r$   rS   )r   )rT   r   r   rR     s    zProximityTest.setUp)r   r   r    rR   rc   r   r   )rT   r   r     s   r   c                   sT   e Zd Z fddZdd Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
  ZS )TestNextOperationsc                s   t t| j  | jj| _d S )N)rQ   r   rR   rS   r"   r   )r   )rT   r   r   rR     s    zTestNextOperations.setUpc             C   s*   | j | jjd | j | jjjd d d S )NOner   r#   )r   r   next_element)r   r   r   r   	test_next  s    zTestNextOperations.test_nextc             C   s    | j jdd}| j|jd  d S )NThree)r)   )rS   r%   r   r   )r   Zlastr   r   r   test_next_of_last_item_is_none  s    z1TestNextOperations.test_next_of_last_item_is_nonec             C   s   | j | jjd  d S )N)r   rS   r   )r   r   r   r   test_next_of_root_is_none  s    z,TestNextOperations.test_next_of_root_is_nonec             C   sB   | j | jjdddg | jjdd | j | jjdddg d S )Nr"   Twor   r9   )r   )r   r   find_all_next)r   r   r   r   test_find_all_next  s    z%TestNextOperations.test_find_all_nextc             C   s2   | j | jjdd d | j | jjddd d S )Nr"   r   r#   r   )r)   )r   r   	find_next)r   r   r   r   test_find_next
  s    z!TestNextOperations.test_find_nextc             C   s<   | j jdd}| j|jdjd | j|jdddg d S )Nr   )r)   r"   r   r   )rS   r%   r   r   r   r   r   )r   r)   r   r   r   test_find_next_for_text_element  s    z2TestNextOperations.test_find_next_for_text_elementc             C   sF   | j jdd}dd |jD }|\}}| j|d d | j|d d S )Nr   )r)   c             S   s   g | ]}|qS r   r   )r   noder   r   r   r     s    z:TestNextOperations.test_next_generator.<locals>.<listcomp>r   r<   r   )rS   r%   Znext_elementsr   )r   r   Z
successorsr   r   r   r   r   test_next_generator  s
    z&TestNextOperations.test_next_generator)r   r   r    rR   r   r   r   r   r   r   r   rc   r   r   )rT   r   r     s   r   c                   sT   e Zd Z fddZdd Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
  ZS )TestPreviousOperationsc                s"   t t| j  | jjdd| _d S )Nr   )r)   )rQ   r   rR   rS   r%   end)r   )rT   r   r   rR     s    zTestPreviousOperations.setUpc             C   s*   | j | jjd d | j | jjjd d S )Nr   r<   r   )r   r   previous_element)r   r   r   r   test_previous!  s    z$TestPreviousOperations.test_previousc             C   s   | j jd}| j|jd  d S )Nhtml)rS   r%   r   r   )r   re   r   r   r   #test_previous_of_first_item_is_none%  s    z:TestPreviousOperations.test_previous_of_first_item_is_nonec             C   s   d S )Nr   )r   r   r   r   test_previous_of_root_is_none)  s    z4TestPreviousOperations.test_previous_of_root_is_nonec             C   s6   | j | jjddddg | j | jjdddg d S )Nr"   r   r   r   r=   )r   )r   r   find_all_previous)r   r   r   r   test_find_all_previous/  s    z-TestPreviousOperations.test_find_all_previousc             C   s2   | j | jjdd d | j | jjddd d S )Nr"   r   r<   r   )r)   )r   r   find_previous)r   r   r   r   test_find_previous7  s    z)TestPreviousOperations.test_find_previousc             C   s>   | j jdd}| j|jdjd | j|jddddg d S )Nr   )r)   r"   r   r   )rS   r%   r   r   r   r   r   )r   r)   r   r   r   #test_find_previous_for_text_element;  s    z:TestPreviousOperations.test_find_previous_for_text_elementc             C   sh   | j jdd}dd |jD }|\}}}}| j|d d | j|jd | j|jd | j|jd	 d S )
Nr   )r)   c             S   s   g | ]}|qS r   r   )r   r   r   r   r   r   C  s    zBTestPreviousOperations.test_previous_generator.<locals>.<listcomp>r   r;   bodyheadr   )rS   r%   Zprevious_elementsr   rN   )r   r   Zpredecessorsr"   r   r   r   r   r   r   test_previous_generatorA  s    z.TestPreviousOperations.test_previous_generator)r   r   r    rR   r   r   r   r   r   r   r   rc   r   r   )rT   r   r     s   r   c                   s   e Zd Z fddZ  ZS )SiblingTestc                s4   t t| j  d}tjdjd|}| j|| _d S )Na  <html>
                    <span id="1">
                     <span id="1.1"></span>
                    </span>
                    <span id="2">
                     <span id="2.1"></span>
                    </span>
                    <span id="3">
                     <span id="3.1"></span>
                    </span>
                    <span id="4"></span>
                    </html>z\n\s* )rQ   r   rR   r6   r7   subr$   rS   )r   markup)rT   r   r   rR   P  s    zSiblingTest.setUp)r   r   r    rR   rc   r   r   )rT   r   r   N  s   r   c                   sL   e Zd Z fddZdd Zdd Zdd Zd	d
 Zdd Zdd Z	  Z
S )TestNextSiblingc                s"   t t| j  | jjdd| _d S )Nr;   )r   )rQ   r   rR   rS   r%   r   )r   )rT   r   r   rR   f  s    zTestNextSibling.setUpc             C   s   | j | jjd  d S )N)r   rS   next_sibling)r   r   r   r   !test_next_sibling_of_root_is_nonej  s    z1TestNextSibling.test_next_sibling_of_root_is_nonec             C   sB   | j | jjd d | j | jjjd d | j | jjd d d S )Nr   r#   r<   z1.1)r   r   r   r   )r   r   r   r   test_next_siblingm  s    z!TestNextSibling.test_next_siblingc             C   sN   | j | jjjd  | jjdd}| j |jd  | jjdd}| j |jd  d S )Nz1.1)r   r?   )r   rS   r   r   r%   )r   nested_spanZ	last_spanr   r   r   test_next_sibling_may_not_existt  s
    z/TestNextSibling.test_next_sibling_may_not_existc             C   s   | j | jjdd d d S )Nspanr   r#   )r   r   find_next_sibling)r   r   r   r   test_find_next_sibling}  s    z&TestNextSibling.test_find_next_siblingc             C   s6   | j | jjddddg | j | jjdddg d S )Nr   r#   r<   r?   )r   )r   r   find_next_siblings)r   r   r   r   test_next_siblings  s    z"TestNextSibling.test_next_siblingsc             C   sv   | j d}|jdd}| j|jjd | j|jjd | j|jddg | j|jddd | j|jddd  d S )NzFoo<b>bar</b>bazr4   )r)   r"   bazr3   nonesuch)r$   r%   r   r   rN   r   r   r   )r   r$   r   r   r   r   "test_next_sibling_for_text_element  s    
z2TestNextSibling.test_next_sibling_for_text_element)r   r   r    rR   r   r   r   r   r   r   rc   r   r   )rT   r   r   d  s   	r   c                   sL   e Zd Z fddZdd Zdd Zdd Zd	d
 Zdd Zdd Z	  Z
S )TestPreviousSiblingc                s"   t t| j  | jjdd| _d S )Nr?   )r   )rQ   r   rR   rS   r%   r   )r   )rT   r   r   rR     s    zTestPreviousSibling.setUpc             C   s   | j | jjd  d S )N)r   rS   previous_sibling)r   r   r   r   %test_previous_sibling_of_root_is_none  s    z9TestPreviousSibling.test_previous_sibling_of_root_is_nonec             C   sB   | j | jjd d | j | jjjd d | j | jjd d d S )Nr   r<   r#   z3.1)r   r   r   r   )r   r   r   r   test_previous_sibling  s    z)TestPreviousSibling.test_previous_siblingc             C   sN   | j | jjjd  | jjdd}| j |jd  | jjdd}| j |jd  d S )Nz1.1)r   r;   )r   rS   r   r   r%   )r   r   Z
first_spanr   r   r   #test_previous_sibling_may_not_exist  s
    z7TestPreviousSibling.test_previous_sibling_may_not_existc             C   s   | j | jjdd d d S )Nr   r   r<   )r   r   find_previous_sibling)r   r   r   r   test_find_previous_sibling  s    z.TestPreviousSibling.test_find_previous_siblingc             C   s6   | j | jjddddg | j | jjdddg d S )Nr   r<   r#   r;   )r   )r   r   find_previous_siblings)r   r   r   r   test_previous_siblings  s    z*TestPreviousSibling.test_previous_siblingsc             C   sv   | j d}|jdd}| j|jjd | j|jjd | j|jddg | j|jddd | j|jddd  d S )NzFoo<b>bar</b>bazr   )r)   r"   r4   r3   r   )r$   r%   r   r   rN   r   r   r   )r   r$   r   r   r   r   &test_previous_sibling_for_text_element  s    
z:TestPreviousSibling.test_previous_sibling_for_text_element)r   r   r    rR   r   r   r   r   r   r   rc   r   r   )rT   r   r     s   	r   c               @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )TestTagCreationz$Test the ability to create new tags.c             C   sd   | j d}|jddddid}| jt|t | jd|j | jtddd|j | jd |j	 d S )Nr   rB   r   rN   za name)r3   rM   )r3   rN   )
r$   new_tagrH   
isinstancer   r   rN   dictrM   r   )r   r$   r   r   r   r   test_new_tag  s    
zTestTagCreation.test_new_tagc             C   s   t rBtdd}|jd}|jd}| jd|j  | jd|j  tdd}|jd}|jd}| jd|j  | jd|j  d S )	Nr   zlxml-xmlbrps   <br/>s   <p/>zhtml.parsers   <p></p>)XML_BUILDER_PRESENTr   r   r   ri   )r   Zxml_soupZxml_brZxml_pZ	html_soupZhtml_brZhtml_pr   r   r   1test_tag_inherits_self_closing_rules_from_builder  s    





zATestTagCreation.test_tag_inherits_self_closing_rules_from_builderc             C   s4   | j d}|jd}| jd| | jt|t d S )Nr   rB   )r$   
new_stringr   rH   r   r   )r   r$   sr   r   r   'test_new_string_creates_navigablestring  s    

z7TestTagCreation.test_new_string_creates_navigablestringc             C   s6   | j d}|jdt}| jd| | jt|t d S )Nr   rB   )r$   r   r   r   rH   r   )r   r$   r   r   r   r   3test_new_string_can_create_navigablestring_subclass  s    
zCTestTagCreation.test_new_string_can_create_navigablestring_subclassN)r   r   r    r1   r   r   r   r   r   r   r   r   r     s
   r   c               @   s<  e Z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'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(dMS )NTestTreeModificationc             C   sl   | j d}d|jd< | j|j | jd |jd= | j|j | jd d|jd< | j|j | jd d S )	Nz<a id="1"></a>r+   r   z<a id="2"></a>z<a></a>rB   Zid2z<a id2="foo"></a>)r$   r/   r   rj   document_for)r   r$   r   r   r   test_attribute_modification  s    


z0TestTreeModification.test_attribute_modificationc             C   sl   t jd }| jd|d}t||d}t||d}d|d< |jjd| |jjd	| | j|jj d
 d S )Nr   z<body></body>)builderr/   olzhttp://foo.com/Zhrefr   r=   s4   <body><a href="http://foo.com/"></a><ol></ol></body>)r   lookupr$   r   r   insertr   ri   )r   r   r$   r/   r   r   r   r   test_new_tag_creation  s    z*TestTreeModification.test_new_tag_creationc             C   s\   d}| j |}|jdd}|j}|jddj|j | j|j| | j|j | jd d S )NzT<p id="1">Don't leave me <b>here</b>.</p>
                <p id="2">Don't leave!</p>r#   )r   zD<p id="1">Don't leave me .</p>
<p id="2">Don't leave!<b>here</b></p>)r$   r%   r"   rD   r   r   rj   r   )r   docr$   Zsecond_paraZboldr   r   r   !test_append_to_contents_moves_tag  s    

z6TestTreeModification.test_append_to_contents_moves_tagc             C   s0   d}| j |}|j}|j|j}| j|| d S )Nz<a></a><b><c></c></b>)r$   r/   replace_withrW   r   )r   r)   r$   r/   new_ar   r   r   1test_replace_with_returns_thing_that_was_replaced  s
    
zFTestTreeModification.test_replace_with_returns_thing_that_was_replacedc             C   s,   d}| j |}|j}|j }| j|| d S )Nz<a><b></b><c></c></a>)r$   r/   unwrapr   )r   r)   r$   r/   r   r   r   r   +test_unwrap_returns_thing_that_was_replaced  s
    
z@TestTreeModification.test_unwrap_returns_thing_that_was_replacedc             C   sJ   | j d}|j}|j  | jd |j | jt|j | jt|j|j	 d S )Nz<a><b>Foo</b></a><c>Bar</c>)
r$   r/   extractr   r   r   r   r   r   rW   )r   r$   r/   r   r   r   Itest_replace_with_and_unwrap_give_useful_exception_when_tag_has_no_parent  s    
z^TestTreeModification.test_replace_with_and_unwrap_give_useful_exception_when_tag_has_no_parentc             C   s:   d}| j |}|j}|jj| | j|j | j| d S )Nz-<a><b></b><c>Foo<d></d></c></a><a><e></e></a>)r$   rW   r   r   rj   r   )r   r)   r$   rW   r   r   r   test_replace_tag_with_itself'  s
    
z1TestTreeModification.test_replace_tag_with_itselfc             C   s&   d}| j |}| jt|jj|j d S )Nz<a><b></b></a>)r$   r   r   r"   r   r/   )r   r)   r$   r   r   r   1test_replace_tag_with_its_parent_raises_exception.  s    
zFTestTreeModification.test_replace_tag_with_its_parent_raises_exceptionc             C   s(   d}| j |}| jt|jjd|j d S )Nz<a><b></b></a>r   )r$   r   r   r/   r   )r   r)   r$   r   r   r   ,test_insert_tag_into_itself_raises_exception3  s    
zATestTreeModification.test_insert_tag_into_itself_raises_exceptionc       	      C   s   | j d}d}| j |}|jd| x|jD ]}t|t s,tq,W t|j\}}}}| jd|j	 | jd|j	 | jd|j	 | jd|j	 dS )	zInserting one BeautifulSoup object into another actually inserts all
        of its children -- you'll never combine BeautifulSoup objects.
        z-<p>And now, a word:</p><p>And we're back.</p>z<p>p2</p><p>p3</p>r=   zAnd now, a word:p2p3zAnd we're back.N)
r$   r   Zdescendantsr   r   AssertionErrorlistZchildrenr   r   )	r   r$   r)   Z	to_insertr   p1r   r   Zp4r   r   r   1test_insert_beautifulsoup_object_inserts_children8  s    

zFTestTreeModification.test_insert_beautifulsoup_object_inserts_childrenc             C   sX   | j d}|j}|jd }|jdd |j\}}|jd |jd | jd|jj d S )Nz<p><a>one</a><b>three</b></p>r   r=   Ztwor   Zthree)r$   r/   r   r   ZreplaceWithr   r"   r   )r   r$   r/   r"   leftrightr   r   r   3test_replace_with_maintains_next_element_throughoutL  s    




zHTestTreeModification.test_replace_with_maintains_next_element_throughoutc             C   sl   | j d}|jddjd |jdd}|j}| j|j| | j|j| | j|jj| | j|jd  d S )Nz<b>Argh!</b>zArgh!)r)   zHooray!)r$   r%   r   r"   r   r   r   r   )r   r$   new_textr"   r   r   r   test_replace_final_node[  s    
z,TestTreeModification.test_replace_final_nodec             C   s   | j d}|jjdd | j|j | jd |jdd}| j|jd | j|jj| | j|j	d | j|j	j
| | j|j
d  | j|j|j d S )Nz<a><b>Argh!</b><c></c></a>r=   zHooray!z!<a><b>Argh!Hooray!</b><c></c></a>)r)   zArgh!)r$   r"   r   r   rj   r   r%   r   r   r   r   rW   )r   r$   r  r   r   r   test_consecutive_text_nodese  s    

z0TestTreeModification.test_consecutive_text_nodesc             C   sT   | j d}|jjdd |jjdd | jddg|jj | j|jjd jd d S )Nz<a></a>r   r3   rB   )r$   r/   r   r   r   r   )r   r$   r   r   r   test_insert_stringz  s
    
z'TestTreeModification.test_insert_stringc             C   s   | j }| jd|d}t||d}|jdd |jjd| | j|j | jd |j}| j|j	| | j|j
| |jdd	}| j|j| | j|j| |j}| j|j	| | j|j
| |jdd	}| j|j| | j|j| | j|j| d S )
Nz%<a><b>Find</b><c>lady!</c><d></d></a>)r   Zmagictagr   ther=   z=<a><b>Find</b><magictag>the</magictag><c>lady!</c><d></d></a>ZFind)r)   )Zdefault_builderr$   r   r   r/   r   rj   r   r"   r   r   r%   r   r   rW   r   )r   r   r$   Z	magic_tagZb_tagr%   Zc_tagr  r   r   r   test_insert_tag  s,    

z$TestTreeModification.test_insert_tagc             C   s0   d}| j |}|jj|j | j||j  d S )Nz<a><b></b></a>)r$   r/   rD   r"   r   rj   )r   rk   r$   r   r   r   *test_append_child_thats_already_at_the_end  s    
z?TestTreeModification.test_append_child_thats_already_at_the_endc             C   s2   d}| j |}|jjd|j | jd|j  d S )Nz<a><b></b><c></c><d></d></a>r   z<a><d></d><b></b><c></c></a>)r$   r/   r   dr   rj   )r   rk   r$   r   r   r   $test_move_tag_to_beginning_of_parent  s    
z9TestTreeModification.test_move_tag_to_beginning_of_parentc             C   s.   | j d}|jjdd | jt|jd d S )Nz<br/>r=   ZContentsz<br>Contents</br>)r$   r   r   r   r(   )r   r$   r   r   r   &test_insert_works_on_empty_element_tag  s    
z;TestTreeModification.test_insert_works_on_empty_element_tagc             C   s`   | j d}|jjd |jjd | j|j | jd |jj|j | j|j | jd d S )Nz<a>foo</a><b>bar</b>BAZQUUXzQUUX<a>foo</a>BAZ<b>bar</b>zQUUX<b>bar</b><a>foo</a>BAZ)r$   r"   insert_beforer/   r   rj   r   )r   r$   r   r   r   test_insert_before  s    
z'TestTreeModification.test_insert_beforec             C   s`   | j d}|jjd |jjd | j|j | jd |jj|j | j|j | jd d S )Nz<a>foo</a><b>bar</b>r  r  z<a>foo</a>QUUX<b>bar</b>BAZzQUUX<b>bar</b><a>foo</a>BAZ)r$   r"   insert_afterr/   r   rj   r   )r   r$   r   r   r   test_insert_after  s    
z&TestTreeModification.test_insert_afterc             C   sR   | j d}|jd}|jd}| jt|j| | jt|j| | jt|j| d S )Nr   r/   )r$   r   r   r   r   r  NotImplementedError)r   r$   r   r   r   r   r   :test_insert_after_raises_exception_if_after_has_no_meaning  s    


zOTestTreeModification.test_insert_after_raises_exception_if_after_has_no_meaningc             C   sR   | j d}|jd}|jd}| jt|j| | jt|j| | jt|j| d S )Nr   r/   )r$   r   r   r   r   r  r  )r   r$   r   r   r   r   r   Ftest_insert_before_raises_notimplementederror_if_before_has_no_meaning  s    


z[TestTreeModification.test_insert_before_raises_notimplementederror_if_before_has_no_meaningc             C   sv   | j d}|jd\}}|j| | j|j | jd | j|jd  | j|j|j | j|jd | j|j	d d S )Nz;<p>There's <b>no</b> business like <b>show</b> business</p>r"   z0<p>There's  business like <b>no</b> business</p>noz	 business)
r$   r-   r   r   rj   r   r   r   r   r   )r   r$   r  Zshowr   r   r   test_replace_with  s    
z&TestTreeModification.test_replace_withc             C   s0   d}| j |}|jj|j | jd|j  d S )Nz<a><b></b><c></c></a>z<a><c></c></a>)r$   r"   r   rW   r   rj   )r   rk   r$   r   r   r   test_replace_first_child  s    
z-TestTreeModification.test_replace_first_childc             C   s0   d}| j |}|jj|j | jd|j  d S )Nz<a><b></b><c></c></a>z<a><b></b></a>)r$   rW   r   r"   r   rj   )r   rk   r$   r   r   r   test_replace_last_child  s    
z,TestTreeModification.test_replace_last_childc             C   s  | j d}|j}|j}|j| | j|j | jd | j|jd  | j|jddj	d  | j|j
d  | j|jd  | j|jd  | j|j|j | j|j
d | j|j	j	|j | j|jd  |jdd}|j}| j|j	| | j|j| | j|j
| | j|j| d S )NzQ<a>We<b>reserve<c>the</c><d>right</d></b></a><e>to<f>refuse</f><g>service</g></e>z-<a>We<f>refuse</f></a><e>to<g>service</g></e>r   )r)   ZWeZto)r$   r"   rr   r   r   rj   r   r   r%   r   r   r   r   r/   eg)r   r$   Z
remove_tagZmove_tagZto_textZg_tagr   r   r   test_nested_tag_replace_with  s.    

z1TestTreeModification.test_nested_tag_replace_withc             C   s6   | j d}|jj  | j|jd  | j|jjd d S )NzI
            <p>Unneeded <em>formatting</em> is unneeded</p>
            zUnneeded formatting is unneeded)r$   emr   r   r   r)   )r   rS   r   r   r   test_unwrap  s
    
z TestTreeModification.test_unwrapc             C   sF   | j d}|jj|jd}| j|j d | j|j | jd d S )NzI wish I was bold.r"   z<b>I wish I was bold.</b>)r$   r   wrapr   r   rj   r   )r   r$   rt   r   r   r   	test_wrap"  s
    
zTestTreeModification.test_wrapc             C   s4   | j d}|jjj|j | j|j | jd d S )Nz<b></b>I wish I was bold.z<b>I wish I was bold.</b>)r$   r"   r   r  r   rj   r   )r   r$   r   r   r   %test_wrap_extracts_tag_from_elsewhere)  s    
z:TestTreeModification.test_wrap_extracts_tag_from_elsewherec             C   sH   | j d}|jjj|j | jdt|jj | j|j | jd d S )Nz+<b>I like being bold.</b>I wish I was bold.r+   z+<b>I like being bold.I wish I was bold.</b>)	r$   r"   r   r  r   r,   r   rj   r   )r   r$   r   r   r   &test_wrap_puts_new_contents_at_the_end/  s    

z;TestTreeModification.test_wrap_puts_new_contents_at_the_endc             C   s   | j d}| jt|jjd |jddj }| j|j d | j|j d | jt|jjd | j|jd  | j|j	d  | j|j
j
d  |jdd	}|jd
d	}| j|j
| | j|j| | j|j	| | j|j| d S )NzR<html><body>Some content. <div id="nav">Nav crap</div> More content.</body></html>r9   Znav)r   z6<html><body>Some content.  More content.</body></html>z<div id="nav">Nav crap</div>r+   zSome content. )r)   z More content.)r$   r   r,   r   r   r%   r   rj   r   r   r   r   r   )r   r$   Z	extractedZ	content_1Z	content_2r   r   r   test_extract7  s"    z!TestTreeModification.test_extractc             C   sz   | j d}|jj}|jj}|jd}|jd}|jj| |jj| |j  |j  | j||jj | j||jj d S )Nz<a>foo</a><b>bar</b>rB   r3   )r$   r/   r   r"   r   rD   r   r   )r   r$   Zfoo_1Zbar_1Zfoo_2Zbar_2r   r   r   4test_extract_distinguishes_between_identical_stringsP  s    


zITestTreeModification.test_extract_distinguishes_between_identical_stringsc                s8   | j d  fdd jdD  | jdt j d S )Nzv
<html>
<head>
<script>foo</script>
</head>
<body>
 <script>bar</script>
 <a></a>
</body>
<script>baz</script>
</html>c                s   g | ]} j j qS r   )scriptr   )r   r   )r$   r   r   r   m  s    zKTestTreeModification.test_extract_multiples_of_same_tag.<locals>.<listcomp>r$  z<body>

<a></a>
</body>)r$   r-   r   r(   r   )r   r   )r$   r   "test_extract_multiples_of_same_taga  s    
z7TestTreeModification.test_extract_multiples_of_same_tagc             C   s.   | j d}|jdj  | jd |jd d S )Nz<html>
<body>hi</body>
</html>r   )r$   r%   r   r   )r   r$   r   r   r   Btest_extract_works_when_element_is_surrounded_by_identical_stringsq  s    zWTestTreeModification.test_extract_works_when_element_is_surrounded_by_identical_stringsc             C   sf   | j d}|j}|jj  | jt|jjd | jt|d |j	}|jdd | jdt|j dS )zTag.clear()z4<p><a>String <em>Italicized</em></a> and another</p>r   r   T)Z	decomposeN)
r$   r/   r   clearr   r,   r   rH   rI   r  )r   r$   r/   r  r   r   r   
test_clearz  s    

zTestTreeModification.test_clearc             C   sB   | j d}d|j_| j|jjdg d|j_| j|jjdg dS )zTag.string = 'string'z<a></a> <b><c></c></b>rB   r3   N)r$   r/   r   r   r   r"   )r   r$   r   r   r   test_string_set  s
    
z$TestTreeModification.test_string_setc             C   s,   | j d}|jj|j_| j|jj d d S )Nz<a><b>foo</b><c>bar</c>s   <a><b>bar</b><c>bar</c></a>)r$   rW   r   r"   r   r/   ri   )r   r$   r   r   r   /test_string_set_does_not_affect_original_string  s    
zDTestTreeModification.test_string_set_does_not_affect_original_stringc             C   s2   | j d}td}||j_| jt|jjt d S )Nz<a></a>rB   )r$   r   r/   r   rH   r   )r   r$   cdatar   r   r   )test_set_string_preserves_class_of_string  s    
z>TestTreeModification.test_set_string_preserves_class_of_stringN))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*  r,  r   r   r   r   r     sL   	
		
$	r   c               @   sx   e Zd Z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S )TestElementObjectsz)Test various features of element objects.c             C   sV   | j d}| jt|jd | jt|d | jt|jd | jt|jjd dS )z3The length of an element is its number of children.z<top>1<b>2</b>3</top>r=   r9   N)r$   r   r,   r   r   )r   r$   r   r   r   test_len  s
    
zTestElementObjects.test_lenc             C   sL   | j d}| j|j|jd | j|jj|jdjd | j|jd dS )z2Accessing a Python member .foo invokes find('foo')z<b><i></i></b>r"   r   N)r$   r   r"   r%   r   r/   )r   r$   r   r   r   test_member_access_invokes_find  s    
z2TestElementObjects.test_member_access_invokes_findc             C   sP   | j d}tjdd}|j}W d Q R X | j|j| | jdt|d j d S )Nz<b><i></i></b>T)recordzp.bTag is deprecated, use .find("b") instead. If you really were looking for a tag called bTag, use .find("bTag")r   )r$   warningscatch_warningsZbTagr   r"   r(   message)r   r$   wr   r   r   r   test_deprecated_member_access  s    
z0TestElementObjects.test_deprecated_member_accessc             C   s2   | j d}| j|jjd | j|jjd dS )zhas_attr() checks for the presence of an attribute.

        Please note note: has_attr() is different from
        __in__. has_attr() checks the tag's attributes and __in__
        checks the tag's chidlren.
        z<foo attr='bar'>attrZattr2N)r$   rH   rB   has_attrassertFalse)r   r$   r   r   r   test_has_attr  s    
z TestElementObjects.test_has_attrc             C   s   d}| j |d d S )Nz%<b a="1" z="5" m="3" f="2" y="4"></b>z%<b a="1" f="2" m="3" y="4" z="5"></b>)ZassertSoupEquals)r   r   r   r   r   .test_attributes_come_out_in_alphabetical_order  s    zATestElementObjects.test_attributes_come_out_in_alphabetical_orderc             C   s   | j d}| j|jjd d S )Nz
<b>foo</b>rB   )r$   r   r"   r   )r   r$   r   r   r   test_string  s    
zTestElementObjects.test_stringc             C   s   | j d}| j|jjd  d S )Nz<b></b>)r$   r   r"   r   )r   r$   r   r   r   test_empty_tag_has_no_string  s    
z/TestElementObjects.test_empty_tag_has_no_stringc             C   s`   | j d}| j|jjd  | j d}| j|jjd  | j d}|jjdd | j|jjd  d S )Nz<a>foo<b></b><b></b></b>z<a>foo<b></b>bar</b>z
<a>foo</b>r=   r3   )r$   r   r"   r   r/   r   )r   r$   r   r   r   -test_tag_with_multiple_children_has_no_string  s    


z@TestElementObjects.test_tag_with_multiple_children_has_no_stringc             C   s,   | j d}| j|jjd | j|jd d S )Nz<a><b>foo</b></a>rB   )r$   r   r/   r   )r   r$   r   r   r   )test_tag_with_recursive_string_has_string  s    
z<TestElementObjects.test_tag_with_recursive_string_has_stringc             C   s4   | j d}| j|jj | j d}| j|jj dS )z7Only a tag containing a single text node has a .string.z<b>f<i>e</i>o</b>z<b></b>N)r$   r8  r"   r   )r   r$   r   r   r   test_lack_of_string  s    

z&TestElementObjects.test_lack_of_stringc             C   s`   | j d}| j|jjd | j|jjddd | j|jjdd | j|jjdddd d	S )
zBTag.text and Tag.get_text(sep=u"") -> all child text, concatenatedz<a>a<b>r</b>   <r> t </r></a>zar  t T)stripZart,z	a,r, , t za,r,tN)r$   r   r/   r)   get_text)r   r$   r   r   r   test_all_text  s
    
z TestElementObjects.test_all_textc             C   sJ   | j d}| j|j d | j|jttfdd | j|jd dd d S )Nzfoo<!--IGNORE-->barZfoobar)typesZfooIGNOREbar)r$   r   rB  r   r   )r   r$   r   r   r   test_get_text_ignores_comments  s    
z1TestElementObjects.test_get_text_ignores_commentsc             C   s$   | j d}| jddgt|j d S )Nzfoo<!--IGNORE-->barrB   r3   )r$   r   r   Zstrings)r   r$   r   r   r   !test_all_strings_ignores_comments  s    
z4TestElementObjects.test_all_strings_ignores_commentsN)r   r   r    r1   r.  r/  r5  r9  r:  r;  r<  r=  r>  r?  rC  rE  rF  r   r   r   r   r-    s   		r-  c               @   sP   e Zd Z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S )TestCDAtaListAttributesz0Testing cdata-list attributes like 'class'.
    c             C   s"   | j d}| jdg|jd  d S )Nz<a class='foo'>rB   rm   )r$   r   r/   )r   r$   r   r   r   test_single_value_becomes_list  s    
z6TestCDAtaListAttributes.test_single_value_becomes_listc             C   s$   | j d}| jddg|jd  d S )Nz<a class='foo bar'>rB   r3   rm   )r$   r   r/   )r   r$   r   r   r   !test_multiple_values_becomes_list  s    
z9TestCDAtaListAttributes.test_multiple_values_becomes_listc             C   s&   | j d}| jdddg|jd  d S )Nz<a class='foo	bar
baz'>rB   r3   r   rm   )r$   r   r/   )r   r$   r   r   r   2test_multiple_values_separated_by_weird_whitespace  s    
zJTestCDAtaListAttributes.test_multiple_values_separated_by_weird_whitespacec             C   s    | j d}| jd|jj  d S )Nz<a class='foo	bar'>s   <a class="foo bar"></a>)r$   r   r/   ri   )r   r$   r   r   r   ,test_attributes_joined_into_string_on_output  s    
zDTestCDAtaListAttributes.test_attributes_joined_into_string_on_outputc             C   s$   | j d}| jdg|jjd d S )Nz<a id='abc def'>zabc defr   )r$   r   r/   Zget_attribute_list)r   r$   r   r   r   test_get_attribute_list  s    
z/TestCDAtaListAttributes.test_get_attribute_listc             C   s$   | j d}| jddg|jd  d S )Nz(<form accept-charset="ISO-8859-1 UTF-8">z
ISO-8859-1zUTF-8zaccept-charset)r$   r   Zform)r   r$   r   r   r   test_accept_charset!  s    
z+TestCDAtaListAttributes.test_accept_charsetc             C   s$   d}| j |}| jd|jd  d S )Nz)<a accept-charset="ISO-8859-1 UTF-8"></a>zISO-8859-1 UTF-8zaccept-charset)r$   r   r/   )r   rk   r$   r   r   r   -test_cdata_attribute_applying_only_to_one_tag%  s    
zETestCDAtaListAttributes.test_cdata_attribute_applying_only_to_one_tagc                s6   | j dj | jd  j  fdd}| jt| d S )Nr   c                  s
   d _ d S )NrB   )rN   r   )r   r   r   t0  s    zJTestCDAtaListAttributes.test_string_has_immutable_name_property.<locals>.t)r$   r   r   rN   r   AttributeError)r   rO  r   )r   r   'test_string_has_immutable_name_property-  s    z?TestCDAtaListAttributes.test_string_has_immutable_name_propertyN)r   r   r    r1   rH  rI  rJ  rK  rL  rM  rN  rQ  r   r   r   r   rG  	  s   rG  c                   s`   e Zd ZdZ f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  ZS )TestPersistencez*Testing features like pickle and deepcopy.c                s&   t t| j  d| _| j| j| _d S )Nay  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Beautiful Soup: We called him Tortoise because he taught us.</title>
<link rev="made" href="mailto:leonardr@segfault.org">
<meta name="Description" content="Beautiful Soup: an HTML parser optimized for screen-scraping.">
<meta name="generator" content="Markov Approximation 1.4 (module: leonardr)">
<meta name="author" content="Leonard Richardson">
</head>
<body>
<a href="foo">foo</a>
<a href="foo"><b>bar</b></a>
</body>
</html>)rQ   rR  rR   Zpager$   rS   )r   )rT   r   r   rR   7  s    zTestPersistence.setUpc             C   s@   t j| jd}t j|}| j|jt | j|j | jj  d S )Nr+   )pickledumpsrS   loadsr   rT   r   rj   )r   dumpedloadedr   r   r   !test_pickle_and_unpickle_identityK  s    
z1TestPersistence.test_pickle_and_unpickle_identityc             C   s&   t j| j}| j|j | jj  d S )N)copydeepcopyrS   r   rj   )r   Zcopiedr   r   r   test_deepcopy_identityS  s    z&TestPersistence.test_deepcopy_identityc             C   s:   t dd}|j}|j }| jdt| | j||j d S )Ns   <p>&nbsp;</p>zhtml.parseru	   <p> </p>)r   Zoriginal_encoding__copy__r   r(   )r   r$   encodingrY  r   r   r   test_copy_preserves_encodingX  s
    
z,TestPersistence.test_copy_preserves_encodingc             C   s>   d}| j |}tj|tj}tj|}| j|j |j  d S )Nu
   <b>☃</b>)r$   rS  rT  ZHIGHEST_PROTOCOLrU  r   rj   )r   r   r$   rV  rW  r   r   r   test_unicode_pickle_  s
    

z#TestPersistence.test_unicode_picklec             C   sz   d}| j |}|jdd}tj|}| j|| | jd |j | jd |j | jd |j | jd |j | jd |j d S )Nz<b>Foo<a></a></b><b>Bar</b>r4   )r   )	r$   r%   rY  r   r   r   assertNotEqualr   r   )r   r   r$   s1s2r   r   r   1test_copy_navigablestring_is_not_attached_to_treeg  s    

zATestPersistence.test_copy_navigablestring_is_not_attached_to_treec             C   s>   d}| j |}|j}tj|}| j|| | jt|t d S )Nz<b><!--Foo--></b>)r$   r   rY  r   rH   r   r   )r   r   r$   ra  rb  r   r   r   0test_copy_navigablestring_subclass_has_same_types  s    

z@TestPersistence.test_copy_navigablestring_subclass_has_same_typec             C   s(   d}| j |}tj|}| j|| d S )Nz)<div><b>Foo<a></a></b><b>Bar</b></div>end)r$   rY  r   )r   r   r$   Z	soup_copyr   r   r   test_copy_entire_soup{  s    

z%TestPersistence.test_copy_entire_soupc             C   s   d}| j |}|j}tj|}| jt|t| | j|| | j||k | jd |j | jd |j | jd |jddj	 | j
d |jddj	 d S )Nz)<div><b>Foo<a></a></b><b>Bar</b></div>endZBar)r   )r$   ra   rY  r   r(   r8  r   r   r%   r   r`  )r   r   r$   ra   Zdiv_copyr   r   r   test_copy_tag_copies_contents  s    

z-TestPersistence.test_copy_tag_copies_contents)r   r   r    r1   rR   rX  r[  r^  r_  rc  rd  re  rf  rc   r   r   )rT   r   rR  4  s   rR  c               @   s   e Z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!S )"TestSubstitutionsc             C   s0   d}| j |}|jdd}| j|| jd d S )Nu#   <b>&lt;&lt;Sacré bleu!&gt;&gt;</b>minimal)	formatter)r$   rj   r   r   )r   r   r$   decodedr   r   r   !test_default_formatter_is_minimal  s    
z3TestSubstitutions.test_default_formatter_is_minimalc             C   s0   d}| j |}|jdd}| j|| jd d S )Nu'   <br><b>&lt;&lt;Sacré bleu!&gt;&gt;</b>r   )ri  z.<br/><b>&lt;&lt;Sacr&eacute; bleu!&gt;&gt;</b>)r$   rj   r   r   )r   r   r$   rj  r   r   r   test_formatter_html  s    
z%TestSubstitutions.test_formatter_htmlc             C   s0   d}| j |}|jdd}| j|| jd d S )Nu'   <br><b>&lt;&lt;Sacré bleu!&gt;&gt;</b>Zhtml5)ri  z-<br><b>&lt;&lt;Sacr&eacute; bleu!&gt;&gt;</b>)r$   rj   r   r   )r   r   r$   rj  r   r   r   test_formatter_html5  s    
z&TestSubstitutions.test_formatter_html5c             C   s0   d}| j |}|jdd}| j|| jd d S )Nu#   <b>&lt;&lt;Sacré bleu!&gt;&gt;</b>rh  )ri  )r$   rj   r   r   )r   r   r$   rj  r   r   r   test_formatter_minimal  s    
z(TestSubstitutions.test_formatter_minimalc             C   s0   d}| j |}|jd d}| j|| jd d S )Nu#   <b>&lt;&lt;Sacré bleu!&gt;&gt;</b>)ri  u   <b><<Sacré bleu!>></b>)r$   rj   r   r   )r   r   r$   rj  r   r   r   test_formatter_null  s
    
z%TestSubstitutions.test_formatter_nullc             C   s4   d}| j |}|jdd d}| j|| jd d S )Nz!<b>&lt;foo&gt;</b><b>bar</b><br/>c             S   s   | j  S )N)upper)xr   r   r   <lambda>  s    z9TestSubstitutions.test_formatter_custom.<locals>.<lambda>)ri  z<b><FOO></b><b>BAR</b><br>)r$   rj   r   r   )r   r   r$   rj  r   r   r   test_formatter_custom  s    
z'TestSubstitutions.test_formatter_customc             C   s   d}| j |}|j}d}| j||j  | j||jdd d}| j||jdd | j||jd d d}| j||jdd	 d d S )
Nu%   <a href="http://a.com?a=b&c=é">e</a>u)   <a href="http://a.com?a=b&amp;c=é">e</a>rh  )ri  z/<a href="http://a.com?a=b&amp;c=&eacute;">e</a>r   u%   <a href="HTTP://A.COM?A=B&C=É">E</a>c             S   s   | j  S )N)rp  )rq  r   r   r   rr    s    zMTestSubstitutions.test_formatter_is_run_on_attribute_values.<locals>.<lambda>)r$   r/   r   rj   )r   r   r$   r/   Zexpect_minimalZexpect_htmlZexpect_upperr   r   r   )test_formatter_is_run_on_attribute_values  s    
z;TestSubstitutions.test_formatter_is_run_on_attribute_valuesc             C   s$   d}t |dj }| jd|k d S )NzO
  <script type="text/javascript">
   console.log("< < hey > > ");
  </script>
zhtml.parsers   < < hey > >)r   ri   rH   )r   r   encodedr   r   r   2test_formatter_skips_script_tag_for_html_documents  s    zDTestSubstitutions.test_formatter_skips_script_tag_for_html_documentsc             C   s$   d}t |dj }| jd|k d S )NzF
  <style type="text/css">
   console.log("< < hey > > ");
  </style>
zhtml.parsers   < < hey > >)r   ri   rH   )r   r   ru  r   r   r   1test_formatter_skips_style_tag_for_html_documents  s    zCTestSubstitutions.test_formatter_skips_style_tag_for_html_documentsc             C   s    | j d}| jd|jj  d S )Nz*<div>  foo  <pre>  	bar
  
  </pre>  baz  z/<div>
 foo
 <pre>  	bar
  
  </pre>
 baz
</div>)r$   r   ra   prettify)r   r$   r   r   r   ,test_prettify_leaves_preformatted_text_alone  s    
z>TestSubstitutions.test_prettify_leaves_preformatted_text_alonec             C   s,   t dd}|jdd d}| jd|k d S )Nz<html><body>foo</body></html>zhtml.parserc             S   s   | j  S )N)rp  )rq  r   r   r   rr    s    zLTestSubstitutions.test_prettify_accepts_formatter_function.<locals>.<lambda>)ri  ZFOO)r   rx  rH   )r   r$   Zprettyr   r   r   (test_prettify_accepts_formatter_function  s    
z:TestSubstitutions.test_prettify_accepts_formatter_functionc             C   s"   | j d}| jtt|j  d S )Nz<a></a>)r$   r   r(   typerx  )r   r$   r   r   r   (test_prettify_outputs_unicode_by_default  s    
z:TestSubstitutions.test_prettify_outputs_unicode_by_defaultc             C   s$   | j d}| jtt|jd d S )Nz<a></a>zutf-8)r$   r   bytesr{  rx  )r   r$   r   r   r   test_prettify_can_encode_data  s    
z/TestSubstitutions.test_prettify_can_encode_datac             C   s0   d}| j |}|jjd}| j||jd d S )Nu   <b>Sacré bleu!</b>zutf-8)r$   r"   ri   r   )r   r   r$   ru  r   r   r   ,test_html_entity_substitution_off_by_default  s    
z>TestSubstitutions.test_html_entity_substitution_off_by_defaultc             C   s   d}| j |}| j|jd d |jd}| jd|k |jd}| jd|k |jd}| jd	|k |jd
jd
}| jd|k d S )NzE<meta content="text/html; charset=x-sjis" http-equiv="Content-type"/>Zcontentztext/html; charset=x-sjiszutf-8s   charset=utf-8euc_jps   charset=euc_jpz	shift-jiss   charset=shift-jiszutf-16zcharset=utf-16)r$   r   metari   rH   rj   )r   Zmeta_tagr$   utf_8r  	shift_jisZutf_16_ur   r   r   test_encoding_substitution  s    



z,TestSubstitutions.test_encoding_substitutionc             C   s2   d}t d}| j||d}| j|jd jd d S )Nz`<head><meta content="text/html; charset=x-sjis" http-equiv="Content-type"/></head><pre>foo</pre>Zpre)Z
parse_onlyr   )r   r$   r   r   rN   )r   r   ry   r$   r   r   r   ;test_encoding_substitution_doesnt_happen_if_tag_is_strained$  s    zMTestSubstitutions.test_encoding_substitution_doesnt_happen_if_tag_is_strainedN)r   r   r    rk  rl  rm  rn  ro  rs  rt  rv  rw  ry  rz  r|  r~  r  r  r  r   r   r   r   rg    s    

	
		rg  c               @   sP   e Zd Z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S )TestEncodingz0Test the ability to encode objects into strings.c             C   s.   d}| j |}| j|jjjddjd d S )Nu
   <b>☃</b>zutf-8u   ☃)r$   r   r"   r   ri   )r   r   r$   r   r   r   "test_unicode_string_can_be_encoded2  s    
z/TestEncoding.test_unicode_string_can_be_encodedc             C   s,   d}| j |}| j|jjd|jd d S )Nu
   <b>☃</b>zutf-8)r$   r   r"   ri   )r   r   r$   r   r   r   1test_tag_containing_unicode_string_can_be_encoded8  s    
z>TestEncoding.test_tag_containing_unicode_string_can_be_encodedc             C   s&   d}| j |}| j|jjdd d S )Nu
   <b>☃</b>asciis   <b>&#9731;</b>)r$   r   r"   ri   )r   r   r$   r   r   r   <test_encoding_substitutes_unrecognized_characters_by_default>  s    
zITestEncoding.test_encoding_substitutes_unrecognized_characters_by_defaultc             C   s&   d}| j |}| jt|jddd d S )Nu
   <b>☃</b>r  strict)errors)r$   r   UnicodeEncodeErrorri   )r   r   r$   r   r   r    test_encoding_can_be_made_strictC  s    
z-TestEncoding.test_encoding_can_be_made_strictc             C   s$   d}| j |}| jd|jj  d S )Nu
   <b>☃</b>u   ☃)r$   r   r"   Zdecode_contents)r   r   r$   r   r   r   test_decode_contentsI  s    
z!TestEncoding.test_decode_contentsc             C   s.   d}| j |}| jdjd|jjdd d S )Nu
   <b>☃</b>u   ☃rg   )r]  )r$   r   ri   r"   Zencode_contents)r   r   r$   r   r   r   test_encode_contentsN  s
    
z!TestEncoding.test_encode_contentsc             C   s*   d}| j |}| jdjd|jj  d S )Nu
   <b>☃</b>u   ☃rg   )r$   r   ri   r"   ZrenderContents)r   r   r$   r   r   r   test_deprecated_renderContentsU  s    
z+TestEncoding.test_deprecated_renderContentsc             C   s8   d}| j |}tr$| j|t| n| jdt| d S )Nu
   <b>☃</b>s   <b>\u2603</b>)r$   r   r   repr)r   r   r$   r   r   r   	test_repr[  s
    
zTestEncoding.test_reprN)r   r   r    r1   r  r  r  r  r  r  r  r  r   r   r   r   r  /  s   r  c               @   s,   e Zd Zdd Zdd Zdd Zdd Zd	S )
TestNavigableStringSubclassesc             C   sX   | j d}td}|jd| | jt|d | j|jddd | j|jd d d S )Nr   rB   r=   z<![CDATA[foo]]>)r)   r   )r$   r   r   r   r(   r%   r   )r   r$   r+  r   r   r   
test_cdatae  s    
z(TestNavigableStringSubclasses.test_cdatac                sV   d _  fdd} jd}td}|jd|  jd|j|d  jd j  d	S )
zkText inside a CData object is passed into the formatter.

        But the return value is ignored.
        r   c                 s     j d7  _ dS )Nr=   zBITTER FAILURE)count)args)r   r   r   	incrementv  s    zNTestNavigableStringSubclasses.test_cdata_is_never_formatted.<locals>.incrementr   z<><><>r=   s   <![CDATA[<><><>]]>)ri  N)r  r$   r   r   r   ri   )r   r  r$   r+  r   )r   r   test_cdata_is_never_formattedo  s    
z;TestNavigableStringSubclasses.test_cdata_is_never_formattedc             C   s2   t d}| jd}|jd| | j|j d d S )NrB   r   r=   s   <!DOCTYPE foo>
)r
   r$   r   r   ri   )r   Zdoctyper$   r   r   r   test_doctype_ends_in_newline  s    
z:TestNavigableStringSubclasses.test_doctype_ends_in_newlinec             C   s   t d}| jd|j  d S )NrB   z<?foo?>)r	   r   Zoutput_ready)r   r	  r   r   r   test_declaration  s    z.TestNavigableStringSubclasses.test_declarationN)r   r   r    r  r  r  r  r   r   r   r   r  c  s   
r  c               @   s  e 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.d/ Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Z d:d; Z!d<d= Z"d>d? Z#d@dA Z$dBdC Z%dDdE Z&dFdG Z'dHdI Z(dJdK Z)dLdM Z*dNdO Z+dPdQ Z,dRdS Z-dTdU Z.dVdW Z/dXdY Z0dZd[ Z1d\d] Z2d^d_ Z3d`da Z4dbdc Z5ddde Z6dfdg Z7dhdi Z8djdk Z9dldm Z:dndo Z;dpdq Z<drds Z=dtS )uTestSoupSelectora  
<!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   HTMLr$   )r   r   r   r   rR     s    zTestSoupSelector.setUpc             K   sR   dd | j j|f|D }|j  |j  | j||d|dj|dj|f  d S )Nc             S   s   g | ]}|d  qS )r   r   )r   elr   r   r   r     s    z2TestSoupSelector.assertSelects.<locals>.<listcomp>z$Selector %s, expected [%s], got [%s]z, )r$   selectsortr   join)r   selectorexpected_idskwargsZel_idsr   r   r   r     s    zTestSoupSelector.assertSelectsc             G   s"   x|D ]\}}| j || qW d S )N)assertSelect)r   Ztestsr  r  r   r   r   assertSelectMultiple  s    z%TestSoupSelector.assertSelectMultiplec             C   sF   | j jd}| jt|d | j|d jd | j|d jdg d S )Nrh   r=   r   z	The title)r$   r  r   r,   rN   r   )r   elsr   r   r   test_one_tag_one  s    z!TestSoupSelector.test_one_tag_onec             C   sX   | j jd}| jt|d x|D ]}| j|jd q"W | j jd}| jd|d  d S )Nra      mainr   )r$   r  r   r,   rN   
select_one)r   r  ra   r  r   r   r   test_one_tag_many  s    
z"TestSoupSelector.test_one_tag_manyc             C   s   | j jd}| jd | d S )NZnonexistenttag)r$   r  r   )r   matchr   r   r   (test_select_one_returns_none_if_no_match  s    z9TestSoupSelector.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$TestSoupSelector.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 divr  r  r  footer)r  r  r  )r   )r   r  r   r   r   test_tag_in_tag_many  s    
z%TestSoupSelector.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=   )r:   zhtml body divr  r+   zbody divr  r  r>   )r   )r   r   r   r   
test_limit  s    zTestSoupSelector.test_limitc             C   s   | j t| jjdd d S )Ndelr   )r   r,   r$   r  )r   r   r   r   test_tag_no_match  s    z"TestSoupSelector.test_tag_no_matchc             C   s   | j t| jjd d S )Nztag%t)r   r   r$   r  )r   r   r   r   test_invalid_tag  s    z!TestSoupSelector.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+TestSoupSelector.test_select_dashed_tag_idsc             C   s6   | j jd}| j|d jd | j|d d d d S )Nzcustom-dashed-tag[id="dash2"]r   zcustom-dashed-tagr   r  )r$   r  r   rN   )r   Zdashedr   r   r   test_select_dashed_by_id  s    z)TestSoupSelector.test_select_dashed_by_idc             C   s   | j | jjdd jd d S )Nzbody > custom-dashed-tagr   zHello there.)r   r$   r  r)   )r   r   r   r   test_dashed_tag_text  s    z%TestSoupSelector.test_dashed_tag_textc             C   s    | j | jjd| jjd d S )Nzcustom-dashed-tag)r   r$   r  r-   )r   r   r   r   #test_select_dashed_matches_find_all  s    z4TestSoupSelector.test_select_dashed_matches_find_allc             C   s   | j ddgfdddgf d S )NZh1header1Zh2header2header3)r  )r   r   r   r   test_header_tags
  s    z!TestSoupSelector.test_header_tagsc             C   sV   xPd	D ]H}| j j|}| jt|d | j|d jd | j|d d dg qW d S )
N.onepp.onephtml p.onepr=   r   r   rm   onep)r  r  r  )r$   r  r   r,   rN   )r   r  r  r   r   r   test_class_one  s
    
zTestSoupSelector.test_class_onec             C   s    | j jd}| jt|d d S )Nzdiv.onepr   )r$   r  r   r,   )r   r  r   r   r   test_class_mismatched_tag  s    z*TestSoupSelector.test_class_mismatched_tagc             C   s    xdD ]}| j |dg qW d S )N	div#inner#innerdiv div#innerr  )r  r  r  )r   )r   r  r   r   r   test_one_id  s    
zTestSoupSelector.test_one_idc             C   s    | j jd}| jt|d d S )Nz#doesnotexistr   )r$   r  r   r,   )r   r  r   r   r   test_bad_id  s    zTestSoupSelector.test_bad_idc             C   sf   | j jd}| jt|d x|D ]}| j|jd q"W | j|d d dg | j|d jd d S )Nzdiv#inner pr9   r   r=   rm   r  r   )r$   r  r   r,   rN   r8  r7  )r   r  r  r   r   r   test_items_in_id#  s    
z!TestSoupSelector.test_items_in_idc             C   s*   x$dD ]}| j t| jj|d qW d S )Ndiv#main deldiv#main div.oopsdiv div#mainr   )r  r  r  )r   r,   r$   r  )r   r  r   r   r   test_a_bunch_of_emptys+  s    
z'TestSoupSelector.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)r  r  r  r  r  r  r  r  )r   )r   r  r   r   r   test_multi_class_support/  s    z)TestSoupSelector.test_multi_class_supportc             C   s    xdD ]}| j |dg qW d S )N.class1.class3.class3.class2.class1.class2.class3r  )r  r  r  )r   )r   r  r   r   r   test_multi_class_selection4  s    z+TestSoupSelector.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_selector9  s    z$TestSoupSelector.test_child_selectorc             C   s   | j ddg d S )Nz.s1 > a#s1a2 spanr  )r   )r   r   r   r   test_child_selector_id=  s    z'TestSoupSelector.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"]r   z
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&TestSoupSelector.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"]r  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_tildeR  s    z%TestSoupSelector.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"]r  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"]r  r   z	[id^="m"]r  zdiv[id^="m"]z
a[id^="m"]zdiv[data-tag^="dashed"]r  )r  )r   r   r   r   test_attribute_startswith`  s    



z*TestSoupSelector.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"]r  zlink[href$=".css"]zlink[id$="1"]z	[id$="1"]r  r   r  r  s2a1r  r  zdiv[id$="1"]z[id$="noending"])r  )r   r   r   r   test_attribute_endswithq  s    z(TestSoupSelector.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"]r  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"]r  r   zdiv[id*="m"]r  z
a[id*="m"]z[href*=".css"]zlink[href*=".css"]zlink[id*="1"]z	[id*="1"]r  r  r  r  r  r  r  zdiv[id*="1"]z[id*="noending"]z[href*="."]za[href*="."]zlink[href*="."]zdiv[id*="n"]r  zdiv[id*="nn"]zdiv[data-tag*="edval"])r  )r   r   r   r   test_attribute_contains{  s.    



z(TestSoupSelector.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_hypen  s
    z.TestSoupSelector.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]r  r  r  z	link[rel]za[rel]z[lang]zlang-enz
lang-en-gbz
lang-en-uszlang-frzp[class]r   r  z[blah]zp[blah]zdiv[data-tag]r  )r  )r   r   r   r   test_attribute_exists  s    

z&TestSoupSelector.test_attribute_existsc             C   s,   d}t |d}|jd\}| jd|j 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  r   r   )r   r   r$   Zchosenr   r   r   "test_quoted_space_in_selector_name  s    
z3TestSoupSelector.test_quoted_space_in_selector_namec             C   s(   | j t| jjd | j t| jjd d S )Nza:no-such-pseudoclassza:nth-of-type(a))r   r  r$   r  )r   r   r   r   test_unsupported_pseudoclass  s    z-TestSoupSelector.test_unsupported_pseudoclassc             C   s   | j jd}| jt|d | j|d jd | j jd}| jt|d | j|d jd | j jd}| jt|d | jt| j jd 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   r   r   test_nth_of_type  s    z!TestSoupSelector.test_nth_of_typec             C   s2   | j jd}| jt|d | j|d jd 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_descendant  s    z3TestSoupSelector.test_nth_of_type_direct_descendantc             C   s   | j ddg d S )Nz#inner > p:nth-of-type(2)r   )r   )r   r   r   r   "test_id_child_selector_nth_of_type  s    z3TestSoupSelector.test_id_child_selector_nth_of_typec             C   s.   | j jddd}|jd}| j|ddg d S )Nra   r  )r   r  r  )r$   r%   r  r   )r   r  selectedr   r   r   test_select_on_element  s    
z'TestSoupSelector.test_select_on_elementc             C   s   | j ddg | j dg  d S )Nz.fancy #innerr  z.normal #inner)r   )r   r   r   r   test_overspecified_child_id  s    z,TestSoupSelector.test_overspecified_child_idc             C   sB   | j ddg | j ddg | j ddg | jg | jjd d S )Nz#p1 + h2r  z#p1 + h2 + pr  z#p1 + #header2 + .class1z#p1 + p)r   r   r$   r  )r   r   r   r   test_adjacent_sibling_selector  s    z/TestSoupSelector.test_adjacent_sibling_selectorc             C   sR   | j dddg | j ddg | j ddg | j ddg | jg | jjd d S )	Nz#p1 ~ h2r  r  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.TestSoupSelector.test_general_sibling_selectorc             C   s   | j t| jjd d S )Nzh1 >)r   r   r$   r  )r   r   r   r   test_dangling_combinator  s    z)TestSoupSelector.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    zCTestSoupSelector.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%TestSoupSelector.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    z3TestSoupSelector.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    z5TestSoupSelector.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    z0TestSoupSelector.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-TestSoupSelector.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?TestSoupSelector.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@TestSoupSelector.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    z9TestSoupSelector.test_multiple_select_indirect_descendantc             C   s(   | j t| jjd | j t| jjd d S )Nz,x, yzx,,y)r   r   r$   r  )r   r   r   r   test_invalid_multiple_select  s    z-TestSoupSelector.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+TestSoupSelector.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)TestSoupSelector.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,TestSoupSelector.test_multiple_select_nestedc             C   sR   d}t |d}|jd}| jd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, .c2r9   Zc1Zc2)ro   )r   r  r   r,   r-   r   )r   r   r$   r  r   r   r   r   test_select_duplicate_elements  s    

z/TestSoupSelector.test_select_duplicate_elementsN)>r   r   r    r  rR   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  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r   r   r   r    sv   1
	
	r  )2r1   Zpdbr   rY  rS  r6   r1  Zbs4r   Zbs4.builderr   r   Zbs4.elementr   r   r   r	   r
   r   r   r   Zbs4.testingr   r   r   r   ZLXML_PRESENTr   r!   r2   rL   rP   rd   r   r   r   r   r   r   r   r   r   r   r-  rG  rR  rg  r  r  r  r   r   r   r   <module>   sN   (
;O 83(3--*   6n+a 4*