66
77package at.bitfire.synctools.icalendar.validation
88
9+ import com.google.common.io.CharStreams
910import io.mockk.junit4.MockKRule
1011import io.mockk.mockkObject
1112import io.mockk.spyk
@@ -18,7 +19,10 @@ import org.junit.Assert.assertTrue
1819import org.junit.Rule
1920import org.junit.Test
2021import java.io.InputStreamReader
22+ import java.io.Reader
2123import java.io.StringReader
24+ import java.io.Writer
25+ import java.util.UUID
2226
2327class ICalPreprocessorTest {
2428
@@ -27,20 +31,6 @@ class ICalPreprocessorTest {
2731
2832 val processor = ICalPreprocessor ()
2933
30-
31- @Test
32- fun testPreprocessStream_runsApplyPreprocessors () {
33- val processor = spyk<ICalPreprocessor >()
34-
35- // readText MUST be called. Otherwise the sequence is never evaluated
36- // there must be at least one line. Otherwise the sequence is empty
37- processor.preprocessStream(StringReader (" \n " )).use { it.readText() }
38-
39- // verify that applyPreprocessors has been called
40- verify { processor.applyPreprocessors(any()) }
41- }
42-
43-
4434 @Test
4535 fun testApplyPreprocessors_appliesStreamProcessors () {
4636 val preprocessors = processor.streamPreprocessors
@@ -59,7 +49,6 @@ class ICalPreprocessorTest {
5949 }
6050 }
6151
62-
6352 @Test
6453 fun testPreprocessCalendar_MsTimeZones () {
6554 javaClass.getResourceAsStream(" /events/outlook1.ics" ).use { stream ->
@@ -73,4 +62,107 @@ class ICalPreprocessorTest {
7362 }
7463 }
7564
65+ @Test
66+ fun testPreprocessStream_runsApplyPreprocessors () {
67+ val processor = spyk<ICalPreprocessor >()
68+
69+ // readText MUST be called. Otherwise the sequence is never evaluated
70+ // there must be at least one line. Otherwise the sequence is empty
71+ processor.preprocessStream(StringReader (" \n " )).use { it.readText() }
72+
73+ // verify that applyPreprocessors has been called
74+ verify { processor.applyPreprocessors(any()) }
75+ }
76+
77+ @Test
78+ fun testPreprocessStream_LargeFiles () {
79+ val preprocessor = ICalPreprocessor ()
80+ val reader = VCalendarReaderGenerator (eventCount = 10_000 )
81+ preprocessor.preprocessStream(reader).use { preprocessed ->
82+ // consume preprocessed stream
83+ val start = System .currentTimeMillis()
84+ CharStreams .copy(preprocessed, Writer .nullWriter())
85+ val end = System .currentTimeMillis()
86+
87+ // no exception called
88+ System .err.println (" testParse_SuperLargeFiles took ${(end - start) / 1000 } seconds" )
89+ }
90+ }
91+
92+
93+ /* *
94+ * Reader that generates a number of VEVENTs for testing.
95+ */
96+ private class VCalendarReaderGenerator (val eventCount : Int ) : Reader() {
97+ private var stage = 0 // 0 = header, 1 = events, 2 = footer, 3 = done
98+ private var eventIdx = 0
99+ private var current: String? = null
100+ private var pos = 0
101+
102+ override fun reset () {
103+ stage = 0
104+ eventIdx = 0
105+ current = null
106+ pos = 0
107+ }
108+
109+ override fun read (cbuf : CharArray , off : Int , len : Int ): Int {
110+ var charsRead = 0
111+ while (charsRead < len) {
112+ if (current == null || pos >= current!! .length) {
113+ current = when (stage) {
114+ 0 -> {
115+ stage = 1
116+ """
117+ BEGIN:VCALENDAR
118+ PRODID:-//xyz Corp//NONSGML PDA Calendar Version 1.0//EN
119+ VERSION:2.0
120+ """ .trimIndent() + " \n "
121+ }
122+ 1 -> {
123+ if (eventIdx < eventCount) {
124+ val event = """
125+ BEGIN:VEVENT
126+ DTSTAMP:19960704T120000Z
127+ UID:${UUID .randomUUID()}
128+ ORGANIZER:mailto:[email protected] 129+ DTSTART:19960918T143000Z
130+ DTEND:19960920T220000Z
131+ STATUS:CONFIRMED
132+ CATEGORIES:CONFERENCE
133+ SUMMARY:Event $eventIdx
134+ DESCRIPTION:Event $eventIdx description
135+ END:VEVENT
136+ """ .trimIndent() + " \n "
137+ eventIdx++
138+ event
139+ } else {
140+ stage = 2
141+ null
142+ }
143+ }
144+ 2 -> {
145+ stage = 3
146+ " END:VCALENDAR\n "
147+ }
148+ else -> return if (charsRead == 0 ) - 1 else charsRead
149+ }
150+ pos = 0
151+ if (current == null ) continue // move to next stage
152+ }
153+ val charsLeft = current!! .length - pos
154+ val toRead = minOf(len - charsRead, charsLeft)
155+ current!! .toCharArray(pos, pos + toRead).copyInto(cbuf, off + charsRead)
156+ pos + = toRead
157+ charsRead + = toRead
158+ }
159+ return charsRead
160+ }
161+
162+ override fun close () {
163+ // No resources to release
164+ current = null
165+ }
166+ }
167+
76168}
0 commit comments