sbt/server-test/src/test/scala/testpkg/ClientTest.scala

125 lines
3.5 KiB
Scala
Raw Normal View History

/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package testpkg
Add tab completion support to thin client The sbtc client can provide a ux very similar to using the sbt shell when combined with tab completions. In fact, since some shells have a better tab completion engine than that provided by jilne2, the experience can be even better. To make this work, we add another entry point to the thin client that is capable of generating completions for an input string. It queries sbt for the completions and prints the result to stdout, where they are consumed by the shell and fed into its completion engine. In addition to providing tab completions, if there is no server running or if the user is completing `runMain`, `testOnly` or `testQuick`, the thin client will prompt the user to ask if they would like to start an sbt server or if they would like to compile to generate the main class or test names. Neither powershell nor zsh support forwarding input to the tab completion script. Zsh will print output to stderr so we opportunistically start the server or complete the test class names. Powershell does not print completion output at all, so we do not start a server or fill completions in that case*. For fish and bash, we prompt the user that they can take these actions so that they can avoid the expensive operation if desired. * Powershell users can set the environment variable SBTC_AUTO_COMPLETE if they want to automatically start a server of compile for run and test names. No output will be displayed so there can be a long latency between pressing <tab> and seeing completion results if this variable is set.
2020-06-25 03:31:18 +02:00
import java.io.{ InputStream, OutputStream, PrintStream }
import sbt.internal.client.NetworkClient
Add tab completion support to thin client The sbtc client can provide a ux very similar to using the sbt shell when combined with tab completions. In fact, since some shells have a better tab completion engine than that provided by jilne2, the experience can be even better. To make this work, we add another entry point to the thin client that is capable of generating completions for an input string. It queries sbt for the completions and prints the result to stdout, where they are consumed by the shell and fed into its completion engine. In addition to providing tab completions, if there is no server running or if the user is completing `runMain`, `testOnly` or `testQuick`, the thin client will prompt the user to ask if they would like to start an sbt server or if they would like to compile to generate the main class or test names. Neither powershell nor zsh support forwarding input to the tab completion script. Zsh will print output to stderr so we opportunistically start the server or complete the test class names. Powershell does not print completion output at all, so we do not start a server or fill completions in that case*. For fish and bash, we prompt the user that they can take these actions so that they can avoid the expensive operation if desired. * Powershell users can set the environment variable SBTC_AUTO_COMPLETE if they want to automatically start a server of compile for run and test names. No output will be displayed so there can be a long latency between pressing <tab> and seeing completion results if this variable is set.
2020-06-25 03:31:18 +02:00
import sbt.internal.util.Util
import scala.collection.mutable
object ClientTest extends AbstractServerTest {
override val testDirectory: String = "client"
object NullInputStream extends InputStream {
override def read(): Int = {
try this.synchronized(this.wait)
catch { case _: InterruptedException => }
-1
}
}
val NullPrintStream = new PrintStream(_ => {}, false)
Add tab completion support to thin client The sbtc client can provide a ux very similar to using the sbt shell when combined with tab completions. In fact, since some shells have a better tab completion engine than that provided by jilne2, the experience can be even better. To make this work, we add another entry point to the thin client that is capable of generating completions for an input string. It queries sbt for the completions and prints the result to stdout, where they are consumed by the shell and fed into its completion engine. In addition to providing tab completions, if there is no server running or if the user is completing `runMain`, `testOnly` or `testQuick`, the thin client will prompt the user to ask if they would like to start an sbt server or if they would like to compile to generate the main class or test names. Neither powershell nor zsh support forwarding input to the tab completion script. Zsh will print output to stderr so we opportunistically start the server or complete the test class names. Powershell does not print completion output at all, so we do not start a server or fill completions in that case*. For fish and bash, we prompt the user that they can take these actions so that they can avoid the expensive operation if desired. * Powershell users can set the environment variable SBTC_AUTO_COMPLETE if they want to automatically start a server of compile for run and test names. No output will be displayed so there can be a long latency between pressing <tab> and seeing completion results if this variable is set.
2020-06-25 03:31:18 +02:00
class CachingPrintStream extends { val cos = new CachingOutputStream }
with PrintStream(cos, true) {
def lines = cos.lines
}
class CachingOutputStream extends OutputStream {
private val lineBuffer = new mutable.ArrayBuffer[String]
private var byteBuffer = new mutable.ArrayBuffer[Byte]
override def write(i: Int) = {
if (i == 10) {
lineBuffer += new String(byteBuffer.toArray)
byteBuffer = new mutable.ArrayBuffer[Byte]
} else Util.ignoreResult(byteBuffer += i.toByte)
}
def lines = lineBuffer.toVector
}
class FixedInputStream(keys: Char*) extends InputStream {
var i = 0
override def read(): Int = {
if (i < keys.length) {
val res = keys(i).toInt
i += 1
res
} else -1
}
}
private def client(args: String*) =
NetworkClient.client(
testPath.toFile,
args.toArray,
NullInputStream,
NullPrintStream,
NullPrintStream,
false
)
Add tab completion support to thin client The sbtc client can provide a ux very similar to using the sbt shell when combined with tab completions. In fact, since some shells have a better tab completion engine than that provided by jilne2, the experience can be even better. To make this work, we add another entry point to the thin client that is capable of generating completions for an input string. It queries sbt for the completions and prints the result to stdout, where they are consumed by the shell and fed into its completion engine. In addition to providing tab completions, if there is no server running or if the user is completing `runMain`, `testOnly` or `testQuick`, the thin client will prompt the user to ask if they would like to start an sbt server or if they would like to compile to generate the main class or test names. Neither powershell nor zsh support forwarding input to the tab completion script. Zsh will print output to stderr so we opportunistically start the server or complete the test class names. Powershell does not print completion output at all, so we do not start a server or fill completions in that case*. For fish and bash, we prompt the user that they can take these actions so that they can avoid the expensive operation if desired. * Powershell users can set the environment variable SBTC_AUTO_COMPLETE if they want to automatically start a server of compile for run and test names. No output will be displayed so there can be a long latency between pressing <tab> and seeing completion results if this variable is set.
2020-06-25 03:31:18 +02:00
// This ensures that the completion command will send a tab that triggers
// sbt to call definedTestNames or discoveredMainClasses if there hasn't
// been a necessary compilation
def tabs = new FixedInputStream('\t', '\t')
private def complete(completionString: String): Seq[String] = {
val cps = new CachingPrintStream
NetworkClient.complete(
testPath.toFile,
Array(s"--completions=sbtc $completionString"),
false,
tabs,
cps
)
cps.lines
}
test("exit success") { c =>
assert(client("willSucceed") == 0)
}
test("exit failure") { _ =>
assert(client("willFail") == 1)
}
test("two commands") { _ =>
assert(client("compile;willSucceed") == 0)
}
test("two commands with failing second") { _ =>
assert(client("compile;willFail") == 1)
}
test("two commands with leading failure") { _ =>
assert(client("willFail;willSucceed") == 1)
}
test("three commands") { _ =>
assert(client("compile;clean;willSucceed") == 0)
}
test("three commands with middle failure") { _ =>
assert(client("compile;willFail;willSucceed") == 1)
}
Add tab completion support to thin client The sbtc client can provide a ux very similar to using the sbt shell when combined with tab completions. In fact, since some shells have a better tab completion engine than that provided by jilne2, the experience can be even better. To make this work, we add another entry point to the thin client that is capable of generating completions for an input string. It queries sbt for the completions and prints the result to stdout, where they are consumed by the shell and fed into its completion engine. In addition to providing tab completions, if there is no server running or if the user is completing `runMain`, `testOnly` or `testQuick`, the thin client will prompt the user to ask if they would like to start an sbt server or if they would like to compile to generate the main class or test names. Neither powershell nor zsh support forwarding input to the tab completion script. Zsh will print output to stderr so we opportunistically start the server or complete the test class names. Powershell does not print completion output at all, so we do not start a server or fill completions in that case*. For fish and bash, we prompt the user that they can take these actions so that they can avoid the expensive operation if desired. * Powershell users can set the environment variable SBTC_AUTO_COMPLETE if they want to automatically start a server of compile for run and test names. No output will be displayed so there can be a long latency between pressing <tab> and seeing completion results if this variable is set.
2020-06-25 03:31:18 +02:00
test("compi completions") { _ =>
val expected = Vector(
"compile",
"compile:",
"compileAnalysisFile",
"compileAnalysisFilename",
"compileAnalysisTargetRoot",
"compileIncSetup",
"compileIncremental",
"compileOutputs",
"compilers",
)
assert(complete("compi") == expected)
}
test("testOnly completions") { _ =>
val testOnlyExpected = Vector(
"testOnly",
"testOnly/",
"testOnly::",
"testOnly;",
)
assert(complete("testOnly") == testOnlyExpected)
val testOnlyOptionsExpected = Vector("--", ";", "test.pkg.FooSpec")
assert(complete("testOnly ") == testOnlyOptionsExpected)
}
test("quote with semi") { _ =>
assert(complete("\"compile; fooB") == Vector("compile; fooBar"))
}
}