fix: 포트 충돌 회피 — note_bridge 8098, intent_service 8099
Jellyfin(8096), OrbStack(8097) 포트 충돌으로 변경. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Test the value types of properties."""
|
||||
@@ -0,0 +1,120 @@
|
||||
from icalendar.prop import (
|
||||
vBoolean,
|
||||
vInline,
|
||||
vUTCOffset,
|
||||
vCategory,
|
||||
vCalAddress,
|
||||
vWeekday,
|
||||
vDuration,
|
||||
vFloat,
|
||||
vGeo,
|
||||
vInt,
|
||||
vText,
|
||||
vMonth,
|
||||
vUTCOffset,
|
||||
vFrequency,
|
||||
vRecur,
|
||||
vDatetime,
|
||||
vUri,
|
||||
)
|
||||
import datetime
|
||||
|
||||
|
||||
def test_param_vCategory():
|
||||
obj = vCategory(["Work", "Personal"], params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vCategory)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vCalAddress():
|
||||
obj = vCalAddress("mailto:jane_doe@example.com", params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vCalAddress)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vWeekday():
|
||||
obj = vWeekday("2FR", params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vWeekday)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vBoolean():
|
||||
obj = vBoolean(True, params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vBoolean)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vDuration():
|
||||
td = datetime.timedelta(days=15, seconds=18020)
|
||||
obj = vDuration(td, params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vDuration)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vFloat():
|
||||
obj = vFloat("1.333", params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vFloat)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vGeo():
|
||||
obj = vGeo((37.386013, -122.082932), params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vGeo)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vInt():
|
||||
obj = vInt("87", params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vInt)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vInline():
|
||||
obj = vInline("sometxt", params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vInline)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vText():
|
||||
obj = vText("sometxt", params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vText)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vMonth():
|
||||
obj = vMonth(1, params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vMonth)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vUTCOffset():
|
||||
obj = vUTCOffset(
|
||||
datetime.timedelta(days=-1, seconds=68400), params={"SOME_PARAM": "VALUE"}
|
||||
)
|
||||
assert isinstance(obj, vUTCOffset)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vFrequency():
|
||||
obj = vFrequency("DAILY", params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vFrequency)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vRecur():
|
||||
obj = vRecur({"FREQ": ["DAILY"], "COUNT": [10]}, params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vRecur)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vDatetime():
|
||||
dt = datetime.datetime(2025, 3, 16, 14, 30, 0, tzinfo=datetime.timezone.utc)
|
||||
obj = vDatetime(dt, params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vDatetime)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
|
||||
|
||||
def test_param_vUri():
|
||||
obj = vUri("WWW.WESBITE.COM", params={"SOME_PARAM": "VALUE"})
|
||||
assert isinstance(obj, vUri)
|
||||
assert obj.params["SOME_PARAM"] == "VALUE"
|
||||
@@ -0,0 +1,70 @@
|
||||
"""Test the identity and equality between properties."""
|
||||
|
||||
from datetime import date, datetime, time
|
||||
|
||||
from icalendar import vDDDTypes
|
||||
from icalendar.timezone.zoneinfo import zoneinfo
|
||||
|
||||
try:
|
||||
import pytz
|
||||
except ImportError:
|
||||
pytz = None
|
||||
from copy import deepcopy
|
||||
|
||||
import pytest
|
||||
from dateutil import tz
|
||||
|
||||
vDDDTypes_list = [
|
||||
vDDDTypes(
|
||||
datetime(
|
||||
year=2022,
|
||||
month=7,
|
||||
day=22,
|
||||
hour=12,
|
||||
minute=7,
|
||||
tzinfo=zoneinfo.ZoneInfo("Europe/London"),
|
||||
)
|
||||
),
|
||||
vDDDTypes(datetime(year=2022, month=7, day=22, hour=12, minute=7)),
|
||||
vDDDTypes(datetime(year=2022, month=7, day=22, hour=12, minute=7, tzinfo=tz.UTC)),
|
||||
vDDDTypes(date(year=2022, month=7, day=22)),
|
||||
vDDDTypes(date(year=2022, month=7, day=23)),
|
||||
vDDDTypes(time(hour=22, minute=7, second=2)),
|
||||
]
|
||||
if pytz:
|
||||
vDDDTypes_list.append(
|
||||
vDDDTypes(
|
||||
pytz.timezone("EST").localize(
|
||||
datetime(year=2022, month=7, day=22, hour=12, minute=7)
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def identity(x):
|
||||
return x
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"map",
|
||||
[
|
||||
deepcopy,
|
||||
identity,
|
||||
hash,
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("v_type", vDDDTypes_list)
|
||||
@pytest.mark.parametrize("other", vDDDTypes_list)
|
||||
def test_vDDDTypes_equivalance(map, v_type, other):
|
||||
if v_type is other:
|
||||
assert map(v_type) == map(other), f"identity implies equality: {map.__name__}()"
|
||||
assert map(v_type) == map(other), f"identity implies equality: {map.__name__}()"
|
||||
else:
|
||||
assert map(v_type) != map(other), f"expected inequality: {map.__name__}()"
|
||||
assert map(v_type) != map(other), f"expected inequality: {map.__name__}()"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("v_type", vDDDTypes_list)
|
||||
def test_inequality_with_different_types(v_type):
|
||||
assert v_type != 42
|
||||
assert v_type != "test"
|
||||
@@ -0,0 +1,19 @@
|
||||
"""Test that composed values are properly converted."""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from icalendar import Event
|
||||
|
||||
|
||||
def test_vDDDLists_timezone(tzp):
|
||||
"""Test vDDDLists with timezone information."""
|
||||
vevent = Event()
|
||||
dt1 = tzp.localize(datetime(2013, 1, 1), "Europe/Vienna")
|
||||
dt2 = tzp.localize(datetime(2013, 1, 2), "Europe/Vienna")
|
||||
dt3 = tzp.localize(datetime(2013, 1, 3), "Europe/Vienna")
|
||||
vevent.add("rdate", [dt1, dt2])
|
||||
vevent.add("exdate", dt3)
|
||||
ical = vevent.to_ical()
|
||||
|
||||
assert b"RDATE;TZID=Europe/Vienna:20130101T000000,20130102T000000" in ical
|
||||
assert b"EXDATE;TZID=Europe/Vienna:20130103T000000" in ical
|
||||
@@ -0,0 +1,363 @@
|
||||
import unittest
|
||||
from datetime import date, datetime, time, timedelta
|
||||
|
||||
from icalendar.parser import Parameters
|
||||
|
||||
|
||||
class TestProp(unittest.TestCase):
|
||||
def test_prop_vFloat(self):
|
||||
from icalendar.prop import vFloat
|
||||
|
||||
self.assertEqual(vFloat(1.0).to_ical(), b"1.0")
|
||||
self.assertEqual(vFloat.from_ical("42"), 42.0)
|
||||
self.assertEqual(vFloat(42).to_ical(), b"42.0")
|
||||
self.assertRaises(ValueError, vFloat.from_ical, "1s3")
|
||||
|
||||
def test_prop_vInt(self):
|
||||
from icalendar.prop import vInt
|
||||
|
||||
self.assertEqual(vInt(42).to_ical(), b"42")
|
||||
self.assertEqual(vInt.from_ical("13"), 13)
|
||||
self.assertRaises(ValueError, vInt.from_ical, "1s3")
|
||||
|
||||
def test_prop_vDDDLists(self):
|
||||
from icalendar.prop import vDDDLists
|
||||
|
||||
dt_list = vDDDLists.from_ical("19960402T010000Z")
|
||||
self.assertIsInstance(dt_list, list)
|
||||
self.assertEqual(len(dt_list), 1)
|
||||
self.assertIsInstance(dt_list[0], datetime)
|
||||
self.assertEqual(str(dt_list[0]), "1996-04-02 01:00:00+00:00")
|
||||
|
||||
p = "19960402T010000Z,19960403T010000Z,19960404T010000Z"
|
||||
dt_list = vDDDLists.from_ical(p)
|
||||
self.assertEqual(len(dt_list), 3)
|
||||
self.assertEqual(str(dt_list[0]), "1996-04-02 01:00:00+00:00")
|
||||
self.assertEqual(str(dt_list[2]), "1996-04-04 01:00:00+00:00")
|
||||
|
||||
dt_list = vDDDLists([])
|
||||
self.assertEqual(dt_list.to_ical(), b"")
|
||||
|
||||
dt_list = vDDDLists([datetime(2000, 1, 1)])
|
||||
self.assertEqual(dt_list.to_ical(), b"20000101T000000")
|
||||
|
||||
dt_list = vDDDLists([datetime(2000, 1, 1), datetime(2000, 11, 11)])
|
||||
self.assertEqual(dt_list.to_ical(), b"20000101T000000,20001111T000000")
|
||||
|
||||
instance = vDDDLists([])
|
||||
self.assertNotEqual(instance, "value")
|
||||
|
||||
def test_prop_vDate(self):
|
||||
from icalendar.prop import vDate
|
||||
|
||||
self.assertEqual(vDate(date(2001, 1, 1)).to_ical(), b"20010101")
|
||||
self.assertEqual(vDate(date(1899, 1, 1)).to_ical(), b"18990101")
|
||||
|
||||
self.assertEqual(vDate.from_ical("20010102"), date(2001, 1, 2))
|
||||
|
||||
self.assertRaises(ValueError, vDate, "d")
|
||||
self.assertRaises(ValueError, vDate.from_ical, "200102")
|
||||
|
||||
def test_prop_vDuration(self):
|
||||
from icalendar.prop import vDuration
|
||||
|
||||
self.assertEqual(vDuration(timedelta(11)).to_ical(), b"P11D")
|
||||
self.assertEqual(vDuration(timedelta(-14)).to_ical(), b"-P14D")
|
||||
self.assertEqual(vDuration(timedelta(1, 7384)).to_ical(), b"P1DT2H3M4S")
|
||||
self.assertEqual(vDuration(timedelta(1, 7380)).to_ical(), b"P1DT2H3M")
|
||||
self.assertEqual(vDuration(timedelta(1, 7200)).to_ical(), b"P1DT2H")
|
||||
self.assertEqual(vDuration(timedelta(0, 7200)).to_ical(), b"PT2H")
|
||||
self.assertEqual(vDuration(timedelta(0, 7384)).to_ical(), b"PT2H3M4S")
|
||||
self.assertEqual(vDuration(timedelta(0, 184)).to_ical(), b"PT3M4S")
|
||||
self.assertEqual(vDuration(timedelta(0, 22)).to_ical(), b"PT22S")
|
||||
self.assertEqual(vDuration(timedelta(0, 3622)).to_ical(), b"PT1H0M22S")
|
||||
self.assertEqual(vDuration(timedelta(days=1, hours=5)).to_ical(), b"P1DT5H")
|
||||
self.assertEqual(vDuration(timedelta(hours=-5)).to_ical(), b"-PT5H")
|
||||
self.assertEqual(vDuration(timedelta(days=-1, hours=-5)).to_ical(), b"-P1DT5H")
|
||||
|
||||
# How does the parsing work?
|
||||
self.assertEqual(vDuration.from_ical("PT1H0M22S"), timedelta(0, 3622))
|
||||
|
||||
self.assertRaises(ValueError, vDuration.from_ical, "kox")
|
||||
|
||||
self.assertEqual(vDuration.from_ical("-P14D"), timedelta(-14))
|
||||
|
||||
self.assertRaises(ValueError, vDuration, 11)
|
||||
|
||||
# calling to_ical twice should result in same output
|
||||
duration = vDuration(timedelta(days=-1, hours=-5))
|
||||
self.assertEqual(duration.to_ical(), b"-P1DT5H")
|
||||
self.assertEqual(duration.to_ical(), b"-P1DT5H")
|
||||
|
||||
def test_prop_vWeekday(self):
|
||||
from icalendar.prop import vWeekday
|
||||
|
||||
self.assertEqual(vWeekday("mo").to_ical(), b"MO")
|
||||
self.assertRaises(ValueError, vWeekday, "erwer")
|
||||
self.assertEqual(vWeekday.from_ical("mo"), "MO")
|
||||
self.assertEqual(vWeekday.from_ical("+3mo"), "+3MO")
|
||||
self.assertRaises(ValueError, vWeekday.from_ical, "Saturday")
|
||||
self.assertEqual(vWeekday("+mo").to_ical(), b"+MO")
|
||||
self.assertEqual(vWeekday("+3mo").to_ical(), b"+3MO")
|
||||
self.assertEqual(vWeekday("-tu").to_ical(), b"-TU")
|
||||
|
||||
def test_prop_vFrequency(self):
|
||||
from icalendar.prop import vFrequency
|
||||
|
||||
self.assertRaises(ValueError, vFrequency, "bad test")
|
||||
self.assertEqual(vFrequency("daily").to_ical(), b"DAILY")
|
||||
self.assertEqual(vFrequency("daily").from_ical("MONTHLY"), "MONTHLY")
|
||||
self.assertRaises(ValueError, vFrequency.from_ical, 234)
|
||||
|
||||
def test_prop_vRecur(self):
|
||||
from icalendar.prop import vRecur
|
||||
|
||||
# Let's see how close we can get to one from the rfc:
|
||||
# FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30
|
||||
|
||||
r = dict({"freq": "yearly", "interval": 2})
|
||||
r.update({"bymonth": 1, "byday": "su", "byhour": [8, 9], "byminute": 30})
|
||||
self.assertEqual(
|
||||
vRecur(r).to_ical(),
|
||||
b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1",
|
||||
)
|
||||
|
||||
r = vRecur(FREQ="yearly", INTERVAL=2)
|
||||
r.update(
|
||||
{
|
||||
"BYMONTH": 1,
|
||||
"BYDAY": "su",
|
||||
"BYHOUR": [8, 9],
|
||||
"BYMINUTE": 30,
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
r.to_ical(),
|
||||
b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1",
|
||||
)
|
||||
|
||||
r = vRecur(freq="DAILY", count=10)
|
||||
r["bysecond"] = [0, 15, 30, 45]
|
||||
self.assertEqual(r.to_ical(), b"FREQ=DAILY;COUNT=10;BYSECOND=0,15,30,45")
|
||||
|
||||
r = vRecur(freq="DAILY", until=datetime(2005, 1, 1, 12, 0, 0))
|
||||
self.assertEqual(r.to_ical(), b"FREQ=DAILY;UNTIL=20050101T120000")
|
||||
|
||||
# How do we fare with regards to parsing?
|
||||
r = vRecur.from_ical("FREQ=DAILY;INTERVAL=2;COUNT=10")
|
||||
self.assertEqual(r, {"COUNT": [10], "FREQ": ["DAILY"], "INTERVAL": [2]})
|
||||
self.assertEqual(vRecur(r).to_ical(), b"FREQ=DAILY;COUNT=10;INTERVAL=2")
|
||||
|
||||
r = vRecur.from_ical(
|
||||
"FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=-SU;BYHOUR=8,9;BYMINUTE=30"
|
||||
)
|
||||
self.assertEqual(
|
||||
r,
|
||||
{
|
||||
"BYHOUR": [8, 9],
|
||||
"BYDAY": ["-SU"],
|
||||
"BYMINUTE": [30],
|
||||
"BYMONTH": [1],
|
||||
"FREQ": ["YEARLY"],
|
||||
"INTERVAL": [2],
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
vRecur(r).to_ical(),
|
||||
b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=-SU;BYMONTH=1",
|
||||
)
|
||||
|
||||
r = vRecur.from_ical("FREQ=WEEKLY;INTERVAL=1;BYWEEKDAY=TH")
|
||||
|
||||
self.assertEqual(r, {"FREQ": ["WEEKLY"], "INTERVAL": [1], "BYWEEKDAY": ["TH"]})
|
||||
|
||||
self.assertEqual(vRecur(r).to_ical(), b"FREQ=WEEKLY;INTERVAL=1;BYWEEKDAY=TH")
|
||||
|
||||
# Some examples from the spec
|
||||
r = vRecur.from_ical("FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1")
|
||||
self.assertEqual(
|
||||
vRecur(r).to_ical(), b"FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1"
|
||||
)
|
||||
|
||||
p = "FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30"
|
||||
r = vRecur.from_ical(p)
|
||||
self.assertEqual(
|
||||
vRecur(r).to_ical(),
|
||||
b"FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1",
|
||||
)
|
||||
|
||||
# and some errors
|
||||
self.assertRaises(ValueError, vRecur.from_ical, "BYDAY=12")
|
||||
|
||||
# when key is not RFC-compliant, parse it as vText
|
||||
r = vRecur.from_ical("FREQ=MONTHLY;BYOTHER=TEXT;BYEASTER=-3")
|
||||
self.assertEqual(vRecur(r).to_ical(), b"FREQ=MONTHLY;BYEASTER=-3;BYOTHER=TEXT")
|
||||
|
||||
def test_prop_vText(self):
|
||||
from icalendar.prop import vText
|
||||
|
||||
self.assertEqual(vText("Simple text").to_ical(), b"Simple text")
|
||||
|
||||
# Escaped text
|
||||
t = vText("Text ; with escaped, chars")
|
||||
self.assertEqual(t.to_ical(), b"Text \\; with escaped\\, chars")
|
||||
|
||||
# Escaped newlines
|
||||
self.assertEqual(
|
||||
vText("Text with escaped\\N chars").to_ical(), b"Text with escaped\\n chars"
|
||||
)
|
||||
|
||||
# If you pass a unicode object, it will be utf-8 encoded. As this is
|
||||
# the (only) standard that RFC 5545 support.
|
||||
t = vText("international chars \xe4\xf6\xfc")
|
||||
self.assertEqual(t.to_ical(), b"international chars \xc3\xa4\xc3\xb6\xc3\xbc")
|
||||
|
||||
# and parsing?
|
||||
self.assertEqual(
|
||||
vText.from_ical("Text \\; with escaped\\, chars"),
|
||||
"Text ; with escaped, chars",
|
||||
)
|
||||
|
||||
t = vText.from_ical("A string with\\; some\\\\ characters in\\it")
|
||||
self.assertEqual(t, "A string with; some\\ characters in\\it")
|
||||
|
||||
# We are forgiving to utf-8 encoding errors:
|
||||
# We intentionally use a string with unexpected encoding
|
||||
#
|
||||
self.assertEqual(vText.from_ical(b"Ol\xe9"), "Ol\ufffd")
|
||||
|
||||
# Notice how accented E character, encoded with latin-1, got replaced
|
||||
# with the official U+FFFD REPLACEMENT CHARACTER.
|
||||
|
||||
def test_prop_vTime(self):
|
||||
from icalendar.prop import vTime
|
||||
|
||||
self.assertEqual(vTime(12, 30, 0).to_ical(), "123000")
|
||||
self.assertEqual(vTime.from_ical("123000"), time(12, 30))
|
||||
|
||||
# We should also fail, right?
|
||||
self.assertRaises(ValueError, vTime.from_ical, "263000")
|
||||
|
||||
self.assertRaises(ValueError, vTime, "263000")
|
||||
|
||||
def test_prop_vUri(self):
|
||||
from icalendar.prop import vUri
|
||||
|
||||
self.assertEqual(
|
||||
vUri("http://www.example.com/").to_ical(), b"http://www.example.com/"
|
||||
)
|
||||
self.assertEqual(
|
||||
vUri.from_ical("http://www.example.com/"), "http://www.example.com/"
|
||||
)
|
||||
|
||||
def test_prop_vGeo(self):
|
||||
from icalendar.prop import vGeo
|
||||
|
||||
# Pass a list
|
||||
self.assertEqual(vGeo([1.2, 3.0]).to_ical(), "1.2;3.0")
|
||||
|
||||
# Pass a tuple
|
||||
self.assertEqual(vGeo((1.2, 3.0)).to_ical(), "1.2;3.0")
|
||||
|
||||
g = vGeo.from_ical("37.386013;-122.082932")
|
||||
self.assertEqual(g, (float("37.386013"), float("-122.082932")))
|
||||
|
||||
self.assertEqual(vGeo(g).to_ical(), "37.386013;-122.082932")
|
||||
|
||||
self.assertRaises(ValueError, vGeo, "g")
|
||||
self.assertRaises(ValueError, vGeo.from_ical, "1s3;1s3")
|
||||
|
||||
def test_prop_vUTCOffset(self):
|
||||
from icalendar.prop import vUTCOffset
|
||||
|
||||
self.assertEqual(vUTCOffset(timedelta(hours=2)).to_ical(), "+0200")
|
||||
|
||||
self.assertEqual(vUTCOffset(timedelta(hours=-5)).to_ical(), "-0500")
|
||||
|
||||
self.assertEqual(vUTCOffset(timedelta()).to_ical(), "+0000")
|
||||
|
||||
self.assertEqual(vUTCOffset(timedelta(minutes=-30)).to_ical(), "-0030")
|
||||
|
||||
self.assertEqual(vUTCOffset(timedelta(hours=2, minutes=-30)).to_ical(), "+0130")
|
||||
|
||||
self.assertEqual(vUTCOffset(timedelta(hours=1, minutes=30)).to_ical(), "+0130")
|
||||
|
||||
# Support seconds
|
||||
self.assertEqual(
|
||||
vUTCOffset(timedelta(hours=1, minutes=30, seconds=7)).to_ical(), "+013007"
|
||||
)
|
||||
|
||||
# Parsing
|
||||
|
||||
self.assertEqual(vUTCOffset.from_ical("0000"), timedelta(0))
|
||||
self.assertEqual(vUTCOffset.from_ical("-0030"), timedelta(-1, 84600))
|
||||
self.assertEqual(vUTCOffset.from_ical("+0200"), timedelta(0, 7200))
|
||||
self.assertEqual(vUTCOffset.from_ical("+023040"), timedelta(0, 9040))
|
||||
|
||||
self.assertEqual(vUTCOffset(vUTCOffset.from_ical("+0230")).to_ical(), "+0230")
|
||||
|
||||
# And a few failures
|
||||
self.assertRaises(ValueError, vUTCOffset.from_ical, "+323k")
|
||||
|
||||
self.assertRaises(ValueError, vUTCOffset.from_ical, "+2400")
|
||||
|
||||
self.assertRaises(ValueError, vUTCOffset, "0:00:00")
|
||||
|
||||
def test_prop_vInline(self):
|
||||
from icalendar.prop import vInline
|
||||
|
||||
self.assertEqual(vInline("Some text"), "Some text")
|
||||
self.assertEqual(vInline("Some text").to_ical(), b"Some text")
|
||||
self.assertEqual(vInline.from_ical("Some text"), "Some text")
|
||||
|
||||
t2 = vInline("other text")
|
||||
t2.params["cn"] = "Test Osterone"
|
||||
self.assertIsInstance(t2.params, Parameters)
|
||||
self.assertEqual(t2.params, {"CN": "Test Osterone"})
|
||||
|
||||
def test_prop_vCategory(self):
|
||||
from icalendar.prop import vCategory
|
||||
|
||||
catz = ["cat 1", "cat 2", "cat 3"]
|
||||
v_cat = vCategory(catz)
|
||||
|
||||
self.assertEqual(v_cat.to_ical(), b"cat 1,cat 2,cat 3")
|
||||
self.assertEqual(vCategory.from_ical(v_cat.to_ical()), catz)
|
||||
c = vCategory(vCategory.from_ical("APPOINTMENT,EDUCATION"))
|
||||
cats = list(c)
|
||||
assert cats == ["APPOINTMENT", "EDUCATION"]
|
||||
|
||||
def test_prop_TypesFactory(self):
|
||||
from icalendar.prop import TypesFactory
|
||||
|
||||
# To get a type you can use it like this.
|
||||
factory = TypesFactory()
|
||||
datetime_parser = factory["date-time"]
|
||||
self.assertEqual(
|
||||
datetime_parser(datetime(2001, 1, 1)).to_ical(), b"20010101T000000"
|
||||
)
|
||||
|
||||
# A typical use is when the parser tries to find a content type and use
|
||||
# text as the default
|
||||
value = "20050101T123000"
|
||||
value_type = "date-time"
|
||||
self.assertEqual(
|
||||
factory.get(value_type, "text").from_ical(value),
|
||||
datetime(2005, 1, 1, 12, 30),
|
||||
)
|
||||
|
||||
# It can also be used to directly encode property and parameter values
|
||||
self.assertEqual(
|
||||
factory.to_ical("comment", "by Rasmussen, Max M\xfcller"),
|
||||
b"by Rasmussen\\, Max M\xc3\xbcller",
|
||||
)
|
||||
self.assertEqual(factory.to_ical("priority", 1), b"1")
|
||||
self.assertEqual(
|
||||
factory.to_ical("cn", "Rasmussen, Max M\xfcller"),
|
||||
b"Rasmussen\\, Max M\xc3\xbcller",
|
||||
)
|
||||
self.assertEqual(
|
||||
factory.from_ical("cn", b"Rasmussen\\, Max M\xc3\xb8ller"),
|
||||
"Rasmussen, Max M\xf8ller",
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Test vBinary"""
|
||||
|
||||
import pytest
|
||||
|
||||
from icalendar import vBinary
|
||||
from icalendar.parser import Parameters
|
||||
|
||||
|
||||
def test_text():
|
||||
txt = b"This is gibberish"
|
||||
txt_ical = b"VGhpcyBpcyBnaWJiZXJpc2g="
|
||||
assert vBinary(txt).to_ical() == txt_ical
|
||||
assert vBinary.from_ical(txt_ical) == txt
|
||||
|
||||
|
||||
def test_binary():
|
||||
txt = b"Binary data \x13 \x56"
|
||||
txt_ical = b"QmluYXJ5IGRhdGEgEyBW"
|
||||
assert vBinary(txt).to_ical() == txt_ical
|
||||
assert vBinary.from_ical(txt_ical) == txt
|
||||
|
||||
|
||||
def test_param():
|
||||
assert isinstance(vBinary("txt").params, Parameters)
|
||||
assert vBinary("txt").params == {"VALUE": "BINARY", "ENCODING": "BASE64"}
|
||||
|
||||
|
||||
def test_long_data():
|
||||
"""Long data should not have line breaks, as that would interfere"""
|
||||
txt = b"a" * 99
|
||||
txt_ical = b"YWFh" * 33
|
||||
assert vBinary(txt).to_ical() == txt_ical
|
||||
assert vBinary.from_ical(txt_ical) == txt
|
||||
|
||||
|
||||
def test_repr():
|
||||
instance = vBinary("value")
|
||||
assert repr(instance) == "vBinary(b'dmFsdWU=')"
|
||||
|
||||
|
||||
def test_from_ical():
|
||||
with pytest.raises(ValueError, match="Not valid base 64 encoding."):
|
||||
vBinary.from_ical("value")
|
||||
with pytest.raises(ValueError, match="Not valid base 64 encoding."):
|
||||
vBinary.from_ical("áèਮ")
|
||||
@@ -0,0 +1,22 @@
|
||||
import pytest
|
||||
|
||||
from icalendar.prop import vBoolean
|
||||
|
||||
|
||||
def test_true():
|
||||
assert vBoolean(True).to_ical() == b"TRUE"
|
||||
|
||||
|
||||
def test_false():
|
||||
assert vBoolean(0).to_ical() == b"FALSE"
|
||||
|
||||
|
||||
def test_roundtrip():
|
||||
assert vBoolean.from_ical(vBoolean(True).to_ical()) == True
|
||||
assert vBoolean.from_ical("true") == True
|
||||
|
||||
|
||||
def test_error():
|
||||
"""Error: key not exists"""
|
||||
with pytest.raises(ValueError):
|
||||
vBoolean.from_ical("ture")
|
||||
@@ -0,0 +1,57 @@
|
||||
from icalendar.parser import Parameters
|
||||
from icalendar.prop import vCalAddress
|
||||
|
||||
txt = b"MAILTO:maxm@mxm.dk"
|
||||
a = vCalAddress(txt)
|
||||
a.params["cn"] = "Max M"
|
||||
|
||||
|
||||
def test_to_ical():
|
||||
assert a.to_ical() == txt
|
||||
|
||||
|
||||
def test_params():
|
||||
assert isinstance(a.params, Parameters)
|
||||
assert a.params == {"CN": "Max M"}
|
||||
|
||||
|
||||
def test_from_ical():
|
||||
assert vCalAddress.from_ical(txt) == "MAILTO:maxm@mxm.dk"
|
||||
|
||||
|
||||
def test_repr():
|
||||
instance = vCalAddress("value")
|
||||
assert repr(instance) == "vCalAddress('value')"
|
||||
|
||||
|
||||
def test_email_malformed():
|
||||
"""Sometimes, people forget to add mailto that."""
|
||||
address = vCalAddress("me@you.we")
|
||||
assert address.email == "me@you.we"
|
||||
|
||||
|
||||
def test_email_mailto():
|
||||
"""Email with a normal mailto link."""
|
||||
address = vCalAddress("mailto:icalendar@email.list")
|
||||
assert address.email == "icalendar@email.list"
|
||||
|
||||
|
||||
def test_capital_email():
|
||||
"""mailto can be capital letters."""
|
||||
address = vCalAddress("MAILTO:yemaya@posteo.net")
|
||||
assert address.email == "yemaya@posteo.net"
|
||||
|
||||
|
||||
def test_name():
|
||||
"""We want the name, too!"""
|
||||
address = vCalAddress("MAILTO:yemaya@posteo.net")
|
||||
assert address.name == ""
|
||||
address.params["CN"] = "name!"
|
||||
assert address.name == "name!"
|
||||
|
||||
|
||||
def test_set_the_name():
|
||||
address = vCalAddress("MAILTO:yemaya@posteo.net")
|
||||
address.name = "Yemaya :)"
|
||||
assert address.name == "Yemaya :)"
|
||||
assert address.params["CN"] == "Yemaya :)"
|
||||
@@ -0,0 +1,37 @@
|
||||
from datetime import date, datetime, time, timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from icalendar.prop import vDDDTypes
|
||||
|
||||
|
||||
def test_instance():
|
||||
assert isinstance(vDDDTypes.from_ical("20010101T123000"), datetime)
|
||||
assert isinstance(vDDDTypes.from_ical("20010101"), date)
|
||||
|
||||
|
||||
def test_datetime_with_timezone(tzp):
|
||||
assert vDDDTypes.from_ical("20010101T123000Z") == tzp.localize_utc(
|
||||
datetime(2001, 1, 1, 12, 30)
|
||||
)
|
||||
|
||||
|
||||
def test_timedelta():
|
||||
assert vDDDTypes.from_ical("P31D") == timedelta(31)
|
||||
assert vDDDTypes.from_ical("-P31D") == timedelta(-31)
|
||||
|
||||
|
||||
def test_bad_input():
|
||||
with pytest.raises(ValueError):
|
||||
vDDDTypes(42)
|
||||
|
||||
|
||||
def test_time_from_string():
|
||||
assert vDDDTypes.from_ical("123000") == time(12, 30)
|
||||
assert isinstance(vDDDTypes.from_ical("123000"), time)
|
||||
|
||||
|
||||
def test_invalid_period_to_ical():
|
||||
invalid_period = (datetime(2000, 1, 1), datetime(2000, 1, 2), datetime(2000, 1, 2))
|
||||
with pytest.raises(ValueError):
|
||||
vDDDTypes(invalid_period).to_ical()
|
||||
@@ -0,0 +1,47 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from icalendar.prop import vDatetime
|
||||
|
||||
|
||||
def test_to_ical():
|
||||
assert vDatetime(datetime(2001, 1, 1, 12, 30, 0)).to_ical() == b"20010101T123000"
|
||||
|
||||
|
||||
def test_from_ical():
|
||||
assert vDatetime.from_ical("20000101T120000") == datetime(2000, 1, 1, 12, 0)
|
||||
assert vDatetime.from_ical("20010101T000000") == datetime(2001, 1, 1, 0, 0)
|
||||
|
||||
|
||||
def test_to_ical_utc(tzp):
|
||||
dutc = tzp.localize_utc(datetime(2001, 1, 1, 12, 30, 0))
|
||||
assert vDatetime(dutc).to_ical() == b"20010101T123000Z"
|
||||
|
||||
|
||||
def test_to_ical_utc_1899(tzp):
|
||||
dutc = tzp.localize_utc(datetime(1899, 1, 1, 12, 30, 0))
|
||||
assert vDatetime(dutc).to_ical() == b"18990101T123000Z"
|
||||
|
||||
|
||||
def test_bad_ical():
|
||||
with pytest.raises(ValueError):
|
||||
vDatetime.from_ical("20010101T000000A")
|
||||
|
||||
|
||||
def test_roundtrip():
|
||||
utc = vDatetime.from_ical("20010101T000000Z")
|
||||
assert vDatetime(utc).to_ical() == b"20010101T000000Z"
|
||||
|
||||
|
||||
def test_transition(tzp):
|
||||
# 1 minute before transition to DST
|
||||
dat = vDatetime.from_ical("20120311T015959", "America/Denver")
|
||||
assert dat.strftime("%Y%m%d%H%M%S %z") == "20120311015959 -0700"
|
||||
|
||||
# After transition to DST
|
||||
dat = vDatetime.from_ical("20120311T030000", "America/Denver")
|
||||
assert dat.strftime("%Y%m%d%H%M%S %z") == "20120311030000 -0600"
|
||||
|
||||
dat = vDatetime.from_ical("20101010T000000", "Europe/Vienna")
|
||||
assert vDatetime(dat).to_ical() == b"20101010T000000"
|
||||
@@ -0,0 +1,63 @@
|
||||
import unittest
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from icalendar.prop import vPeriod
|
||||
|
||||
|
||||
class TestProp(unittest.TestCase):
|
||||
def test_one_day(self):
|
||||
# One day in exact datetimes
|
||||
per = (datetime(2000, 1, 1), datetime(2000, 1, 2))
|
||||
self.assertEqual(vPeriod(per).to_ical(), b"20000101T000000/20000102T000000")
|
||||
|
||||
per = (datetime(2000, 1, 1), timedelta(days=31))
|
||||
self.assertEqual(vPeriod(per).to_ical(), b"20000101T000000/P31D")
|
||||
|
||||
def test_roundtrip(self):
|
||||
p = vPeriod.from_ical("20000101T000000/20000102T000000")
|
||||
self.assertEqual(p, (datetime(2000, 1, 1, 0, 0), datetime(2000, 1, 2, 0, 0)))
|
||||
self.assertEqual(vPeriod(p).to_ical(), b"20000101T000000/20000102T000000")
|
||||
|
||||
self.assertEqual(
|
||||
vPeriod.from_ical("20000101T000000/P31D"),
|
||||
(datetime(2000, 1, 1, 0, 0), timedelta(31)),
|
||||
)
|
||||
|
||||
def test_round_trip_with_absolute_time(self):
|
||||
p = vPeriod.from_ical("20000101T000000Z/20000102T000000Z")
|
||||
self.assertEqual(vPeriod(p).to_ical(), b"20000101T000000Z/20000102T000000Z")
|
||||
|
||||
def test_bad_input(self):
|
||||
self.assertRaises(ValueError, vPeriod.from_ical, "20000101T000000/Psd31D")
|
||||
|
||||
|
||||
def test_timezoned(tzp):
|
||||
start = tzp.localize(datetime(2000, 1, 1), "Europe/Copenhagen")
|
||||
end = tzp.localize(datetime(2000, 1, 2), "Europe/Copenhagen")
|
||||
per = (start, end)
|
||||
assert vPeriod(per).to_ical() == b"20000101T000000/20000102T000000"
|
||||
assert vPeriod(per).params["TZID"] == "Europe/Copenhagen"
|
||||
|
||||
|
||||
def test_timezoned_with_timedelta(tzp):
|
||||
p = vPeriod(
|
||||
(tzp.localize(datetime(2000, 1, 1), "Europe/Copenhagen"), timedelta(days=31))
|
||||
)
|
||||
assert p.to_ical() == b"20000101T000000/P31D"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"params",
|
||||
[
|
||||
("20000101T000000", datetime(2000, 1, 2)),
|
||||
(datetime(2000, 1, 1), "20000102T000000"),
|
||||
(datetime(2000, 1, 2), datetime(2000, 1, 1)),
|
||||
(datetime(2000, 1, 2), timedelta(-1)),
|
||||
],
|
||||
)
|
||||
def test_invalid_parameters(params):
|
||||
"""The parameters are of wrong type or of wrong order."""
|
||||
with pytest.raises(ValueError):
|
||||
vPeriod(params)
|
||||
@@ -0,0 +1,27 @@
|
||||
import pytest
|
||||
|
||||
from icalendar.prop import vWeekday
|
||||
|
||||
|
||||
def test_simple():
|
||||
weekday = vWeekday("SU")
|
||||
assert weekday.to_ical() == b"SU"
|
||||
assert weekday.weekday == "SU"
|
||||
assert weekday.relative is None
|
||||
|
||||
|
||||
def test_relative():
|
||||
weekday = vWeekday("-1MO")
|
||||
assert weekday.to_ical() == b"-1MO"
|
||||
assert weekday.weekday == "MO"
|
||||
assert weekday.relative == -1
|
||||
|
||||
|
||||
def test_roundtrip():
|
||||
assert vWeekday.from_ical(vWeekday("+2TH").to_ical()) == "+2TH"
|
||||
|
||||
|
||||
def test_error():
|
||||
"""Error: Expected weekday abbrevation, got: \"-100MO\" """
|
||||
with pytest.raises(ValueError):
|
||||
vWeekday.from_ical("-100MO")
|
||||
@@ -0,0 +1,22 @@
|
||||
"""Test the mappings from windows to olson tzids"""
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from icalendar import vDatetime
|
||||
from icalendar.timezone.windows_to_olson import WINDOWS_TO_OLSON
|
||||
|
||||
|
||||
def test_windows_timezone(tzp):
|
||||
"""Test that the timezone is mapped correctly to olson."""
|
||||
dt = vDatetime.from_ical("20170507T181920", "Eastern Standard Time")
|
||||
expected = tzp.localize(datetime(2017, 5, 7, 18, 19, 20), "America/New_York")
|
||||
assert dt.tzinfo == expected.tzinfo
|
||||
assert dt == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("olson_id", WINDOWS_TO_OLSON.values())
|
||||
def test_olson_names(tzp, olson_id):
|
||||
"""test if all mappings actually map to valid tzids"""
|
||||
assert tzp.timezone(olson_id) is not None
|
||||
Reference in New Issue
Block a user