Skip to content

Commit 9c04e82

Browse files
author
Andriy Onyshchuk
committed
Migrate ScalaObjectMapperSpec and PPairToScalaTupleSpec to FixtureAnyFunSuite
Both specs now build their evaluator (and dependent fixtures) inside withFixture per test, with deterministic close in finally. ScalaObjectMapperSpec's fixture is the ConfigEvaluator; PPairToScalaTupleSpec's bundles the evaluated PModule and the configured ValueMapper since every test consumes both. The ConfigEvaluatorBuilder-extension test stays separate — its purpose is to exercise the builder path, not the evaluator one — and now uses scala.util.Using for the same try-with-resources discipline as withFixture.
1 parent 1d5634f commit 9c04e82

2 files changed

Lines changed: 96 additions & 121 deletions

File tree

pkl-config-scala/src/test/scala/org/pkl/config/scala/ScalaObjectMapperSpec.scala

Lines changed: 75 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,31 @@ package org.pkl.config.scala
1717

1818
import com.softwaremill.diffx.*
1919
import com.softwaremill.diffx.scalatest.DiffShouldMatcher.*
20-
import org.pkl.config.java.ConfigEvaluator
20+
import org.pkl.config.java.{ConfigEvaluator, ConfigEvaluatorBuilder}
2121
import org.pkl.config.java.mapper.ConversionException
2222
import org.pkl.config.scala.syntax.*
2323
import org.pkl.core.{Duration => PDuration, ModuleSource}
24-
import org.scalatest.funsuite.AnyFunSuite
24+
import org.scalatest.Outcome
25+
import org.scalatest.funsuite.FixtureAnyFunSuite
2526

2627
import java.time.Instant
2728
import java.util.concurrent.TimeUnit
2829
import scala.concurrent.duration.{Duration, FiniteDuration}
30+
import scala.util.Using
2931
import scala.util.matching.Regex
3032

31-
class ScalaObjectMapperSpec extends AnyFunSuite {
33+
class ScalaObjectMapperSpec extends FixtureAnyFunSuite {
3234
import ScalaObjectMapperSpec.*
3335

34-
test("evaluate scala types") {
36+
type FixtureParam = ConfigEvaluator
37+
38+
override def withFixture(test: OneArgTest): Outcome = {
39+
val evaluator = ConfigEvaluator.preconfigured().forScala()
40+
try withFixture(test.toNoArgTest(evaluator))
41+
finally evaluator.close()
42+
}
43+
44+
test("evaluate scala types") { evaluator =>
3545

3646
val code = {
3747
"""
@@ -75,11 +85,7 @@ class ScalaObjectMapperSpec extends AnyFunSuite {
7585
|""".stripMargin
7686
}
7787

78-
val result = ConfigEvaluator
79-
.preconfigured()
80-
.forScala()
81-
.evaluate(ModuleSource.text(code))
82-
.to[ObjectMappingTestContainer]
88+
val result = evaluator.evaluate(ModuleSource.text(code)).to[ObjectMappingTestContainer]
8389

8490
result shouldMatchTo ObjectMappingTestContainer(
8591
optionalVal1 = None,
@@ -102,65 +108,55 @@ class ScalaObjectMapperSpec extends AnyFunSuite {
102108
)
103109
}
104110

105-
test("idiomatic Scala 3 enum routes through PStringToScalaEnum") {
111+
test("idiomatic Scala 3 enum routes through PStringToScalaEnum") { evaluator =>
106112
val code = {
107113
"""
108114
|module M
109115
|color = "Bbb"
110116
|""".stripMargin
111117
}
112118

113-
val result = ConfigEvaluator
114-
.preconfigured()
115-
.forScala()
116-
.evaluate(ModuleSource.text(code))
117-
.to[EnumContainer]
119+
val result = evaluator.evaluate(ModuleSource.text(code)).to[EnumContainer]
118120
assert(result.color == SimpleEnum.Bbb)
119121
}
120122

121123
test("unknown enum value raises ConversionException listing valid members in declaration order") {
122-
val code = {
123-
"""
124-
|module M
125-
|color = "Purple"
126-
|""".stripMargin
127-
}
128-
129-
val ex = intercept[ConversionException] {
130-
ConfigEvaluator
131-
.preconfigured()
132-
.forScala()
133-
.evaluate(ModuleSource.text(code))
134-
.to[EnumContainer]
135-
}
136-
val msg = ex.getMessage
137-
assert(msg.contains("Purple"), s"expected input name in message, got: $msg")
138-
val aaaIdx = msg.indexOf("Aaa")
139-
val bbbIdx = msg.indexOf("Bbb")
140-
val cccIdx = msg.indexOf("Ccc")
141-
assert(
142-
aaaIdx >= 0 && bbbIdx > aaaIdx && cccIdx > bbbIdx,
143-
s"expected Aaa, Bbb, Ccc in declaration order, got: $msg"
144-
)
124+
evaluator =>
125+
val code = {
126+
"""
127+
|module M
128+
|color = "Purple"
129+
|""".stripMargin
130+
}
131+
132+
val ex = intercept[ConversionException] {
133+
evaluator.evaluate(ModuleSource.text(code)).to[EnumContainer]
134+
}
135+
val msg = ex.getMessage
136+
assert(msg.contains("Purple"), s"expected input name in message, got: $msg")
137+
val aaaIdx = msg.indexOf("Aaa")
138+
val bbbIdx = msg.indexOf("Bbb")
139+
val cccIdx = msg.indexOf("Ccc")
140+
assert(
141+
aaaIdx >= 0 && bbbIdx > aaaIdx && cccIdx > bbbIdx,
142+
s"expected Aaa, Bbb, Ccc in declaration order, got: $msg"
143+
)
145144
}
146145

147146
test("Java-compat Scala 3 enum (extends java.lang.Enum) routes through PStringToEnum") {
148-
val code = {
149-
"""
150-
|module M
151-
|color = "Yyy"
152-
|""".stripMargin
153-
}
154-
155-
val result = ConfigEvaluator
156-
.preconfigured()
157-
.forScala()
158-
.evaluate(ModuleSource.text(code))
159-
.to[JavaCompatEnumContainer]
160-
assert(result.color == JavaCompatEnum.Yyy)
147+
evaluator =>
148+
val code = {
149+
"""
150+
|module M
151+
|color = "Yyy"
152+
|""".stripMargin
153+
}
154+
155+
val result = evaluator.evaluate(ModuleSource.text(code)).to[JavaCompatEnumContainer]
156+
assert(result.color == JavaCompatEnum.Yyy)
161157
}
162158

163-
test("missing required property on case class raises ConversionException") {
159+
test("missing required property on case class raises ConversionException") { evaluator =>
164160
val code = {
165161
"""
166162
|module M
@@ -169,75 +165,58 @@ class ScalaObjectMapperSpec extends AnyFunSuite {
169165
}
170166

171167
val ex = intercept[ConversionException] {
172-
ConfigEvaluator
173-
.preconfigured()
174-
.forScala()
175-
.evaluate(ModuleSource.text(code))
176-
.to[Person]
168+
evaluator.evaluate(ModuleSource.text(code)).to[Person]
177169
}
178170
val msg = ex.getMessage
179171
assert(msg.contains("age"), s"expected missing property name in message, got: $msg")
180172
}
181173

182174
test("type mismatch between Pkl value and case class field raises ConversionException") {
183-
val code = {
184-
"""
185-
|module M
186-
|value = "not an int"
187-
|""".stripMargin
188-
}
189-
190-
val ex = intercept[ConversionException] {
191-
ConfigEvaluator
192-
.preconfigured()
193-
.forScala()
194-
.evaluate(ModuleSource.text(code))
195-
.to[IntContainer]
196-
}
197-
val msg = ex.getMessage
198-
assert(
199-
msg.toLowerCase.contains("cannot convert") ||
200-
msg.toLowerCase.contains("string") ||
201-
msg.toLowerCase.contains("int"),
202-
s"expected type-mismatch hint in message, got: $msg"
203-
)
175+
evaluator =>
176+
val code = {
177+
"""
178+
|module M
179+
|value = "not an int"
180+
|""".stripMargin
181+
}
182+
183+
val ex = intercept[ConversionException] {
184+
evaluator.evaluate(ModuleSource.text(code)).to[IntContainer]
185+
}
186+
val msg = ex.getMessage
187+
assert(
188+
msg.toLowerCase.contains("cannot convert") ||
189+
msg.toLowerCase.contains("string") ||
190+
msg.toLowerCase.contains("int"),
191+
s"expected type-mismatch hint in message, got: $msg"
192+
)
204193
}
205194

206-
test("pStringToScalaRegex converts Pkl String to Scala Regex") {
195+
test("pStringToScalaRegex converts Pkl String to Scala Regex") { evaluator =>
207196
val code = {
208197
"""
209198
|module M
210199
|pattern = "^[0-9]+$"
211200
|""".stripMargin
212201
}
213202

214-
val result = ConfigEvaluator
215-
.preconfigured()
216-
.forScala()
217-
.evaluate(ModuleSource.text(code))
218-
.to[RegexContainer]
203+
val result = evaluator.evaluate(ModuleSource.text(code)).to[RegexContainer]
219204
assert(result.pattern.pattern.pattern() == "^[0-9]+$")
220205
}
221206

222-
test("pRegexToScalaRegex converts Pkl Regex to Scala Regex") {
207+
test("pRegexToScalaRegex converts Pkl Regex to Scala Regex") { evaluator =>
223208
val code = {
224209
"""
225210
|module M
226211
|pattern: Regex = Regex("^[a-z]+$")
227212
|""".stripMargin
228213
}
229214

230-
val result = ConfigEvaluator
231-
.preconfigured()
232-
.forScala()
233-
.evaluate(ModuleSource.text(code))
234-
.to[RegexContainer]
215+
val result = evaluator.evaluate(ModuleSource.text(code)).to[RegexContainer]
235216
assert(result.pattern.pattern.pattern() == "^[a-z]+$")
236217
}
237218

238-
test("forScala extension on ConfigEvaluatorBuilder wires Scala converters") {
239-
import org.pkl.config.java.ConfigEvaluatorBuilder
240-
219+
test("forScala extension on ConfigEvaluatorBuilder wires Scala converters") { _ =>
241220
val code = {
242221
"""
243222
|module M
@@ -246,18 +225,15 @@ class ScalaObjectMapperSpec extends AnyFunSuite {
246225
|""".stripMargin
247226
}
248227

249-
val evaluator = ConfigEvaluatorBuilder.preconfigured().forScala().build()
250-
try {
228+
Using.resource(ConfigEvaluatorBuilder.preconfigured().forScala().build()) { evaluator =>
251229
val result = evaluator.evaluate(ModuleSource.text(code)).to[Person]
252230
assert(result == Person("via-builder", 7))
253-
} finally {
254-
evaluator.close()
255231
}
256232
}
257233

258234
test(
259235
"inherited Java conversions: BigInteger, BigDecimal, URI, URL, Path, File, Char, Bytes, DataSize, Listing, Mapping"
260-
) {
236+
) { evaluator =>
261237
val code = {
262238
"""
263239
|module M
@@ -275,11 +251,7 @@ class ScalaObjectMapperSpec extends AnyFunSuite {
275251
|""".stripMargin
276252
}
277253

278-
val result = ConfigEvaluator
279-
.preconfigured()
280-
.forScala()
281-
.evaluate(ModuleSource.text(code))
282-
.to[InheritedTypesContainer]
254+
val result = evaluator.evaluate(ModuleSource.text(code)).to[InheritedTypesContainer]
283255

284256
assert(result.bigInt == new java.math.BigInteger("9007199254740993"))
285257
assert(result.bigDec == java.math.BigDecimal.valueOf(1.5))

pkl-config-scala/src/test/scala/org/pkl/config/scala/mapper/PPairToScalaTupleSpec.scala

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,37 @@
1515
*/
1616
package org.pkl.config.scala.mapper
1717

18-
import org.pkl.config.java.mapper.{Types, ValueMapperBuilder}
19-
import org.pkl.core.{Duration, Evaluator, PClassInfo, PObject}
18+
import org.pkl.config.java.mapper.{Types, ValueMapper, ValueMapperBuilder}
19+
import org.pkl.core.{Duration, Evaluator, PModule, PObject}
2020
import org.pkl.core.ModuleSource.modulePath
21-
import org.scalatest.BeforeAndAfterAll
22-
import org.scalatest.funsuite.AnyFunSuite
21+
import org.scalatest.Outcome
22+
import org.scalatest.funsuite.FixtureAnyFunSuite
2323
import org.scalatest.matchers.should.Matchers.*
2424
import org.pkl.config.scala.syntax.*
2525

2626
import scala.jdk.CollectionConverters.*
2727

28-
class PPairToScalaTupleSpec extends AnyFunSuite with BeforeAndAfterAll {
28+
class PPairToScalaTupleSpec extends FixtureAnyFunSuite {
2929
import PPairToScalaTupleSpec.*
3030

31-
private val evaluator = Evaluator.preconfigured()
31+
case class TestFixture(module: PModule, mapper: ValueMapper)
3232

33-
private val module = {
34-
evaluator.evaluate(
35-
modulePath("org/pkl/config/scala/mapper/PPairToScalaTuple.pkl")
36-
)
37-
}
38-
39-
private val mapper = ValueMapperBuilder.preconfigured().forScala().build()
33+
type FixtureParam = TestFixture
4034

41-
override def afterAll(): Unit = {
42-
evaluator.close()
35+
override def withFixture(test: OneArgTest): Outcome = {
36+
val evaluator = Evaluator.preconfigured()
37+
try {
38+
val module = evaluator.evaluate(
39+
modulePath("org/pkl/config/scala/mapper/PPairToScalaTuple.pkl")
40+
)
41+
val mapper = ValueMapperBuilder.preconfigured().forScala().build()
42+
withFixture(test.toNoArgTest(TestFixture(module, mapper)))
43+
} finally {
44+
evaluator.close()
45+
}
4346
}
4447

45-
test("Pair or scalar values") {
48+
test("Pair or scalar values") { case TestFixture(module, mapper) =>
4649
val ex1 = module.getProperty("ex1")
4750
val mapped: (Int, Duration) = {
4851
mapper.map(
@@ -58,7 +61,7 @@ class PPairToScalaTupleSpec extends AnyFunSuite with BeforeAndAfterAll {
5861
mapped shouldBe (1, Duration.ofSeconds(3))
5962
}
6063

61-
test("Pair of PObject") {
64+
test("Pair of PObject") { case TestFixture(module, mapper) =>
6265
val ex2 = module.getProperty("ex2")
6366
val mapped: (PObject, PObject) = {
6467
mapper.map(
@@ -82,7 +85,7 @@ class PPairToScalaTupleSpec extends AnyFunSuite with BeforeAndAfterAll {
8285
)
8386
}
8487

85-
test("Pair of case class") {
88+
test("Pair of case class") { case TestFixture(module, mapper) =>
8689
val ex2 = module.getProperty("ex2")
8790
val mapped: (Animal, Animal) = {
8891
mapper.map(

0 commit comments

Comments
 (0)