File: Console.kt

package info (click to toggle)
kotlin 1.3.31%2Bds1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 109,908 kB
  • sloc: java: 454,756; xml: 18,599; javascript: 10,452; sh: 513; python: 97; makefile: 69; ansic: 4
file content (100 lines) | stat: -rw-r--r-- 3,365 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
 * that can be found in the license/LICENSE.txt file.
 */

@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")

package test.io

import org.junit.Test
import java.nio.charset.Charset
import kotlin.test.*

class ConsoleTest {
    private val linuxLineSeparator: String = "\n"
    private val windowsLineSeparator: String = "\r\n"

    @Test
    fun shouldReadEmptyLine() {
        testReadLine("", emptyList())
    }

    @Test
    fun shouldReadSingleLine() {
        for (length in 1..3) {
            val line = buildString { repeat(length) { append('a' + it) } }
            testReadLine(line, listOf(line))
        }
    }

    @Test
    fun trailingEmptyLineIsIgnored() {
        testReadLine(linuxLineSeparator, listOf(""))
        testReadLine(windowsLineSeparator, listOf(""))
        testReadLine("a$linuxLineSeparator", listOf("a"))
        testReadLine("a$windowsLineSeparator", listOf("a"))
    }

    @Test
    fun shouldReadOneLine() {
        testReadLine("first", listOf("first"))
    }

    @Test
    fun shouldReadTwoLines() {
        testReadLine("first${linuxLineSeparator}second", listOf("first", "second"))
    }

    @Test
    fun shouldReadConsecutiveEmptyLines() {
        testReadLine("$linuxLineSeparator$linuxLineSeparator", listOf("", ""))
        testReadLine("$linuxLineSeparator$windowsLineSeparator", listOf("", ""))
        testReadLine("$windowsLineSeparator$linuxLineSeparator", listOf("", ""))
        testReadLine("$windowsLineSeparator$windowsLineSeparator", listOf("", ""))
    }

    @Test
    fun shouldReadWindowsLineSeparator() {
        testReadLine("first${windowsLineSeparator}second", listOf("first", "second"))
    }

    @Test
    fun shouldReadMultibyteEncodings() {
        testReadLine("first${linuxLineSeparator}second", listOf("first", "second"), charset = Charsets.UTF_32)
    }

    @Test
    fun readSurrogatePairs() {
        val c = "\uD83D\uDC4D" // thumb-up emoji
        testReadLine("$c$linuxLineSeparator", listOf(c))
        testReadLine("e $c$linuxLineSeparator", listOf("e $c"))
        testReadLine("$c$windowsLineSeparator", listOf(c))
        testReadLine("e $c$c", listOf("e $c$c"))
        testReadLine("e $c$linuxLineSeparator$c", listOf("e $c", c))
    }

    private fun testReadLine(text: String, expected: List<String>, charset: Charset = Charsets.UTF_8) {
        val actual = readLines(text, charset)
        assertEquals(expected, actual)
        val referenceExpected = readLinesReference(text, charset)
        assertEquals(referenceExpected, actual, "Comparing to reference readLine")

    }

    private fun readLines(text: String, charset: Charset): List<String> {
        text.byteInputStream(charset).use { stream ->
            val decoder = charset.newDecoder()
            @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
            return generateSequence { readLine(stream, decoder) }.toList().also {
                assertTrue("All bytes should be read") { stream.read() == -1 }
            }
        }
    }

    private fun readLinesReference(text: String, charset: Charset): List<String> {
        text.byteInputStream(charset).bufferedReader(charset).use { reader ->
            return generateSequence { reader.readLine() }.toList()
        }
    }
}