o
    .j)                     @   sn   d Z ddlmZmZmZ ddlmZ G dd dZG dd dZG dd	 d	Z	G d
d dZ
G d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                   @   0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )TestComponentFactoryz3Test ComponentFactory's dynamic component creation.c                 C   s0   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_class r   [/home/thesage/.local/lib/python3.10/site-packages/icalendar/tests/test_custom_components.py"test_create_custom_component_class   s   
z7TestComponentFactory.test_create_custom_component_classc                 C   s"   t  }|d}t|tsJ dS )z6Dynamically created components inherit from Component.X-CUSTOMN)r   r	   
issubclassr   )r   r   custom_classr   r   r   -test_custom_component_inherits_from_component   s   
zBTestComponentFactory.test_custom_component_inherits_from_componentc                 C   s*   t  }|d}|d}||u sJ dS )z1Factory returns same class for repeated requests.X-VENDORN)r   r	   )r   r   class1class2r   r   r   %test_factory_caches_component_classes#   s   

z:TestComponentFactory.test_factory_caches_component_classesc                 C   s0   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_classr   r   r   test_sanitizes_component_names*   s   
z3TestComponentFactory.test_sanitizes_component_namesN)r   
__module____qualname____doc__r   r   r   r   r   r   r   r   r      s    r   c                   @   s@   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S )(TestCustomComponentWithComponentFromIcalz;Test parsing custom components using Component.from_ical().c                 C      |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calendarr   r   r   &test_parse_standalone_custom_component6   s   zOTestCustomComponentWithComponentFromIcal.test_parse_standalone_custom_componentc                 C   s    d}t |}|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compr   r   r   $test_custom_component_preserves_name=   s   
zMTestCustomComponentWithComponentFromIcal.test_custom_component_preserves_namec                 C   sP   d}t |}|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-123Nr)   r+   r   r   r   %test_custom_component_with_propertiesC   s   
zNTestCustomComponentWithComponentFromIcal.test_custom_component_with_propertiesc                 C   s>   d}t |}| }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   r*   r#   )r   originalr-   regeneratedr   r   r    test_custom_component_round_tripQ   s   
zITestCustomComponentWithComponentFromIcal.test_custom_component_round_tripc                 C   r!   )z>Custom component can contain standard components (issue #178).N))issue_178_custom_component_contains_otherr#   r$   r%   r   r   r   5test_custom_component_can_contain_standard_componentsZ      z^TestCustomComponentWithComponentFromIcal.test_custom_component_can_contain_standard_componentsc                 C   sj   d}t |}|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s3J 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   VEVENTr0   zevent-1r/   zEvent inside customN)r   r*   r
   lensubcomponents)r   r,   	containereventr   r   r   ,test_parse_custom_component_containing_event`   s   
	
zUTestCustomComponentWithComponentFromIcal.test_parse_custom_component_containing_eventN)
r   r   r   r   r(   r.   r1   r4   r6   r?   r   r   r   r   r    3   s    	r    c                   @   r   )'TestCustomComponentWithCalendarFromIcalz:Test parsing custom components using Calendar.from_ical().c                 C   r!   )z4Calendar can contain custom components (issue #178).N)'issue_178_custom_component_inside_otherr#   r$   r%   r   r   r   #test_calendar_with_custom_componentw   r7   zKTestCustomComponentWithCalendarFromIcal.test_calendar_with_custom_componentc                 C   sL   d}t |}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
r9   r   r   r0   zcustom-1N)r   r*   r;   r<   r
   )r   r,   calcustomr   r   r   /test_parse_calendar_containing_custom_component}   s   
	
zWTestCustomComponentWithCalendarFromIcal.test_parse_calendar_containing_custom_componentc                 C   sX   d}t |}t|jdksJ d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                 S   s   g | ]}|j qS r   r
   .0r-   r   r   r   
<listcomp>       zsTestCustomComponentWithCalendarFromIcal.test_calendar_with_mixed_standard_and_custom_components.<locals>.<listcomp>r:   r   VTODONr   r*   r;   r<   )r   r,   rC   namesr   r   r   7test_calendar_with_mixed_standard_and_custom_components   s   
z_TestCustomComponentWithCalendarFromIcal.test_calendar_with_mixed_standard_and_custom_componentsc                 C   2   d}t |}| }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   r*   r#   )r   r2   rC   r3   r   r   r   ,test_custom_component_round_trip_in_calendar   s
   
zTTestCustomComponentWithCalendarFromIcal.test_custom_component_round_trip_in_calendarN)r   r   r   r   rB   rE   rO   rR   r   r   r   r   r@   t   s    r@   c                   @   r   )TestCustomComponentAPIz=Test that custom components work with standard Component API.c                 C   sF   t d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-TESTrG   summaryzTest Summaryzx-customzCustom Valuer/   r   N)r   addr   r-   r   r   r   %test_add_property_to_custom_component   s
   
z<TestCustomComponentAPI.test_add_property_to_custom_componentc                 C   s\   t d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.r8   rG   uid123rU   z
Test Eventr9   r   r:   N)r   r   rV   add_componentr;   r<   r
   )r   r=   r>   r   r   r   )test_add_subcomponent_to_custom_component   s   

z@TestCustomComponentAPI.test_add_subcomponent_to_custom_componentc                 C   sp   t dd}|dd |dd t| }dd |D }d	|v s$J d
|v s*J d|v s0J d|v s6J dS )z0Can iterate over properties in custom component.rT   rG   prop1value1prop2value2c                 S   s   g | ]\}}|qS r   r   )rI   r
   valuer   r   r   rJ      s    zJTestCustomComponentAPI.test_custom_component_iteration.<locals>.<listcomp>PROP1PROP2BEGINENDN)r   rV   listproperty_items)r   r-   props
prop_namesr   r   r   test_custom_component_iteration   s   
z6TestCustomComponentAPI.test_custom_component_iterationc                 C   sR   t dd}|dd |ddksJ |ddu sJ |dddks'J dS )	z)Can use get() method on custom component.rT   rG   existingra   EXISTINGNONEXISTENTNdefault)r   rV   getrW   r   r   r    test_custom_component_get_method   s
   
z7TestCustomComponentAPI.test_custom_component_get_methodN)r   r   r   r   rX   r\   rj   rp   r   r   r   r   rS      s    rS   c                   @   r   )TestRFC5545Compliancez/Test RFC 5545 compliance for custom components.c                 C   rP   )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-PROPNrQ   r   r,   rC   r3   r   r   r   test_preserves_x_components   s
   
z1TestRFC5545Compliance.test_preserves_x_componentsc                 C   rP   )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 componentNrQ   rr   r   r   r   test_preserves_iana_components   s
   
z4TestRFC5545Compliance.test_preserves_iana_componentsc                 C   sD   d}t |}t|jdksJ d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
rF   c                 S   s   h | ]}|j qS r   rG   rH   r   r   r   	<setcomp>!  rK   zVTestRFC5545Compliance.test_does_not_silently_drop_custom_components.<locals>.<setcomp>>   
X-UNKNOWN1
X-UNKNOWN2UNKNOWN3NrM   )r   r,   rC   component_namesr   r   r   -test_does_not_silently_drop_custom_components  s
   
zCTestRFC5545Compliance.test_does_not_silently_drop_custom_componentsc                 C   s   d}t |}|jdksJ t|jdksJ |jd }|jdks#J |d dks+J | }t |}t|jdks=J |jd jdksGJ 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-OUTERr9   r   zX-INNERr/   InnerN)r   r*   r
   r;   r<   r#   )r   r,   outerinnerr3   reparsedr   r   r   'test_nested_custom_components_preserved$  s   


z=TestRFC5545Compliance.test_nested_custom_components_preservedN)r   r   r   r   rs   rt   rz   r   r   r   r   r   rq      s    rq   N)r   	icalendarr   r   r   icalendar.cal.component_factoryr   r   r    r@   rS   rq   r   r   r   r   <module>   s     AG.