
    i)                         d Z ddlmZmZmZ ddlmZ  G d d          Z G d d          Z G d d	          Z	 G d
 d          Z
 G d d          ZdS )a  Tests for custom component parsing and handling.

Custom components include:
- X-Components (vendor-specific, starting with X-)
- IANA-Components (registered but not in RFC 5545)
- Any unrecognized component names

According to RFC 5545:
- Applications MUST ignore custom components they don't recognize
- Applications SHOULD NOT silently drop components (data loss prevention)

icalendar preserves all custom components through dynamic component creation.
    )Calendar	ComponentEvent)ComponentFactoryc                   *    e Zd ZdZd Zd Zd Zd ZdS )TestComponentFactoryz3Test ComponentFactory's dynamic component creation.c                     t                      }|                    d          }|j        dk    sJ |j        dk    sJ dS )z4Factory creates component classes for unknown names.zMy-ComponentzMY-COMPONENTMyComponentN)r   get_component_classname__name__)selffactorymy_component_classs      a/root/projects/butler/venv/lib/python3.11/site-packages/icalendar/tests/test_custom_components.py"test_create_custom_component_classz7TestComponentFactory.test_create_custom_component_class   sO    "$$$88HH!&.8888!*m;;;;;;    c                 z    t                      }|                    d          }t          |t                    sJ dS )z6Dynamically created components inherit from Component.X-CUSTOMN)r   r   
issubclassr   )r   r   custom_classs      r   -test_custom_component_inherits_from_componentzBTestComponentFactory.test_custom_component_inherits_from_component   s<    "$$22:>>,	2222222r   c                     t                      }|                    d          }|                    d          }||u sJ dS )z1Factory returns same class for repeated requests.X-VENDORN)r   r   )r   r   class1class2s       r   %test_factory_caches_component_classesz:TestComponentFactory.test_factory_caches_component_classes#   sJ    "$$,,Z88,,Z88r   c                     t                      }|                    d          }|j        dk    sJ |j        dk    sJ dS )z7Factory sanitizes non-alphanumeric characters in names.zX-MY-COMPONENTXMYCOMPONENTN)r   r   r   r   )r   r   component_classs      r   test_sanitizes_component_namesz3TestComponentFactory.test_sanitizes_component_names*   sP    "$$!556FGG'>9999#'7777777r   N)r   
__module____qualname____doc__r   r   r   r!    r   r   r   r      sV        ==< < <3 3 3     8 8 8 8 8r   r   c                   6    e Zd ZdZd Zd Zd Zd Zd Zd Z	dS )	(TestCustomComponentWithComponentFromIcalz;Test parsing custom components using Component.from_ical().c                 R    |j         }|                                |j        k    sJ dS )z1Parse a standalone custom component (issue #178).N)1issue_178_component_with_invalid_name_representedto_icalraw_icsr   	calendarscalendars      r   &test_parse_standalone_custom_componentzOTestCustomComponentWithComponentFromIcal.test_parse_standalone_custom_component6   s2     N!!X%5555555r   c                 L    d}t          j        |          }|j        dk    sJ dS )z#Custom component name is preserved.s(   BEGIN:X-MYCOMPONENT
END:X-MYCOMPONENT
zX-MYCOMPONENTNr   	from_icalr   r   ics_datacomps      r   $test_custom_component_preserves_namezMTestCustomComponentWithComponentFromIcal.test_custom_component_preserves_name=   s0    B"8,,yO++++++r   c                     d}t          j        |          }|j        dk    sJ |d         dk    sJ |d         dk    sJ |d         dk    sJ d	S )
z&Custom components can have properties.sd   BEGIN:X-VENDOR
SUMMARY:Vendor Component
X-VENDOR-PROP:proprietary value
UID:vendor-123
END:X-VENDOR
r   SUMMARYzVendor ComponentzX-VENDOR-PROPzproprietary valueUIDz
vendor-123Nr1   r3   s      r   %test_custom_component_with_propertieszNTestCustomComponentWithComponentFromIcal.test_custom_component_with_propertiesC   sv     "8,,yJ&&&&I"44444O$(;;;;;E{l******r   c                 ~    d}t          j        |          }|                                }d|v sJ d|v sJ d|v sJ dS )z-Custom components survive round-trip parsing.s(   BEGIN:X-TEST
SUMMARY:Test
END:X-TEST
s   BEGIN:X-TESTs   SUMMARY:Tests
   END:X-TESTN)r   r2   r*   )r   originalr5   regenerateds       r    test_custom_component_round_tripzITestCustomComponentWithComponentFromIcal.test_custom_component_round_tripQ   s]    D"8,,llnn+----+----++++++r   c                 R    |j         }|                                |j        k    sJ dS )z>Custom component can contain standard components (issue #178).N))issue_178_custom_component_contains_otherr*   r+   r,   s      r   5test_custom_component_can_contain_standard_componentsz^TestCustomComponentWithComponentFromIcal.test_custom_component_can_contain_standard_componentsZ   s2     F!!X%5555555r   c                     d}t          j        |          }|j        dk    sJ t          |j                  dk    sJ |j        d         }|j        dk    sJ |d         dk    sJ |d         d	k    sJ d
S )z)Parse custom component containing VEVENT.s   BEGIN:X-CONTAINER
SUMMARY:Container
BEGIN:VEVENT
UID:event-1
DTSTART:20240101T120000Z
SUMMARY:Event inside custom
END:VEVENT
END:X-CONTAINER
X-CONTAINER   r   VEVENTr9   zevent-1r8   zEvent inside customN)r   r2   r   lensubcomponents)r   r4   	containerevents       r   ,test_parse_custom_component_containing_eventzUTestCustomComponentWithComponentFromIcal.test_parse_custom_component_containing_event`   s     '11	~....9*++q0000'*zX%%%%U|y((((Y#8888888r   N)
r   r"   r#   r$   r/   r6   r:   r>   rA   rJ   r%   r   r   r'   r'   3   st        EE6 6 6, , ,+ + +, , ,6 6 69 9 9 9 9r   r'   c                   *    e Zd ZdZd Zd Zd Zd ZdS )'TestCustomComponentWithCalendarFromIcalz:Test parsing custom components using Calendar.from_ical().c                 R    |j         }|                                |j        k    sJ dS )z4Calendar can contain custom components (issue #178).N)'issue_178_custom_component_inside_otherr*   r+   r,   s      r   #test_calendar_with_custom_componentzKTestCustomComponentWithCalendarFromIcal.test_calendar_with_custom_componentw   s2     D!!X%5555555r   c                     d}t          j        |          }t          |j                  dk    sJ |j        d         }|j        dk    sJ |d         dk    sJ dS )z,Parse VCALENDAR containing custom component.s   BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Test//EN
BEGIN:X-CUSTOM
UID:custom-1
SUMMARY:Custom component in calendar
END:X-CUSTOM
END:VCALENDAR
rD   r   r   r9   zcustom-1N)r   r2   rF   rG   r   )r   r4   calcustoms       r   /test_parse_calendar_containing_custom_componentzWTestCustomComponentWithCalendarFromIcal.test_parse_calendar_containing_custom_component}   sr      **3$%%****"1%{j((((e}
******r   c                     d}t          j        |          }t          |j                  dk    sJ d |j        D             }d|v sJ d|v sJ d|v sJ dS )z0Calendar can mix standard and custom components.s   BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Test//EN
BEGIN:VEVENT
UID:event-1
DTSTART:20240101T120000Z
SUMMARY:Standard event
END:VEVENT
BEGIN:X-VENDOR
UID:vendor-1
X-PROP:value
END:X-VENDOR
BEGIN:VTODO
UID:todo-1
SUMMARY:Standard todo
END:VTODO
END:VCALENDAR
   c                     g | ]	}|j         
S r%   r   .0r5   s     r   
<listcomp>zsTestCustomComponentWithCalendarFromIcal.test_calendar_with_mixed_standard_and_custom_components.<locals>.<listcomp>   s    999t999r   rE   r   VTODONr   r2   rF   rG   )r   r4   rQ   namess       r   7test_calendar_with_mixed_standard_and_custom_componentsz_TestCustomComponentWithCalendarFromIcal.test_calendar_with_mixed_standard_and_custom_components   s    $  **3$%%**** :9s'89995    U""""%r   c                 r    d}t          j        |          }|                                }d|v sJ d|v sJ dS )z1Custom components in calendar survive round-trip.sg   BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Test//EN
BEGIN:X-MYAPP
X-SETTING:value
END:X-MYAPP
END:VCALENDAR
s   BEGIN:X-MYAPPs   X-SETTING:valueNr   r2   r*   )r   r<   rQ   r=   s       r   ,test_custom_component_round_trip_in_calendarzTTestCustomComponentWithCalendarFromIcal.test_custom_component_round_trip_in_calendar   sP      **kkmm;....![000000r   N)r   r"   r#   r$   rO   rS   r^   ra   r%   r   r   rL   rL   t   sV        DD6 6 6+ + +"     :1 1 1 1 1r   rL   c                   *    e Zd ZdZd Zd Zd Zd ZdS )TestCustomComponentAPIz=Test that custom components work with standard Component API.c                     t          d          }|                    dd           |                    dd           |d         dk    sJ |d         dk    sJ d	S )
z'Can add properties to custom component.X-TESTrW   summaryzTest Summaryzx-customzCustom Valuer8   r   N)r   addr   r5   s     r   %test_add_property_to_custom_componentz<TestCustomComponentAPI.test_add_property_to_custom_component   sk    h'''N+++^,,,I.0000J>111111r   c                 (   t          d          }t                      }|                    dd           |                    dd           |                    |           t	          |j                  dk    sJ |j        d         j        d	k    sJ d
S )z*Can add subcomponents to custom component.rC   rW   uid123rf   z
Test EventrD   r   rE   N)r   r   rg   add_componentrF   rG   r   )r   rH   rI   s      r   )test_add_subcomponent_to_custom_componentz@TestCustomComponentAPI.test_add_subcomponent_to_custom_component   s    =111			%		)\***&&&9*++q0000&q).(::::::r   c                    t          d          }|                    dd           |                    dd           t          |                                          }d |D             }d|v sJ d	|v sJ d
|v sJ d|v sJ dS )z0Can iterate over properties in custom component.re   rW   prop1value1prop2value2c                     g | ]\  }}|S r%   r%   )rY   r   values      r   rZ   zJTestCustomComponentAPI.test_custom_component_iteration.<locals>.<listcomp>   s    444{tUd444r   PROP1PROP2BEGINENDN)r   rg   listproperty_items)r   r5   props
prop_namess       r   test_custom_component_iterationz6TestCustomComponentAPI.test_custom_component_iteration   s    h'''(###(### T((**++44e444
*$$$$*$$$$*$$$$
""""""r   c                     t          d          }|                    dd           |                    d          dk    sJ |                    d          J |                    dd          dk    sJ dS )	z)Can use get() method on custom component.re   rW   existingru   EXISTINGNONEXISTENTNdefault)r   rg   getrh   s     r    test_custom_component_get_methodz7TestCustomComponentAPI.test_custom_component_get_method   s    h'''W%%%xx
##w....xx&&...xxy11Y>>>>>>r   N)r   r"   r#   r$   ri   rn   r~   r   r%   r   r   rc   rc      sV        GG2 2 2	; 	; 	;# # #? ? ? ? ?r   rc   c                   *    e Zd ZdZd Zd Zd Zd ZdS )TestRFC5545Compliancez/Test RFC 5545 compliance for custom components.c                 r    d}t          j        |          }|                                }d|v sJ d|v sJ dS )z-X-components (vendor-specific) are preserved.sj   BEGIN:VCALENDAR
VERSION:2.0
BEGIN:X-VENDOR-COMP
X-VENDOR-PROP:proprietary
END:X-VENDOR-COMP
END:VCALENDAR
s   X-VENDOR-COMPs   X-VENDOR-PROPNr`   r   r4   rQ   r=   s       r   test_preserves_x_componentsz1TestRFC5545Compliance.test_preserves_x_components   sR      **kkmm  ;....;......r   c                 r    d}t          j        |          }|                                }d|v sJ d|v sJ dS )z)IANA-registered components are preserved.so   BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VFUTURE
UID:future-1
SUMMARY:Future IANA component
END:VFUTURE
END:VCALENDAR
s   VFUTUREs   Future IANA componentNr`   r   s       r   test_preserves_iana_componentsz4TestRFC5545Compliance.test_preserves_iana_components   sR      **kkmm [((((';666666r   c                     d}t          j        |          }t          |j                  dk    sJ d |j        D             }|h dk    sJ dS )z8Custom components are never silently dropped (RFC 5545).s   BEGIN:VCALENDAR
VERSION:2.0
BEGIN:X-UNKNOWN1
UID:1
END:X-UNKNOWN1
BEGIN:X-UNKNOWN2
UID:2
END:X-UNKNOWN2
BEGIN:UNKNOWN3
UID:3
END:UNKNOWN3
END:VCALENDAR
rU   c                     h | ]	}|j         
S r%   rW   rX   s     r   	<setcomp>zVTestRFC5545Compliance.test_does_not_silently_drop_custom_components.<locals>.<setcomp>!  s    CCC49CCCr   >   
X-UNKNOWN1
X-UNKNOWN2UNKNOWN3Nr\   )r   r4   rQ   component_namess       r   -test_does_not_silently_drop_custom_componentszCTestRFC5545Compliance.test_does_not_silently_drop_custom_components  sm      ** 3$%%****CC1BCCC"J"J"JJJJJJJr   c                    d}t          j        |          }|j        dk    sJ t          |j                  dk    sJ |j        d         }|j        dk    sJ |d         dk    sJ |                                }t          j        |          }t          |j                  dk    sJ |j        d         j        dk    sJ dS )	z-Nested custom components are fully preserved.sP   BEGIN:X-OUTER
SUMMARY:Outer
BEGIN:X-INNER
SUMMARY:Inner
END:X-INNER
END:X-OUTER
zX-OUTERrD   r   zX-INNERr8   InnerN)r   r2   r   rF   rG   r*   )r   r4   outerinnerr=   reparseds         r   'test_nested_custom_components_preservedz=TestRFC5545Compliance.test_nested_custom_components_preserved$  s     #H--zY&&&&5&''1,,,,#A&zY&&&&Y7**** mmoo&{338)**a////%a(-::::::r   N)r   r"   r#   r$   r   r   r   r   r%   r   r   r   r      sY        99/ / / 7 7 7$K K K,; ; ; ; ;r   r   N)r$   	icalendarr   r   r   icalendar.cal.component_factoryr   r   r'   rL   rc   r   r%   r   r   <module>r      s)    1 0 0 0 0 0 0 0 0 0 < < < < < <8 8 8 8 8 8 8 8@>9 >9 >9 >9 >9 >9 >9 >9BD1 D1 D1 D1 D1 D1 D1 D1N+? +? +? +? +? +? +? +?\P; P; P; P; P; P; P; P; P; P;r   