@@ -3,6 +3,7 @@ package scala.cli.integration
33import com .eed3si9n .expecty .Expecty .expect
44
55import scala .cli .integration .TestUtil .removeAnsiColors
6+ import scala .util .Properties
67
78abstract class ReplTestDefinitions extends ScalaCliSuite with TestScalaVersionArgs {
89 this : TestScalaVersion =>
@@ -15,23 +16,39 @@ abstract class ReplTestDefinitions extends ScalaCliSuite with TestScalaVersionAr
1516 actualScalaVersion.coursierVersion >= " 3.7.0-RC1" .coursierVersion
1617
1718 protected val dryRunPrefix : String = " Dry run:"
18- protected val runInReplPrefix : String = " Running in REPL:"
19+ protected val runInReplPrefix : String = " Running in Scala REPL:"
1920
2021 def runInRepl (
2122 codeToRunInRepl : String ,
22- testInputs : TestInputs = TestInputs .empty
23- )(f : os.CommandResult => Unit ): Unit = {
23+ testInputs : TestInputs = TestInputs .empty,
24+ cliOptions : Seq [String ] = Seq .empty,
25+ shouldPipeStdErr : Boolean = false ,
26+ check : Boolean = true ,
27+ env : Map [String , String ] = Map .empty
28+ )(
29+ runAfterRepl : os.CommandResult => Unit ,
30+ runBeforeReplAndGetExtraCliOpts : () => Seq [os.Shellable ] = () => Seq .empty
31+ ): Unit = {
2432 testInputs.fromRoot { root =>
25- f(
33+ val potentiallyExtraCliOpts = runBeforeReplAndGetExtraCliOpts()
34+ runAfterRepl(
2635 os.proc(
2736 TestUtil .cli,
2837 " repl" ,
38+ " ." ,
2939 " --repl-quit-after-init" ,
3040 " --repl-init-script" ,
3141 codeToRunInRepl,
32- extraOptions
42+ extraOptions,
43+ cliOptions,
44+ potentiallyExtraCliOpts
3345 )
34- .call(cwd = root)
46+ .call(
47+ cwd = root,
48+ stderr = if shouldPipeStdErr then os.Pipe else os.Inherit ,
49+ env = env,
50+ check = check
51+ )
3552 )
3653 }
3754 }
@@ -114,11 +131,160 @@ abstract class ReplTestDefinitions extends ScalaCliSuite with TestScalaVersionAr
114131 expect(output.contains(" typer" ))
115132 }
116133
117- if canRunInRepl then
134+ if canRunInRepl then {
118135 test(s " $runInReplPrefix simple " ) {
119136 val expectedMessage = " 1337"
120137 runInRepl(s """ println( $expectedMessage) """ )(r =>
121138 expect(r.out.trim() == expectedMessage)
122139 )
123140 }
141+
142+ test(s " $runInReplPrefix verify Scala version from the REPL " ) {
143+ val opts = if actualScalaVersion.startsWith(" 3" ) && ! isScala38OrNewer then
144+ Seq (" --with-compiler" )
145+ else Seq .empty
146+ runInRepl(
147+ codeToRunInRepl = s """ println( $retrieveScalaVersionCode) """ ,
148+ cliOptions = opts
149+ )(r => expect(r.out.trim() == actualScalaVersion))
150+ }
151+
152+ test(s " $runInReplPrefix test scope " ) {
153+ val message = " something something something REPL"
154+ runInRepl(
155+ codeToRunInRepl = " println(example.TestScopeExample.message)" ,
156+ testInputs = TestInputs (
157+ os.rel / " example" / " TestScopeExample.test.scala" ->
158+ s """ package example
159+ |
160+ |object TestScopeExample {
161+ | def message: String = " $message"
162+ |}
163+ | """ .stripMargin
164+ ),
165+ cliOptions = Seq (" --test" )
166+ )(r => expect(r.out.trim() == message))
167+ }
168+
169+ test(s " $runInReplPrefix https://github.com/scala/scala3/issues/21229 " ) {
170+ runInRepl(
171+ codeToRunInRepl = " println(stuff.baz)" ,
172+ testInputs = TestInputs (
173+ os.rel / " Pprint.scala" ->
174+ """ //> using dep com.lihaoyi::pprint::0.9.0
175+ |package stuff
176+ |import scala.quoted.*
177+ |def foo = pprint(1)
178+ |inline def bar = pprint(1)
179+ |inline def baz = ${ bazImpl }
180+ |def bazImpl(using Quotes) = '{ pprint(1) }
181+ |""" .stripMargin
182+ )
183+ )(res => expect(res.out.trim().nonEmpty))
184+ }
185+
186+ if ! Properties .isWin then {
187+ test(s " $runInReplPrefix ScalaPy " ) {
188+ val opts =
189+ if actualScalaVersion.startsWith(" 3" ) && ! isScala38OrNewer then Seq (" --with-compiler" )
190+ else Seq .empty
191+ runInRepl(
192+ codeToRunInRepl =
193+ s """ import me.shadaj.scalapy.py
194+ |println("Hello" + " from Scala " + $retrieveScalaVersionCode)
195+ |val sth = py.module("foo.something")
196+ |py.Dynamic.global.applyDynamicNamed("print")("" -> sth.messageStart, "" -> sth.messageEnd, "flush" -> py.Any.from(true))
197+ | """ .stripMargin,
198+ testInputs = TestInputs (
199+ os.rel / " foo" / " something.py" ->
200+ """ messageStart = 'Hello from'
201+ |messageEnd = 'ScalaPy'
202+ |""" .stripMargin
203+ ),
204+ cliOptions = Seq (" --python" , " --power" ) ++ opts,
205+ shouldPipeStdErr = true
206+ ) { res =>
207+ val output = res.out.trim().linesIterator.toVector.take(2 ).mkString(" \n " )
208+ expect(output ==
209+ s """ Hello from Scala $actualScalaVersion
210+ |Hello from ScalaPy """ .stripMargin)
211+ }
212+ }
213+
214+ test(s " $runInReplPrefix ScalaPy with PYTHONSAFEPATH " ) {
215+ val opts =
216+ if actualScalaVersion.startsWith(" 3" ) && ! isScala38OrNewer then Seq (" --with-compiler" )
217+ else Seq .empty
218+ runInRepl(
219+ codeToRunInRepl =
220+ s """ import me.shadaj.scalapy.py
221+ |println("Hello" + " from Scala " + $retrieveScalaVersionCode)
222+ |val sth = py.module("foo.something")
223+ |py.Dynamic.global.applyDynamicNamed("print")("" -> sth.messageStart, "" -> sth.messageEnd, "flush" -> py.Any.from(true))
224+ | """ .stripMargin,
225+ testInputs = TestInputs (
226+ os.rel / " foo" / " something.py" ->
227+ """ messageStart = 'Hello from'
228+ |messageEnd = 'ScalaPy'
229+ |""" .stripMargin
230+ ),
231+ cliOptions = Seq (" --python" , " --power" ) ++ opts,
232+ shouldPipeStdErr = true ,
233+ // check = false, // technically should be an error, but the REPL itself doesn't return it as such.
234+ env = Map (" PYTHONSAFEPATH" -> " foo" )
235+ ) { errorRes =>
236+ // expect(errorRes.exitCode != 0) // technically should be an error, but the REPL itself doesn't return it as such.
237+ val errorOutput = TestUtil .removeAnsiColors(errorRes.err.trim() + errorRes.out.trim())
238+ expect(errorOutput.contains(" No module named 'foo'" ))
239+ }
240+ }
241+
242+ test(s " $runInReplPrefix with extra JAR " ) {
243+ runInRepl(codeToRunInRepl =
244+ """ import shapeless._; println("Here's an HList: " + (2 :: true :: "a" :: HNil))"""
245+ )(
246+ runBeforeReplAndGetExtraCliOpts = () =>
247+ val shapelessJar =
248+ os.proc(TestUtil .cs, " fetch" , " --intransitive" , " com.chuusai:shapeless_2.13:2.3.7" )
249+ .call()
250+ .out
251+ .text()
252+ .trim
253+ Seq (" --jar" , shapelessJar)
254+ ,
255+ runAfterRepl = res => expect(res.out.trim() == " Here's an HList: 2 :: true :: a :: HNil" )
256+ )
257+ }
258+
259+ if ! isScala38OrNewer then
260+ // TODO rewrite this test to work with Scala 3.8+ once 3.8.0 stable is out
261+ test(s " $runInReplPrefix as jar " ) {
262+ val inputs = TestInputs (
263+ os.rel / " CheckCp.scala" ->
264+ """ //> using dep com.lihaoyi::os-lib:0.9.1
265+ |package checkcp
266+ |class CheckCp
267+ |object CheckCp {
268+ | def hasDir: Boolean = {
269+ | val uri: java.net.URI = classOf[checkcp.CheckCp].getProtectionDomain.getCodeSource.getLocation.toURI
270+ | os.isDir(os.Path(java.nio.file.Paths.get(uri)))
271+ | }
272+ |}
273+ |""" .stripMargin
274+ )
275+ val code = """ println("hasDir=" + checkcp.CheckCp.hasDir)"""
276+ runInRepl(codeToRunInRepl = code, testInputs = inputs) {
277+ res => expect(res.out.trim().contains(" hasDir=true" ))
278+ }
279+ runInRepl(
280+ codeToRunInRepl = code,
281+ testInputs = inputs,
282+ cliOptions = Seq (" --as-jar" , " --power" )
283+ ) {
284+ res => expect(res.out.trim().contains(" hasDir=false" ))
285+ }
286+
287+ }
288+ }
289+ }
124290}
0 commit comments