Skip to content

Commit e1dd30c

Browse files
authored
Merge pull request #3982 from Gedochao/maintenance/rewrite-repl-ammonite-tests
Run the entire REPL test suite on both Ammonite and Scala 3 REPL
2 parents e5503e1 + 9489649 commit e1dd30c

File tree

9 files changed

+434
-377
lines changed

9 files changed

+434
-377
lines changed

modules/integration/src/test/scala/scala/cli/integration/ReplAmmoniteTestDefinitions.scala

Lines changed: 135 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@ package scala.cli.integration
22

33
import com.eed3si9n.expecty.Expecty.expect
44

5-
import scala.cli.integration.TestUtil.removeAnsiColors
6-
import scala.util.Properties
5+
import scala.cli.integration.TestUtil.{normalizeArgsForWindows, removeAnsiColors}
76

87
trait ReplAmmoniteTestDefinitions { this: ReplTestDefinitions =>
9-
protected val retrieveScalaVersionCode: String = if (actualScalaVersion.startsWith("2."))
10-
"scala.util.Properties.versionNumberString"
11-
else "dotty.tools.dotc.config.Properties.simpleVersionString"
12-
8+
protected val ammonitePrefix: String = "Running in Ammonite REPL:"
139
def expectedScalaVersionForAmmonite: String =
1410
actualScalaVersion match {
1511
case s
@@ -32,212 +28,185 @@ trait ReplAmmoniteTestDefinitions { this: ReplTestDefinitions =>
3228
}
3329

3430
def actualMaxAmmoniteScalaVersion: String =
35-
if (actualScalaVersion.startsWith(Constants.scala3LtsPrefix))
31+
if actualScalaVersion.startsWith(Constants.scala3LtsPrefix) then
3632
Constants.maxAmmoniteScala3LtsVersion
37-
else if (actualScalaVersion.startsWith(Constants.scala3NextPrefix))
33+
else if actualScalaVersion.startsWith(Constants.scala3NextPrefix) then
3834
Constants.maxAmmoniteScala3Version
39-
else if (actualScalaVersion.startsWith("2.13")) Constants.maxAmmoniteScala213Version
35+
else if actualScalaVersion.startsWith("2.13") then Constants.maxAmmoniteScala213Version
4036
else Constants.maxAmmoniteScala212Version
4137

38+
def shouldUseMaxAmmoniteScalaVersion: Boolean =
39+
actualScalaVersion.coursierVersion > actualMaxAmmoniteScalaVersion.coursierVersion
40+
4241
def ammoniteExtraOptions: Seq[String] =
43-
Seq("--scala", actualMaxAmmoniteScalaVersion) ++ TestUtil.extraOptions
42+
if !shouldUseMaxAmmoniteScalaVersion then extraOptions
43+
else Seq("--scala", actualMaxAmmoniteScalaVersion) ++ TestUtil.extraOptions
44+
45+
def runInAmmoniteRepl(
46+
codeToRunInRepl: String = "",
47+
testInputs: TestInputs = TestInputs.empty,
48+
cliOptions: Seq[String] = Seq.empty,
49+
extraAmmoniteOptions: Seq[String] = Seq.empty,
50+
shouldPipeStdErr: Boolean = false,
51+
check: Boolean = true,
52+
env: Map[String, String] = Map.empty
53+
)(
54+
runAfterRepl: os.CommandResult => Unit,
55+
runBeforeReplAndGetExtraCliOpts: () => Seq[os.Shellable] = () => Seq.empty
56+
): Unit = {
57+
val ammArgs =
58+
if codeToRunInRepl.nonEmpty then
59+
(Seq("-c", codeToRunInRepl) ++ extraAmmoniteOptions)
60+
.normalizeArgsForWindows
61+
.flatMap(arg => Seq("--ammonite-arg", arg))
62+
else Seq.empty
63+
testInputs.fromRoot { root =>
64+
val potentiallyExtraCliOpts = runBeforeReplAndGetExtraCliOpts()
65+
runAfterRepl(
66+
os.proc(
67+
TestUtil.cli,
68+
"--power",
69+
"repl",
70+
".",
71+
"--ammonite",
72+
ammArgs,
73+
ammoniteExtraOptions,
74+
cliOptions,
75+
potentiallyExtraCliOpts
76+
).call(
77+
cwd = root,
78+
env = env,
79+
check = check,
80+
stderr = if shouldPipeStdErr then os.Pipe else os.Inherit
81+
)
82+
)
83+
}
84+
}
4485

45-
def ammoniteTest(useMaxAmmoniteScalaVersion: Boolean): Unit = {
86+
def ammoniteTest(): Unit = {
4687
TestInputs.empty.fromRoot { root =>
47-
val testExtraOptions = if (useMaxAmmoniteScalaVersion) ammoniteExtraOptions else extraOptions
48-
val ammArgs = Seq(
49-
"-c",
50-
s"""println("Hello" + " from Scala " + $retrieveScalaVersionCode)"""
51-
)
52-
.map {
53-
if (Properties.isWin)
54-
a => if (a.contains(" ")) "\"" + a.replace("\"", "\\\"") + "\"" else a
55-
else
56-
identity
88+
runInAmmoniteRepl(
89+
codeToRunInRepl = s"""println("Hello" + " from Scala " + $retrieveScalaVersionCode)""",
90+
shouldPipeStdErr = true
91+
) { res =>
92+
val output = res.out.trim()
93+
val expectedSv =
94+
if shouldUseMaxAmmoniteScalaVersion then actualMaxAmmoniteScalaVersion
95+
else expectedScalaVersionForAmmonite
96+
expect(output == s"Hello from Scala $expectedSv")
97+
if shouldUseMaxAmmoniteScalaVersion then {
98+
// the maximum Scala version supported by ammonite is being used, so we shouldn't downgrade
99+
val errOutput = res.err.trim()
100+
expect(!errOutput.contains("not yet supported with this version of Ammonite"))
57101
}
58-
.flatMap(arg => Seq("--ammonite-arg", arg))
59-
val res =
60-
os.proc(TestUtil.cli, "--power", "repl", testExtraOptions, "--ammonite", ammArgs)
61-
.call(cwd = root, stderr = os.Pipe)
62-
val output = res.out.trim()
63-
val expectedSv =
64-
if (useMaxAmmoniteScalaVersion) actualMaxAmmoniteScalaVersion
65-
else expectedScalaVersionForAmmonite
66-
expect(output == s"Hello from Scala $expectedSv")
67-
if (useMaxAmmoniteScalaVersion) {
68-
// the maximum Scala version supported by ammonite is being used, so we shouldn't downgrade
69-
val errOutput = res.err.trim()
70-
expect(!errOutput.contains("not yet supported with this version of Ammonite"))
71102
}
72103
}
73104
}
74105

75-
def ammoniteTestScope(useMaxAmmoniteScalaVersion: Boolean): Unit = {
106+
def ammoniteTestScope(): Unit = {
76107
val message = "something something ammonite"
77-
TestInputs(
78-
os.rel / "example" / "TestScopeExample.test.scala" ->
79-
s"""package example
80-
|
81-
|object TestScopeExample {
82-
| def message: String = "$message"
83-
|}
84-
|""".stripMargin
85-
).fromRoot { root =>
86-
val testExtraOptions = if (useMaxAmmoniteScalaVersion) ammoniteExtraOptions else extraOptions
87-
val ammArgs = Seq("-c", "println(example.TestScopeExample.message)")
88-
.map {
89-
if (Properties.isWin)
90-
a => if (a.contains(" ")) "\"" + a.replace("\"", "\\\"") + "\"" else a
91-
else
92-
identity
93-
}
94-
.flatMap(arg => Seq("--ammonite-arg", arg))
95-
val res =
96-
os.proc(
97-
TestUtil.cli,
98-
"--power",
99-
"repl",
100-
".",
101-
testExtraOptions,
102-
"--test",
103-
"--ammonite",
104-
ammArgs
105-
)
106-
.call(cwd = root, stderr = os.Pipe)
108+
runInAmmoniteRepl(
109+
codeToRunInRepl = "println(example.TestScopeExample.message)",
110+
testInputs =
111+
TestInputs(
112+
os.rel / "example" / "TestScopeExample.test.scala" ->
113+
s"""package example
114+
|
115+
|object TestScopeExample {
116+
| def message: String = "$message"
117+
|}
118+
|""".stripMargin
119+
),
120+
cliOptions = Seq("--test"),
121+
shouldPipeStdErr = true
122+
) { res =>
107123
val output = res.out.trim()
108124
expect(output == message)
109-
if (useMaxAmmoniteScalaVersion) {
125+
if shouldUseMaxAmmoniteScalaVersion then {
110126
// the maximum Scala version supported by ammonite is being used, so we shouldn't downgrade
111127
val errOutput = res.err.trim()
112128
expect(!errOutput.contains("not yet supported with this version of Ammonite"))
113129
}
114130
}
115131
}
116132

117-
def ammoniteScalapyTest(useMaxAmmoniteScalaVersion: Boolean): Unit = {
118-
val testExtraOptions = if (useMaxAmmoniteScalaVersion) ammoniteExtraOptions else extraOptions
119-
val inputs = TestInputs(
120-
os.rel / "foo" / "something.py" ->
121-
"""messageStart = 'Hello from'
122-
|messageEnd = 'ScalaPy'
123-
|""".stripMargin
124-
)
125-
inputs.fromRoot { root =>
126-
val ammArgs = Seq(
127-
"-c",
128-
s"""println("Hello" + " from Scala " + $retrieveScalaVersionCode)
129-
|val sth = py.module("foo.something")
130-
|py.Dynamic.global.applyDynamicNamed("print")("" -> sth.messageStart, "" -> sth.messageEnd, "flush" -> py.Any.from(true))
131-
|""".stripMargin
132-
)
133-
.map {
134-
if (Properties.isWin)
135-
a => if (a.contains(" ")) "\"" + a.replace("\"", "\\\"") + "\"" else a
136-
else
137-
identity
138-
}
139-
.flatMap(arg => Seq("--ammonite-arg", arg))
140-
141-
val errorRes = os.proc(
142-
TestUtil.cli,
143-
"--power",
144-
"repl",
145-
testExtraOptions,
146-
"--ammonite",
147-
"--python",
148-
ammArgs
149-
).call(
150-
cwd = root,
151-
env = Map("PYTHONSAFEPATH" -> "foo"),
152-
mergeErrIntoOut = true,
153-
check = false
133+
def ammoniteScalapyTest(): Unit = {
134+
val codeToRunInRepl =
135+
s"""println("Hello" + " from Scala " + $retrieveScalaVersionCode)
136+
|val sth = py.module("foo.something")
137+
|py.Dynamic.global.applyDynamicNamed("print")("" -> sth.messageStart, "" -> sth.messageEnd, "flush" -> py.Any.from(true))
138+
|""".stripMargin
139+
val inputs =
140+
TestInputs(
141+
os.rel / "foo" / "something.py" ->
142+
"""messageStart = 'Hello from'
143+
|messageEnd = 'ScalaPy'
144+
|""".stripMargin
154145
)
146+
runInAmmoniteRepl(
147+
codeToRunInRepl = codeToRunInRepl,
148+
testInputs = inputs,
149+
cliOptions = Seq("--python"),
150+
shouldPipeStdErr = true,
151+
check = false,
152+
env = Map("PYTHONSAFEPATH" -> "foo")
153+
) { errorRes =>
155154
expect(errorRes.exitCode != 0)
156-
val errorOutput = errorRes.out.text()
155+
val errorOutput = errorRes.err.trim() + errorRes.out.trim()
157156
expect(errorOutput.contains("No module named 'foo'"))
158-
159-
val res = os.proc(
160-
TestUtil.cli,
161-
"--power",
162-
"repl",
163-
testExtraOptions,
164-
"--ammonite",
165-
"--python",
166-
ammArgs
167-
).call(cwd = root, stderr = os.Pipe)
157+
}
158+
runInAmmoniteRepl(
159+
codeToRunInRepl = codeToRunInRepl,
160+
testInputs = inputs,
161+
cliOptions = Seq("--python"),
162+
shouldPipeStdErr = true
163+
) { res =>
168164
val expectedSv =
169-
if (useMaxAmmoniteScalaVersion) actualMaxAmmoniteScalaVersion
165+
if shouldUseMaxAmmoniteScalaVersion then actualMaxAmmoniteScalaVersion
170166
else expectedScalaVersionForAmmonite
171167
val lines = res.out.trim().linesIterator.toVector
172168
expect(lines == Seq(s"Hello from Scala $expectedSv", "Hello from ScalaPy"))
173-
if (useMaxAmmoniteScalaVersion)
169+
if shouldUseMaxAmmoniteScalaVersion then
174170
// the maximum Scala version supported by ammonite is being used, so we shouldn't downgrade
175171
expect(!res.err.trim().contains("not yet supported with this version of Ammonite"))
176172
}
177173
}
178174

179175
def ammoniteMaxVersionString: String =
180-
if (actualScalaVersion == actualMaxAmmoniteScalaVersion) ""
176+
if actualScalaVersion <= actualMaxAmmoniteScalaVersion then s" with Scala $actualScalaVersion"
181177
else s" with Scala $actualMaxAmmoniteScalaVersion (the latest supported version)"
182178

183-
test(s"ammonite$ammoniteMaxVersionString") {
184-
ammoniteTest(useMaxAmmoniteScalaVersion = true)
185-
}
186-
187-
test(s"ammonite scalapy$ammoniteMaxVersionString") {
188-
ammoniteScalapyTest(useMaxAmmoniteScalaVersion = true)
189-
}
190-
191-
test("ammonite with test scope sources") {
192-
ammoniteTestScope(useMaxAmmoniteScalaVersion = true)
193-
}
179+
test(s"$ammonitePrefix simple $ammoniteMaxVersionString")(ammoniteTest())
180+
test(s"$ammonitePrefix scalapy$ammoniteMaxVersionString")(ammoniteScalapyTest())
181+
test(s"$ammonitePrefix with test scope sources$ammoniteMaxVersionString")(ammoniteTestScope())
194182

195-
test("default ammonite version in help") {
196-
TestInputs.empty.fromRoot { root =>
197-
val res = os.proc(TestUtil.cli, "--power", "repl", extraOptions, "--help").call(cwd = root)
198-
val lines = removeAnsiColors(res.out.trim()).linesIterator.toVector
183+
test(s"$ammonitePrefix ammonite version in help$ammoniteMaxVersionString") {
184+
runInAmmoniteRepl(cliOptions = Seq("--help")) { res =>
185+
val lines = removeAnsiColors(res.out.trim()).linesIterator.toVector
199186
val ammVersionHelp = lines.find(_.contains("--ammonite-ver")).getOrElse("")
200187
expect(ammVersionHelp.contains(s"(${Constants.ammoniteVersion} by default)"))
201188
}
202189
}
203190

204191
def ammoniteWithExtraJarTest(): Unit = {
205-
TestInputs.empty.fromRoot { root =>
206-
val ammArgs = Seq(
207-
"-c",
208-
"""import shapeless._; println("Here's an HList: " + (2 :: true :: "a" :: HNil))"""
209-
)
210-
.map {
211-
if (Properties.isWin)
212-
a => if (a.contains(" ")) "\"" + a.replace("\"", "\\\"") + "\"" else a
213-
else
214-
identity
215-
}
216-
.flatMap(arg => Seq("--ammonite-arg", arg))
217-
val shapelessJar =
218-
os.proc(TestUtil.cs, "fetch", "--intransitive", "com.chuusai:shapeless_2.13:2.3.7")
219-
.call()
220-
.out
221-
.text()
222-
.trim
223-
val cmd = Seq[os.Shellable](
224-
TestUtil.cli,
225-
"--power",
226-
"repl",
227-
ammoniteExtraOptions,
228-
"--jar",
229-
shapelessJar,
230-
"--ammonite",
231-
ammArgs
232-
)
233-
val res = os.proc(cmd).call(cwd = root)
234-
val output = res.out.trim()
235-
expect(output == "Here's an HList: 2 :: true :: a :: HNil")
236-
}
192+
runInAmmoniteRepl(codeToRunInRepl =
193+
"""import shapeless._; println("Here's an HList: " + (2 :: true :: "a" :: HNil))"""
194+
)(
195+
runBeforeReplAndGetExtraCliOpts = () =>
196+
val shapelessJar =
197+
os.proc(TestUtil.cs, "fetch", "--intransitive", "com.chuusai:shapeless_2.13:2.3.7")
198+
.call()
199+
.out
200+
.text()
201+
.trim
202+
Seq("--jar", shapelessJar)
203+
,
204+
runAfterRepl = res => expect(res.out.trim() == "Here's an HList: 2 :: true :: a :: HNil")
205+
)
237206
}
238207

239-
if (actualScalaVersion.startsWith("2.13"))
240-
test(s"ammonite with extra JAR$ammoniteMaxVersionString") {
208+
if actualScalaVersion.startsWith("2.13") then
209+
test(s"$ammonitePrefix with extra JAR$ammoniteMaxVersionString") {
241210
ammoniteWithExtraJarTest()
242211
}
243212
}

0 commit comments

Comments
 (0)