def test_any_text_value_recode(value): esc = TextConv.serialize(value) assert TextConv.parse(esc) == value cl = ContentLine("TEST", value=esc) assert ContentLine.parse(cl.serialize()) == cl assert string_to_container(cl.serialize()) == [cl] vals = [esc, esc, "test", esc] cl2 = ContentLine("TEST", value=TextConv.join_value_list(vals)) assert list(TextConv.split_value_list(cl2.value)) == vals assert ContentLine.parse(cl.serialize()) == cl assert string_to_container(cl.serialize()) == [cl]
def test_container_parse_error(): pytest.raises(ParseError, string_to_container, "BEGIN:TEST") assert string_to_container("END:TEST") == [ContentLine(name="END", value="TEST")] pytest.raises(ParseError, string_to_container, "BEGIN:TEST1\nEND:TEST2") pytest.raises(ParseError, string_to_container, "BEGIN:TEST1\nEND:TEST2\nEND:TEST1") assert string_to_container("BEGIN:TEST1\nEND:TEST1\nEND:TEST1") == [Container("TEST1"), ContentLine(name="END", value="TEST1")] pytest.raises(ParseError, string_to_container, "BEGIN:TEST1\nBEGIN:TEST1\nEND:TEST1")
def test_any_name_params_value_recode(name, value, param1, p1value, param2, p2value1, p2value2): assume(param1 != param2) raw = "%s;%s=%s;%s=%s,%s:%s" % (name, param1, quote_escape_param(p1value), param2, quote_escape_param(p2value1), quote_escape_param(p2value2), value) assert ContentLine.parse(raw).serialize() == raw cl = ContentLine(name, {param1: [p1value], param2: [p2value1, p2value2]}, value) assert ContentLine.parse(cl.serialize()) == cl assert string_to_container(raw) == [cl]
def test_container_nested(): inp = """BEGIN:TEST1 VAL1:The-Val BEGIN:TEST2 VAL2:The-Val BEGIN:TEST3 VAL3:The-Val END:TEST3 END:TEST2 VAL4:The-Val BEGIN:TEST2 VAL5:The-Val END:TEST2 BEGIN:TEST2 VAL5:The-Val END:TEST2 VAL6:The-Val END:TEST1""" out = Container('TEST1', [ ContentLine(name='VAL1', params={}, value='The-Val'), Container('TEST2', [ ContentLine(name='VAL2', params={}, value='The-Val'), Container('TEST3', [ ContentLine(name='VAL3', params={}, value='The-Val') ]) ]), ContentLine(name='VAL4', params={}, value='The-Val'), Container('TEST2', [ ContentLine(name='VAL5', params={}, value='The-Val')]), Container('TEST2', [ ContentLine(name='VAL5', params={}, value='The-Val')]), ContentLine(name='VAL6', params={}, value='The-Val')]) assert string_to_container(inp) == [out] assert out.serialize() == inp.replace("\n", "\r\n")
def test_contentline_funcs(): cl = ContentLine("TEST", {"PARAM": ["VAL"]}, "VALUE") assert cl["PARAM"] == ["VAL"] cl["PARAM2"] = ["VALA", "VALB"] assert cl.params == {"PARAM": ["VAL"], "PARAM2": ["VALA", "VALB"]} cl_clone = cl.clone() assert cl == cl_clone and cl is not cl_clone assert cl.params == cl_clone.params and cl.params is not cl_clone.params assert cl.params["PARAM2"] == cl_clone.params["PARAM2"] and cl.params["PARAM2"] is not cl_clone.params["PARAM2"] cl_clone["PARAM2"].append("VALC") assert cl != cl_clone assert str(cl) == "TEST{'PARAM': ['VAL'], 'PARAM2': ['VALA', 'VALB']}='VALUE'" assert str(cl_clone) == "TEST{'PARAM': ['VAL'], 'PARAM2': ['VALA', 'VALB', 'VALC']}='VALUE'"
def test_value_characters(): chars = "abcABC0123456789" "-=_+!$%&*()[]{}<>'@#~/?|`¬€¨ÄÄää´ÁÁááßæÆ \t\\n😜🇪🇺👩🏾💻👨🏻👩🏻👧🏻👦🏻xyzXYZ" special_chars = ";:,\"^" inp = "TEST;P1={chars};P2={chars},{chars},\"{chars}\",{chars}:{chars}:{chars}{special}".format( chars=chars, special=special_chars) out = ContentLine("TEST", {"P1": [chars], "P2": [chars, chars, QuotedParamValue(chars), chars]}, chars + ":" + chars + special_chars) par = ContentLine.parse(inp) assert par == out ser = out.serialize() assert inp == ser par_ser = par.serialize() assert inp == par_ser assert string_to_container(inp) == [out]
def serialize(self, component: "Component", output: Container, context: ContextDict): if self.is_multi_value: self.__serialize_multi(component, output, context) else: value = self.get_value(component) if value: params = copy_extra_params( cast(ExtraParams, self.get_extra_params(component))) converter = self.__find_value_converter(params, value) serialized = converter.serialize(value, params, context) output.append( ContentLine(name=self.ics_name, params=params, value=serialized))
def test_param_quoting(): inp = 'TEST;P1="A";P2=B;P3=C,"D",E,"F":"VAL"' out = ContentLine("TEST", { "P1": [QuotedParamValue("A")], "P2": ["B"], "P3": ["C", QuotedParamValue("D"), "E", QuotedParamValue("F")], }, '"VAL"') par = ContentLine.parse(inp) assert par == out ser = out.serialize() assert inp == ser par_ser = par.serialize() assert inp == par_ser assert string_to_container(inp) == [out] for param in out.params.keys(): for o_val, p_val in zip(out[param], par[param]): assert type(o_val) == type(p_val)
def __serialize_multi(self, component: "Component", output: "Container", context: ContextDict): extra_params = cast(List[ExtraParams], self.get_extra_params(component)) values = self.get_value_list(component) if len(extra_params) != len(values): raise ValueError( "length of extra params doesn't match length of parameters" " for attribute %s of %r" % (self.attribute.name, component)) merge_next = False current_params = None current_values = [] for value, params in zip(values, extra_params): merge_next = False params = copy_extra_params(params) if params.pop("__merge_next", None) == ["TRUE"]: merge_next = True converter = self.__find_value_converter(params, value) serialized = converter.serialize( value, params, context) # might modify params and context if current_params is not None: if current_params != params: raise ValueError() else: current_params = params current_values.append(serialized) if not merge_next: cl = ContentLine( name=self.ics_name, params=params, value=converter.join_value_list(current_values)) output.append(cl) current_params = None current_values = [] if merge_next: raise ValueError( "last value in value list may not have merge_next set")
def test_container(): inp = """BEGIN:TEST VAL1:The-Val VAL2;PARAM1=P1;PARAM2=P2A,P2B;PARAM3="P3:A","P3:B,C":The-Val2 END:TEST""" out = Container('TEST', [ ContentLine(name='VAL1', params={}, value='The-Val'), ContentLine(name='VAL2', params={'PARAM1': ['P1'], 'PARAM2': ['P2A', 'P2B'], 'PARAM3': ['P3:A', 'P3:B,C']}, value='The-Val2')]) assert string_to_container(inp) == [out] assert out.serialize() == inp.replace("\n", "\r\n") assert str(out) == "TEST[VAL1='The-Val', VAL2{'PARAM1': ['P1'], 'PARAM2': ['P2A', 'P2B'], 'PARAM3': ['P3:A', 'P3:B,C']}='The-Val2']" assert repr(out) == "Container('TEST', [ContentLine(name='VAL1', params={}, value='The-Val'), ContentLine(name='VAL2', params={'PARAM1': ['P1'], 'PARAM2': ['P2A', 'P2B'], 'PARAM3': ['P3:A', 'P3:B,C']}, value='The-Val2')])" out_shallow = out.clone(deep=False) out_deep = out.clone(deep=True) assert out == out_shallow == out_deep assert all(a == b for a, b in zip(out, out_shallow)) assert all(a == b for a, b in zip(out, out_deep)) assert all(a is b for a, b in zip(out, out_shallow)) assert all(a is not b for a, b in zip(out, out_deep)) out_deep.append(ContentLine("LAST")) assert out != out_deep out[0].params["NEW"] = "SOMETHING" assert out == out_shallow out_shallow.name = "DIFFERENT" assert out != out_shallow with pytest.raises(TypeError): out_shallow[0] = ['CONTENT:Line'] with pytest.raises(TypeError): out_shallow[:] = ['CONTENT:Line'] pytest.raises(TypeError, out_shallow.append, 'CONTENT:Line') pytest.raises(TypeError, out_shallow.append, ['CONTENT:Line']) pytest.raises(TypeError, out_shallow.extend, ['CONTENT:Line']) out_shallow[:] = [out[0]] assert out_shallow == Container("DIFFERENT", [out[0]]) out_shallow[:] = [] assert out_shallow == Container("DIFFERENT") out_shallow.append(ContentLine("CL1")) out_shallow.extend([ContentLine("CL3")]) out_shallow.insert(1, ContentLine("CL2")) out_shallow += [ContentLine("CL4")] assert out_shallow[1:3] == Container("DIFFERENT", [ContentLine("CL2"), ContentLine("CL3")]) assert out_shallow == Container("DIFFERENT", [ContentLine("CL1"), ContentLine("CL2"), ContentLine("CL3"), ContentLine("CL4")]) with pytest.warns(UserWarning, match="not all-uppercase"): assert string_to_container("BEGIN:test\nEND:TeSt") == [Container("TEST", [])]
def test_any_param_value_recode(param, value): raw = "TEST;%s=%s:VALUE" % (param, quote_escape_param(value)) assert ContentLine.parse(raw).serialize() == raw cl = ContentLine("TEST", {param: [value]}, "VALUE") assert ContentLine.parse(cl.serialize()) == cl assert string_to_container(raw) == [cl]
def test_any_name_value_recode(name, value): raw = "%s:%s" % (name, value) assert ContentLine.parse(raw).serialize() == raw cl = ContentLine(name, value=value) assert ContentLine.parse(cl.serialize()) == cl assert string_to_container(raw) == [cl]
import re import pytest from hypothesis import assume, given, example from hypothesis.strategies import characters, text from ics.grammar import Container, ContentLine, ParseError, QuotedParamValue, escape_param, string_to_container, unfold_lines CONTROL = [chr(i) for i in range(ord(" ")) if i != ord("\t")] + [chr(0x7F)] NAME = text(alphabet=(characters(whitelist_categories=["Lu"], whitelist_characters=["-"], max_codepoint=128)), min_size=1) VALUE = text(characters(blacklist_categories=["Cs"], blacklist_characters=CONTROL)) @pytest.mark.parametrize("inp, out", [ ('HAHA:', ContentLine(name='HAHA', params={}, value='')), ('HAHA:hoho', ContentLine(name='HAHA', params={}, value='hoho')), ('HAHA:hoho:hihi', ContentLine(name='HAHA', params={}, value='hoho:hihi')), ( 'HAHA;hoho=1:hoho', ContentLine(name='HAHA', params={'hoho': ['1']}, value='hoho') ), ( 'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU', ContentLine(name='RRULE', params={}, value='FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU') ), ( 'SUMMARY:dfqsdfjqkshflqsjdfhqs fqsfhlqs dfkqsldfkqsdfqsfqsfqsfs', ContentLine(name='SUMMARY', params={}, value='dfqsdfjqkshflqsjdfhqs fqsfhlqs dfkqsldfkqsdfqsfqsfqsfs') ), ( 'DTSTART;TZID=Europe/Brussels:20131029T103000', ContentLine(name='DTSTART', params={'TZID': ['Europe/Brussels']}, value='20131029T103000') ), ( 'haha;p2=v2;p1=v1:',
import attr import pytest from hypothesis import given from ics.grammar import ContentLine, string_to_container from ics.valuetype.text import TextConverter # Text may be comma-separated multi-value but is never quoted, with the characters [\\;,\n] escaped from tests.grammar import VALUE TextConv: TextConverter = TextConverter.INST @pytest.mark.parametrize("inp_esc, out_uesc", [ ( "SUMMARY:Project XYZ Final Review\\nConference Room - 3B\\nCome Prepared.", ContentLine("SUMMARY", value="Project XYZ Final Review\nConference Room - 3B\nCome Prepared.") ), ( "DESCRIPTION;ALTREP=\"cid:[email protected]\":The Fall'98 Wild Wizards Conference - - Las Vegas\\, NV\\, USA", ContentLine("DESCRIPTION", {"ALTREP": ["cid:[email protected]"]}, value="The Fall'98 Wild Wizards Conference - - Las Vegas, NV, USA") ), ( "TEST:abc\\r\\n\\,\\;:\"\t=xyz", ContentLine("TEST", value="abc\r\n,;:\"\t=xyz") ), ]) def test_example_text_recode(inp_esc, out_uesc): par_esc = ContentLine.parse(inp_esc) par_uesc = attr.evolve(par_esc, value=TextConv.parse(par_esc.value)) out_esc = attr.evolve(out_uesc, value=TextConv.serialize(out_uesc.value)) assert par_uesc == out_uesc