Coverage Summary for Class: Application (lzwpack)

Class Method, % Line, %
Application$ 0% (0/ 13) 0% (0/ 22)
Application$$anon$1 0% (0/ 4) 0% (0/ 10)
Application$OperationMode$ 0% (0/ 1) 0% (0/ 1)
Application$OperationMode$Compress$ 0% (0/ 1) 0% (0/ 1)
Application$OperationMode$Decompress$ 0% (0/ 1) 0% (0/ 1)
Application$Options 0% (0/ 1) 0% (0/ 1)
Application$Options$ 0% (0/ 1) 0% (0/ 1)
total 0% (0/ 22) 0% (0/ 37)


1 package lzwpack 2  3 import java.nio.file.{Path, Paths} 4  5 import cats.effect.{IO, Sync} 6 import fs2.{Sink, Stream} 7  8 object Application { 9  sealed trait OperationMode 10  object OperationMode { 11  case object Compress extends OperationMode 12  case object Decompress extends OperationMode 13  } 14  15  case class Options(path: Path = Paths.get("."), mode: OperationMode = OperationMode.Compress, maxCodeSize: Int = MaxCodeSize) 16  17  def options = new scopt.OptionParser[Options]("lzwpack") { 18  head("lzwpack", "LZW compression utility") 19  20  opt[Unit]('d', "decompress") action { (_, opts) => 21  opts.copy(mode = OperationMode.Decompress) 22  } text "decompress input file instead of compression" 23  24  opt[Int]('b', "bits") action { (n, opts) => opts.copy(maxCodeSize = n) } validate { n => 25  if (n >= 9 && n <= 16) success 26  else failure("Code size must be between 9 and 16") 27  } text "the maximum number of bits to use for each code" 28  29  arg[String]("path") action { (path, opts) => opts.copy(path = Paths.get(path)) } 30  31  help("help").text("prints this usage text") 32  } 33  34  // Use compress(1) compatible alphabet by default 35  import Alphabet.Compress 36  37  def inputStream(path: Path): Stream[IO, Byte] = fs2.io.file.readAll[IO](path, 32768) 38  39  def runCompress(path: Path, maxCodeSize: Int, sink: Sink[IO, Byte] = fs2.io.stdout): IO[Unit] = { 40  inputStream(path) 41  .through(compressAdaptive) 42  .through(CompressHeader.encode) 43  .to(sink) 44  .compile 45  .drain 46  } 47  48  def runDecompress(path: Path, maxCodeSize: Int, sink: Sink[IO, Byte] = fs2.io.stdout): IO[Unit] = { 49  inputStream(path) 50  .through(CompressHeader.decode) 51  .through(decompressAdaptive) 52  .to(sink) 53  .compile 54  .drain 55  } 56  57  def parseOptions(args: Seq[String]): IO[Option[Options]] = IO { 58  options.parse(args, Options()) 59  } 60  61  /** 62  * Parses program options and evaluates the corresponding action. 63  * This function does not actually perform side effects; it just returns a IO instance that can then 64  * be evaluated "at the end of the universe" – the program's [[main]] method. 65  */ 66  def program(args: Seq[String]): IO[Unit] = parseOptions(args) flatMap { 67  case Some(Options(path, OperationMode.Compress, maxCodeSize)) => runCompress(path, maxCodeSize) 68  case Some(Options(path, OperationMode.Decompress, maxCodeSize)) => runDecompress(path, maxCodeSize) 69  case None => IO.unit 70  } 71  72  def main(args: Array[String]): Unit = program(args).unsafeRunSync() 73 }