<commit_before>import datetime as dt
import logging
import os
from textwrap import dedent
from time import sleep

import khal.khalendar.exceptions
import khal.utils
import pytest
from freezegun import freeze_time
from khal.khalendar import CalendarCollection
from khal.khalendar.backend import CouldNotCreateDbDir
from khal.khalendar.event import Event
from khal.khalendar.vdir import Item

from . import utils
from .utils import (_get_text, cal1, cal2, cal3, normalize_component, DumbItem,
                    BERLIN, LONDON, SYDNEY, LOCALE_SYDNEY, LOCALE_BERLIN)

today = dt.date.today()
yesterday = today - dt.timedelta(days=1)
tomorrow = today + dt.timedelta(days=1)

aday = dt.date(2014, 4, 9)
bday = dt.date(2014, 4, 10)

event_allday_template = """BEGIN:VEVENT
SEQUENCE:0
UID:<EMAIL>
DTSTART;VALUE=DATE:{}
DTEND;VALUE=DATE:{}
SUMMARY:a meeting
DESCRIPTION:short description
LOCATION:LDB Lobby
END:VEVENT"""

event_today = event_allday_template.format(
    today.strftime('%Y%m%d'), tomorrow.strftime('%Y%m%d'))
item_today = Item(event_today)
SIMPLE_EVENT_UID = 'V042MJ8B3SJNFXQOJL6P53OFMHJE8Z3VZWOU'


class TestCalendar(object):

    def test_create(self, coll_vdirs):
        assert True

    def test_new_event(self, coll_vdirs, sleep_time):
        coll, vdirs = coll_vdirs
        event = coll.new_event(event_today, cal1)
        assert event.calendar == cal1
        coll.new(event)
        events = list(coll.get_events_on(today))
        assert len(events) == 1
        assert events[0].color == 'dark blue'
        assert len(list(coll.get_events_on(tomorrow))) == 0
        assert len(list(coll.get_events_on(yesterday))) == 0
        assert len(list(vdirs[cal1].list())) == 1

    def test_sanity(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        mtimes = dict()
        for i in range(100):
            for cal in coll._calendars:
                mtime = coll._local_ctag(cal)
                if mtimes.get(cal):
                    assert mtimes[cal] == mtime
                else:
                    mtimes[cal] = mtime

    def test_db_needs_update(self, coll_vdirs, sleep_time):
        coll, vdirs = coll_vdirs

        print('init')
        for calendar in coll._calendars:
            print('{}: saved ctag: {}, vdir ctag: {}'.format(
                calendar, coll._local_ctag(calendar), coll._backend.get_ctag(calendar)))
        assert len(list(vdirs[cal1].list())) == 0
        assert coll._needs_update(cal1) is False
        sleep(sleep_time)

        vdirs[cal1].upload(item_today)
        print('upload')
        for calendar in coll._calendars:
            print('{}: saved ctag: {}, vdir ctag: {}'.format(
                calendar, coll._local_ctag(calendar), coll._backend.get_ctag(calendar)))
        assert len(list(vdirs[cal1].list())) == 1
        assert coll._needs_update(cal1) is True
        coll.update_db()
        print('updated')
        for calendar in coll._calendars:
            print('{}: saved ctag: {}, vdir ctag: {}'.format(
                calendar, coll._local_ctag(calendar), coll._backend.get_ctag(calendar)))
        assert coll._needs_update(cal1) is False


class TestVdirsyncerCompat(object):
    def test_list(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        event = Event.fromString(_get_text('event_d'), calendar=cal1, locale=LOCALE_BERLIN)
        assert event.etag is None
        assert event.href is None
        coll.new(event)
        assert event.etag is not None
        assert event.href == 'V042MJ8B3SJNFXQOJL6P53OFMHJE8Z3VZWOU.ics'
        event = Event.fromString(event_today, calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event)
        hrefs = sorted(href for href, etag in coll._backend.list(cal1))
        assert set(str(coll.get_event(href, calendar=cal1).uid) for href in hrefs) == set((
            '<EMAIL>',
            'V042MJ8B3SJNFXQOJL6P53OFMHJE8Z3VZWOU',
        ))


class TestCollection(object):

    astart = dt.datetime.combine(aday, dt.time.min)
    aend = dt.datetime.combine(aday, dt.time.max)
    bstart = dt.datetime.combine(bday, dt.time.min)
    bend = dt.datetime.combine(bday, dt.time.max)
    astart_berlin = utils.BERLIN.localize(astart)
    aend_berlin = utils.BERLIN.localize(aend)
    bstart_berlin = utils.BERLIN.localize(bstart)
    bend_berlin = utils.BERLIN.localize(bend)

    def test_default_calendar(self, tmpdir):
        calendars = {
            'foobar': {'name': 'foobar', 'path': str(tmpdir), 'readonly': True},
            'home': {'name': 'home', 'path': str(tmpdir)},
            'work': {'name': 'work', 'path': str(tmpdir), 'readonly': True},
        }
        coll = CalendarCollection(
            calendars=calendars, locale=LOCALE_BERLIN, dbpath=':memory:',
        )
        assert coll.default_calendar_name is None
        with pytest.raises(ValueError):
            coll.default_calendar_name = 'work'
        assert coll.default_calendar_name is None
        with pytest.raises(ValueError):
            coll.default_calendar_name = 'unknownstuff'
        assert coll.default_calendar_name is None
        coll.default_calendar_name = 'home'
        assert coll.default_calendar_name == 'home'
        assert coll.writable_names == ['home']

    def test_empty(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        start = dt.datetime.combine(today, dt.time.min)
        end = dt.datetime.combine(today, dt.time.max)
        assert list(coll.get_floating(start, end)) == list()
        assert list(coll.get_localized(utils.BERLIN.localize(start),
                                       utils.BERLIN.localize(end))) == list()

    def test_insert(self, coll_vdirs):
        """insert a localized event"""
        coll, vdirs = coll_vdirs
        coll.new(
            Event.fromString(_get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN),
            cal1)
        events = list(coll.get_localized(self.astart_berlin, self.aend_berlin))
        assert len(events) == 1
        assert events[0].color == 'dark blue'
        assert events[0].calendar == cal1

        events = list(coll.get_events_on(aday))
        assert len(events) == 1
        assert events[0].color == 'dark blue'
        assert events[0].calendar == cal1

        assert len(list(vdirs[cal1].list())) == 1
        assert len(list(vdirs[cal2].list())) == 0
        assert len(list(vdirs[cal3].list())) == 0
        assert list(coll.get_floating(self.astart, self.aend)) == []

    def test_insert_d(self, coll_vdirs):
        """insert a floating event"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(_get_text('event_d'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        events = list(coll.get_events_on(aday))
        assert len(events) == 1
        assert events[0].calendar == cal1
        assert events[0].color == 'dark blue'
        assert len(list(vdirs[cal1].list())) == 1
        assert len(list(vdirs[cal2].list())) == 0
        assert len(list(vdirs[cal3].list())) == 0
        assert list(coll.get_localized(self.bstart_berlin, self.bend_berlin)) == []

    def test_insert_d_no_value(self, coll_vdirs):
        """insert a date event with no VALUE=DATE option"""
        coll, vdirs = coll_vdirs
        coll.new(
            Event.fromString(
                _get_text('event_d_no_value'), calendar=cal1, locale=LOCALE_BERLIN),
            cal1)
        events = list(coll.get_events_on(aday))
        assert len(events) == 1
        assert events[0].calendar == cal1
        assert len(list(vdirs[cal1].list())) == 1
        assert len(list(vdirs[cal2].list())) == 0
        assert len(list(vdirs[cal3].list())) == 0
        assert list(coll.get_localized(self.bstart_berlin, self.bend_berlin)) == []

    def test_get(self, coll_vdirs):
        """test getting an event by its href"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(
            _get_text('event_dt_simple'), href='xyz.ics', calendar=cal1, locale=LOCALE_BERLIN,
        )
        coll.new(event, cal1)
        event_from_db = coll.get_event(SIMPLE_EVENT_UID + '.ics', cal1)
        with freeze_time('2016-1-1'):
            assert normalize_component(event_from_db.raw) == \
                normalize_component(_get_text('event_dt_simple_inkl_vtimezone'))

    def test_change(self, coll_vdirs):
        """moving an event from one calendar to another"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(_get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        event = list(coll.get_events_on(aday))[0]
        assert event.calendar == cal1

        coll.change_collection(event, cal2)
        events = list(coll.get_events_on(aday))
        assert len(events) == 1
        assert events[0].calendar == cal2

    def test_update_event(self, coll_vdirs):
        """updating one event"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(
            _get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        events = coll.get_events_on(aday)
        event = list(events)[0]
        event.update_summary('really simple event')
        event.update_start_end(bday, bday)
        coll.update(event)
        events = list(coll.get_localized(self.astart_berlin, self.aend_berlin))
        assert len(events) == 0
        events = list(coll.get_floating(self.bstart, self.bend))
        assert len(events) == 1
        assert events[0].summary == 'really simple event'

    def test_newevent(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        bday = dt.datetime.combine(aday, dt.time.min)
        anend = bday + dt.timedelta(hours=1)
        event = khal.utils.new_event(
            dtstart=bday, dtend=anend, summary="hi", timezone=utils.BERLIN,
            locale=LOCALE_BERLIN,
        )
        event = coll.new_event(event.to_ical(), coll.default_calendar_name)
        assert event.allday is False

    def test_modify_readonly_calendar(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        coll._calendars[cal1]['readonly'] = True
        coll._calendars[cal3]['readonly'] = True
        event = Event.fromString(_get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)

        with pytest.raises(khal.khalendar.exceptions.ReadOnlyCalendarError):
            coll.new(event, cal1)
        with pytest.raises(khal.khalendar.exceptions.ReadOnlyCalendarError):
            # params don't really matter here
            coll.delete('href', 'eteg', cal1)

    def test_search(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        assert len(list(coll.search('Event'))) == 0
        event = Event.fromString(
            _get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        assert len(list(coll.search('Event'))) == 1
        event = Event.fromString(
            _get_text('event_dt_floating'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        assert len(list(coll.search('Search for me'))) == 1
        assert len(list(coll.search('Event'))) == 2

    def test_search_recurrence_id_only(self, coll_vdirs):
        """test searching for recurring events which only have a recuid event,
        and no master"""
        coll, vdirs = coll_vdirs
        assert len(list(coll.search('Event'))) == 0
        event = Event.fromString(
            _get_text('event_dt_recuid_no_master'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        assert len(list(coll.search('Event'))) == 1

    def test_search_recurrence_id_only_multi(self, coll_vdirs):
        """test searching for recurring events which only have a recuid event,
        and no master"""
        coll, vdirs = coll_vdirs
        assert len(list(coll.search('Event'))) == 0
        event = Event.fromString(
            _get_text('event_dt_multi_recuid_no_master'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        events = list(sorted(coll.search('Event')))
        assert len(events) == 2
        assert events[0].format(
            '{start} {end} {title}', dt.date.today()) == '30.06. 07:30 30.06. 12:00 Arbeit\x1b[0m'
        assert events[1].format(
            '{start} {end} {title}', dt.date.today()) == '07.07. 08:30 07.07. 12:00 Arbeit\x1b[0m'

    def test_delete_two_events(self, coll_vdirs, sleep_time):
            """testing if we can delete any of two events in two different
            calendars with the same filename"""
            coll, vdirs = coll_vdirs
            event1 = Event.fromString(
                _get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
            event2 = Event.fromString(
                _get_text('event_dt_simple'), calendar=cal2, locale=LOCALE_BERLIN)
            coll.new(event1, cal1)
            sleep(sleep_time)  # make sure the etags are different
            coll.new(event2, cal2)
            etag1 = list(vdirs[cal1].list())[0][1]
            etag2 = list(vdirs[cal2].list())[0][1]
            events = list(coll.get_localized(self.astart_berlin, self.aend_berlin))
            assert len(events) == 2
            assert events[0].calendar != events[1].calendar
            for event in events:
                if event.calendar == cal1:
                    assert event.etag == etag1
                if event.calendar == cal2:
                    assert event.etag == etag2

    def test_invalid_timezones(self, coll_vdirs):
        """testing if we can delete any of two events in two different
        calendars with the same filename"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(
            _get_text('invalid_tzoffset'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        events = list(sorted(coll.search('Event')))
        assert len(events) == 1
        assert events[0].format('{start} {end} {title}', dt.date.today()) == \
            '02.12. 08:00 02.12. 09:30 Some event\x1b[0m'

    def test_multi_uid_vdir(self, coll_vdirs, caplog):
        coll, vdirs = coll_vdirs
        vdirs[cal1].upload(DumbItem(_get_text('event_dt_multi_uid'), uid='12345'))
        caplog.set_level(logging.WARNING)
        coll.update_db()
        assert list(coll.search('')) == []
        messages = [rec.message for rec in caplog.records]
        assert messages[0].startswith(
            "The .ics file at foobar/12345.ics contains multiple UIDs.\n"
        )
        assert messages[1].startswith(
            "Skipping foobar/12345.ics: \nThis event will not be available in khal."
        )
<commit_msg>initialize click_log<commit_after>import datetime as dt
import logging
import os
from textwrap import dedent
from time import sleep

import khal.khalendar.exceptions
import khal.utils
import pytest
from freezegun import freeze_time
from khal.khalendar import CalendarCollection
from khal.khalendar.backend import CouldNotCreateDbDir
from khal.khalendar.event import Event
from khal.khalendar.vdir import Item

from . import utils
from .utils import (_get_text, cal1, cal2, cal3, normalize_component, DumbItem,
                    BERLIN, LONDON, SYDNEY, LOCALE_SYDNEY, LOCALE_BERLIN)

today = dt.date.today()
yesterday = today - dt.timedelta(days=1)
tomorrow = today + dt.timedelta(days=1)

aday = dt.date(2014, 4, 9)
bday = dt.date(2014, 4, 10)

event_allday_template = """BEGIN:VEVENT
SEQUENCE:0
UID:<EMAIL>
DTSTART;VALUE=DATE:{}
DTEND;VALUE=DATE:{}
SUMMARY:a meeting
DESCRIPTION:short description
LOCATION:LDB Lobby
END:VEVENT"""

event_today = event_allday_template.format(
    today.strftime('%Y%m%d'), tomorrow.strftime('%Y%m%d'))
item_today = Item(event_today)
SIMPLE_EVENT_UID = 'V042MJ8B3SJNFXQOJL6P53OFMHJE8Z3VZWOU'


class TestCalendar(object):

    def test_create(self, coll_vdirs):
        assert True

    def test_new_event(self, coll_vdirs, sleep_time):
        coll, vdirs = coll_vdirs
        event = coll.new_event(event_today, cal1)
        assert event.calendar == cal1
        coll.new(event)
        events = list(coll.get_events_on(today))
        assert len(events) == 1
        assert events[0].color == 'dark blue'
        assert len(list(coll.get_events_on(tomorrow))) == 0
        assert len(list(coll.get_events_on(yesterday))) == 0
        assert len(list(vdirs[cal1].list())) == 1

    def test_sanity(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        mtimes = dict()
        for i in range(100):
            for cal in coll._calendars:
                mtime = coll._local_ctag(cal)
                if mtimes.get(cal):
                    assert mtimes[cal] == mtime
                else:
                    mtimes[cal] = mtime

    def test_db_needs_update(self, coll_vdirs, sleep_time):
        coll, vdirs = coll_vdirs

        print('init')
        for calendar in coll._calendars:
            print('{}: saved ctag: {}, vdir ctag: {}'.format(
                calendar, coll._local_ctag(calendar), coll._backend.get_ctag(calendar)))
        assert len(list(vdirs[cal1].list())) == 0
        assert coll._needs_update(cal1) is False
        sleep(sleep_time)

        vdirs[cal1].upload(item_today)
        print('upload')
        for calendar in coll._calendars:
            print('{}: saved ctag: {}, vdir ctag: {}'.format(
                calendar, coll._local_ctag(calendar), coll._backend.get_ctag(calendar)))
        assert len(list(vdirs[cal1].list())) == 1
        assert coll._needs_update(cal1) is True
        coll.update_db()
        print('updated')
        for calendar in coll._calendars:
            print('{}: saved ctag: {}, vdir ctag: {}'.format(
                calendar, coll._local_ctag(calendar), coll._backend.get_ctag(calendar)))
        assert coll._needs_update(cal1) is False


class TestVdirsyncerCompat(object):
    def test_list(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        event = Event.fromString(_get_text('event_d'), calendar=cal1, locale=LOCALE_BERLIN)
        assert event.etag is None
        assert event.href is None
        coll.new(event)
        assert event.etag is not None
        assert event.href == 'V042MJ8B3SJNFXQOJL6P53OFMHJE8Z3VZWOU.ics'
        event = Event.fromString(event_today, calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event)
        hrefs = sorted(href for href, etag in coll._backend.list(cal1))
        assert set(str(coll.get_event(href, calendar=cal1).uid) for href in hrefs) == set((
            '<EMAIL>',
            'V042MJ8B3SJNFXQOJL6P53OFMHJE8Z3VZWOU',
        ))


class TestCollection(object):

    astart = dt.datetime.combine(aday, dt.time.min)
    aend = dt.datetime.combine(aday, dt.time.max)
    bstart = dt.datetime.combine(bday, dt.time.min)
    bend = dt.datetime.combine(bday, dt.time.max)
    astart_berlin = utils.BERLIN.localize(astart)
    aend_berlin = utils.BERLIN.localize(aend)
    bstart_berlin = utils.BERLIN.localize(bstart)
    bend_berlin = utils.BERLIN.localize(bend)

    def test_default_calendar(self, tmpdir):
        calendars = {
            'foobar': {'name': 'foobar', 'path': str(tmpdir), 'readonly': True},
            'home': {'name': 'home', 'path': str(tmpdir)},
            'work': {'name': 'work', 'path': str(tmpdir), 'readonly': True},
        }
        coll = CalendarCollection(
            calendars=calendars, locale=LOCALE_BERLIN, dbpath=':memory:',
        )
        assert coll.default_calendar_name is None
        with pytest.raises(ValueError):
            coll.default_calendar_name = 'work'
        assert coll.default_calendar_name is None
        with pytest.raises(ValueError):
            coll.default_calendar_name = 'unknownstuff'
        assert coll.default_calendar_name is None
        coll.default_calendar_name = 'home'
        assert coll.default_calendar_name == 'home'
        assert coll.writable_names == ['home']

    def test_empty(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        start = dt.datetime.combine(today, dt.time.min)
        end = dt.datetime.combine(today, dt.time.max)
        assert list(coll.get_floating(start, end)) == list()
        assert list(coll.get_localized(utils.BERLIN.localize(start),
                                       utils.BERLIN.localize(end))) == list()

    def test_insert(self, coll_vdirs):
        """insert a localized event"""
        coll, vdirs = coll_vdirs
        coll.new(
            Event.fromString(_get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN),
            cal1)
        events = list(coll.get_localized(self.astart_berlin, self.aend_berlin))
        assert len(events) == 1
        assert events[0].color == 'dark blue'
        assert events[0].calendar == cal1

        events = list(coll.get_events_on(aday))
        assert len(events) == 1
        assert events[0].color == 'dark blue'
        assert events[0].calendar == cal1

        assert len(list(vdirs[cal1].list())) == 1
        assert len(list(vdirs[cal2].list())) == 0
        assert len(list(vdirs[cal3].list())) == 0
        assert list(coll.get_floating(self.astart, self.aend)) == []

    def test_insert_d(self, coll_vdirs):
        """insert a floating event"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(_get_text('event_d'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        events = list(coll.get_events_on(aday))
        assert len(events) == 1
        assert events[0].calendar == cal1
        assert events[0].color == 'dark blue'
        assert len(list(vdirs[cal1].list())) == 1
        assert len(list(vdirs[cal2].list())) == 0
        assert len(list(vdirs[cal3].list())) == 0
        assert list(coll.get_localized(self.bstart_berlin, self.bend_berlin)) == []

    def test_insert_d_no_value(self, coll_vdirs):
        """insert a date event with no VALUE=DATE option"""
        coll, vdirs = coll_vdirs
        coll.new(
            Event.fromString(
                _get_text('event_d_no_value'), calendar=cal1, locale=LOCALE_BERLIN),
            cal1)
        events = list(coll.get_events_on(aday))
        assert len(events) == 1
        assert events[0].calendar == cal1
        assert len(list(vdirs[cal1].list())) == 1
        assert len(list(vdirs[cal2].list())) == 0
        assert len(list(vdirs[cal3].list())) == 0
        assert list(coll.get_localized(self.bstart_berlin, self.bend_berlin)) == []

    def test_get(self, coll_vdirs):
        """test getting an event by its href"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(
            _get_text('event_dt_simple'), href='xyz.ics', calendar=cal1, locale=LOCALE_BERLIN,
        )
        coll.new(event, cal1)
        event_from_db = coll.get_event(SIMPLE_EVENT_UID + '.ics', cal1)
        with freeze_time('2016-1-1'):
            assert normalize_component(event_from_db.raw) == \
                normalize_component(_get_text('event_dt_simple_inkl_vtimezone'))

    def test_change(self, coll_vdirs):
        """moving an event from one calendar to another"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(_get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        event = list(coll.get_events_on(aday))[0]
        assert event.calendar == cal1

        coll.change_collection(event, cal2)
        events = list(coll.get_events_on(aday))
        assert len(events) == 1
        assert events[0].calendar == cal2

    def test_update_event(self, coll_vdirs):
        """updating one event"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(
            _get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        events = coll.get_events_on(aday)
        event = list(events)[0]
        event.update_summary('really simple event')
        event.update_start_end(bday, bday)
        coll.update(event)
        events = list(coll.get_localized(self.astart_berlin, self.aend_berlin))
        assert len(events) == 0
        events = list(coll.get_floating(self.bstart, self.bend))
        assert len(events) == 1
        assert events[0].summary == 'really simple event'

    def test_newevent(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        bday = dt.datetime.combine(aday, dt.time.min)
        anend = bday + dt.timedelta(hours=1)
        event = khal.utils.new_event(
            dtstart=bday, dtend=anend, summary="hi", timezone=utils.BERLIN,
            locale=LOCALE_BERLIN,
        )
        event = coll.new_event(event.to_ical(), coll.default_calendar_name)
        assert event.allday is False

    def test_modify_readonly_calendar(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        coll._calendars[cal1]['readonly'] = True
        coll._calendars[cal3]['readonly'] = True
        event = Event.fromString(_get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)

        with pytest.raises(khal.khalendar.exceptions.ReadOnlyCalendarError):
            coll.new(event, cal1)
        with pytest.raises(khal.khalendar.exceptions.ReadOnlyCalendarError):
            # params don't really matter here
            coll.delete('href', 'eteg', cal1)

    def test_search(self, coll_vdirs):
        coll, vdirs = coll_vdirs
        assert len(list(coll.search('Event'))) == 0
        event = Event.fromString(
            _get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        assert len(list(coll.search('Event'))) == 1
        event = Event.fromString(
            _get_text('event_dt_floating'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        assert len(list(coll.search('Search for me'))) == 1
        assert len(list(coll.search('Event'))) == 2

    def test_search_recurrence_id_only(self, coll_vdirs):
        """test searching for recurring events which only have a recuid event,
        and no master"""
        coll, vdirs = coll_vdirs
        assert len(list(coll.search('Event'))) == 0
        event = Event.fromString(
            _get_text('event_dt_recuid_no_master'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        assert len(list(coll.search('Event'))) == 1

    def test_search_recurrence_id_only_multi(self, coll_vdirs):
        """test searching for recurring events which only have a recuid event,
        and no master"""
        coll, vdirs = coll_vdirs
        assert len(list(coll.search('Event'))) == 0
        event = Event.fromString(
            _get_text('event_dt_multi_recuid_no_master'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        events = list(sorted(coll.search('Event')))
        assert len(events) == 2
        assert events[0].format(
            '{start} {end} {title}', dt.date.today()) == '30.06. 07:30 30.06. 12:00 Arbeit\x1b[0m'
        assert events[1].format(
            '{start} {end} {title}', dt.date.today()) == '07.07. 08:30 07.07. 12:00 Arbeit\x1b[0m'

    def test_delete_two_events(self, coll_vdirs, sleep_time):
            """testing if we can delete any of two events in two different
            calendars with the same filename"""
            coll, vdirs = coll_vdirs
            event1 = Event.fromString(
                _get_text('event_dt_simple'), calendar=cal1, locale=LOCALE_BERLIN)
            event2 = Event.fromString(
                _get_text('event_dt_simple'), calendar=cal2, locale=LOCALE_BERLIN)
            coll.new(event1, cal1)
            sleep(sleep_time)  # make sure the etags are different
            coll.new(event2, cal2)
            etag1 = list(vdirs[cal1].list())[0][1]
            etag2 = list(vdirs[cal2].list())[0][1]
            events = list(coll.get_localized(self.astart_berlin, self.aend_berlin))
            assert len(events) == 2
            assert events[0].calendar != events[1].calendar
            for event in events:
                if event.calendar == cal1:
                    assert event.etag == etag1
                if event.calendar == cal2:
                    assert event.etag == etag2

    def test_invalid_timezones(self, coll_vdirs):
        """testing if we can delete any of two events in two different
        calendars with the same filename"""
        coll, vdirs = coll_vdirs
        event = Event.fromString(
            _get_text('invalid_tzoffset'), calendar=cal1, locale=LOCALE_BERLIN)
        coll.new(event, cal1)
        events = list(sorted(coll.search('Event')))
        assert len(events) == 1
        assert events[0].format('{start} {end} {title}', dt.date.today()) == \
            '02.12. 08:00 02.12. 09:30 Some event\x1b[0m'

    def test_multi_uid_vdir(self, coll_vdirs, caplog):
        import click_log
        click_log.basic_config('khal').setLevel(logging.DEBUG)
        coll, vdirs = coll_vdirs
        vdirs[cal1].upload(DumbItem(_get_text('event_dt_multi_uid'), uid='12345'))
        caplog.set_level(logging.WARNING)
        coll.update_db()
        assert list(coll.search('')) == []
        messages = [rec.message for rec in caplog.records]
        assert messages[0].startswith(
            "The .ics file at foobar/12345.ics contains multiple UIDs.\n"
        )
        assert messages[1].startswith(
            "Skipping foobar/12345.ics: \nThis event will not be available in khal."
        )

{'fraction_non_alphanumeric': 0.12071382174968377, 'fraction_numerical': 0.0175720488188438, 'mean_word_length': 2.6934343434343435, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5865902', 'n_tokens_mistral': 9896, 'n_tokens_neox': 9493, 'n_words': 1922}