diff --git a/core/src/main/scala/io/chrisdavenport/shellfish/FilesOs.scala b/core/src/main/scala/io/chrisdavenport/shellfish/FilesOs.scala index 2d29c1c..e3d90bd 100644 --- a/core/src/main/scala/io/chrisdavenport/shellfish/FilesOs.scala +++ b/core/src/main/scala/io/chrisdavenport/shellfish/FilesOs.scala @@ -81,7 +81,8 @@ object FilesOs { /** * Reads the contents of the file at the path using UTF-8 decoding and returns - * it line by line as a List of Strings. + * it line by line as a List of Strings. It will ignore any empty characters + * after the last newline (similar to `wc -l`). * * @param path * The path to read from @@ -89,7 +90,11 @@ object FilesOs { * The file loaded in memory as a collection of lines of Strings */ def readLines(path: Path): IO[List[String]] = - files.readUtf8Lines(path).compile.toList + files + .readUtf8Lines(path) + .dropLastIf(_.isEmpty) + .compile + .toList /** * Reads the contents of the file and deserializes its contents as `A` using diff --git a/core/src/main/scala/io/chrisdavenport/shellfish/syntax/path/package.scala b/core/src/main/scala/io/chrisdavenport/shellfish/syntax/path/package.scala index 636f1a2..d70c190 100644 --- a/core/src/main/scala/io/chrisdavenport/shellfish/syntax/path/package.scala +++ b/core/src/main/scala/io/chrisdavenport/shellfish/syntax/path/package.scala @@ -75,7 +75,8 @@ package object path { /** * Reads the contents of the file at the path using UTF-8 decoding and - * returns it line by line as a List of Strings. + * returns it line by line as a List of Strings. It will ignore any empty + * characters after the last newline (similar to `wc -l`). * * @param path * The path to read from diff --git a/core/src/test/scala/io/chrisdavenport/shellfish/FileOsSpec.scala b/core/src/test/scala/io/chrisdavenport/shellfish/FileOsSpec.scala index 9ab30ca..cb51965 100644 --- a/core/src/test/scala/io/chrisdavenport/shellfish/FileOsSpec.scala +++ b/core/src/test/scala/io/chrisdavenport/shellfish/FileOsSpec.scala @@ -80,7 +80,8 @@ object FileOsSpec extends SimpleIOSuite with Checkers { sizeBefore <- path.readLines.map(_.size) _ <- path.appendLine("Im a last line!") sizeAfter <- path.readLines.map(_.size) - } yield expect(sizeBefore + 1 == sizeAfter) + } yield expect(sizeBefore + 2 == sizeAfter) + // That is, one new line of the appendLine and, one newline character of the writeLines method } } } @@ -322,7 +323,7 @@ object FileOsSpec extends SimpleIOSuite with Checkers { } } - // Warning: Platform dependent test; this may fail on some operating systems + // Warning: Platform-dependent test; this may fail on some operating systems test("We should be able to get the file permissions in POSIX systems") { val permissionsGenerator: Gen[PosixPermissions] = @@ -343,4 +344,20 @@ object FileOsSpec extends SimpleIOSuite with Checkers { } } + test( + "Writing lines should return a list with the same length when reading them" + ) { + val contentGenerator: Gen[List[String]] = + Gen.size.flatMap(size => Gen.listOfN(size, Gen.alphaNumStr)) + + forall(contentGenerator) { contentsList => + withTempFile { path => + for { + _ <- path.writeLines(contentsList) + readlns <- path.readLines + } yield expect(contentsList.length == readlns.length) + } + } + } + }