From 7bcd6b598c6c226f87d19d068cc8fe5abbb70f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Jourdan-Weil?= Date: Sat, 26 Jul 2025 17:09:02 +0200 Subject: [PATCH 1/2] fix: location for anything other than a step was wrong See https://github.com/cucumber/cucumber-jvm-scala/issues/404 --- .../scala/AbstractGlueDefinition.scala | 2 +- .../io/cucumber/scala/DataTableTypeDsl.scala | 39 +++++++++++++++---- .../scala/DefaultTransformerDsl.scala | 16 ++++++-- .../io/cucumber/scala/DocStringTypeDsl.scala | 9 ++++- .../io/cucumber/scala/ParameterTypeDsl.scala | 4 +- .../scala/ScalaDataTableCellDefinition.scala | 6 +-- .../scala/ScalaDataTableDefinition.scala | 6 +-- .../scala/ScalaDataTableEntryDefinition.scala | 6 +-- ...ScalaDataTableOptionalCellDefinition.scala | 6 +-- ...calaDataTableOptionalEntryDefinition.scala | 6 +-- .../ScalaDataTableOptionalRowDefinition.scala | 6 +-- .../scala/ScalaDataTableRowDefinition.scala | 6 +-- .../scala/ScalaDataTableTypeDefinition.scala | 24 ++++++++---- .../scala/ScalaDataTableTypeDetails.scala | 27 +++++++++---- ...ltDataTableCellTransformerDefinition.scala | 2 +- ...tDataTableEntryTransformerDefinition.scala | 2 +- ...efaultParameterTransformerDefinition.scala | 2 +- .../ScalaDefaultTransformerDetails.scala | 9 +++-- .../scala/ScalaDocStringTypeDefinition.scala | 2 +- .../scala/ScalaDocStringTypeDetails.scala | 3 +- .../cucumber/scala/ScalaHookDefinition.scala | 2 +- .../scala/ScalaParameterTypeDefinition.scala | 2 +- .../scala/ScalaParameterTypeDetails.scala | 3 +- .../scala/ScalaStaticHookDefinition.scala | 2 +- 24 files changed, 112 insertions(+), 80 deletions(-) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/AbstractGlueDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/AbstractGlueDefinition.scala index 3ef21026..1121dd0a 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/AbstractGlueDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/AbstractGlueDefinition.scala @@ -15,7 +15,7 @@ trait AbstractGlueDefinition extends Located { val location: StackTraceElement - lazy val sourceReference: SourceReference = + private lazy val sourceReference: SourceReference = SourceReference.fromStackTraceElement(location) override def getLocation(): String = { diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/DataTableTypeDsl.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/DataTableTypeDsl.scala index f43c3605..2ddcae65 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/DataTableTypeDsl.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/DataTableTypeDsl.scala @@ -2,7 +2,7 @@ package io.cucumber.scala import scala.reflect.ClassTag -private[scala] trait DataTableTypeDsl extends BaseScalaDsl { +private[scala] trait DataTableTypeDsl extends BaseScalaDsl { self => /** Register a data table type. */ @@ -27,7 +27,12 @@ private[scala] trait DataTableTypeDsl extends BaseScalaDsl { body: DataTableEntryDefinitionBody[T] )(implicit ev: ClassTag[T]): Unit = { registry.registerDataTableType( - ScalaDataTableEntryTypeDetails[T](replaceWithEmptyString, body, ev) + ScalaDataTableEntryTypeDetails[T]( + replaceWithEmptyString, + body, + ev, + Utils.frame(self) + ) ) } @@ -38,7 +43,8 @@ private[scala] trait DataTableTypeDsl extends BaseScalaDsl { ScalaDataTableOptionalEntryTypeDetails[T]( replaceWithEmptyString, body, - ev + ev, + Utils.frame(self) ) ) } @@ -47,7 +53,12 @@ private[scala] trait DataTableTypeDsl extends BaseScalaDsl { body: DataTableRowDefinitionBody[T] )(implicit ev: ClassTag[T]): Unit = { registry.registerDataTableType( - ScalaDataTableRowTypeDetails[T](replaceWithEmptyString, body, ev) + ScalaDataTableRowTypeDetails[T]( + replaceWithEmptyString, + body, + ev, + Utils.frame(self) + ) ) } @@ -58,7 +69,8 @@ private[scala] trait DataTableTypeDsl extends BaseScalaDsl { ScalaDataTableOptionalRowTypeDetails[T]( replaceWithEmptyString, body, - ev + ev, + Utils.frame(self) ) ) } @@ -67,7 +79,12 @@ private[scala] trait DataTableTypeDsl extends BaseScalaDsl { body: DataTableCellDefinitionBody[T] )(implicit ev: ClassTag[T]): Unit = { registry.registerDataTableType( - ScalaDataTableCellTypeDetails[T](replaceWithEmptyString, body, ev) + ScalaDataTableCellTypeDetails[T]( + replaceWithEmptyString, + body, + ev, + Utils.frame(self) + ) ) } @@ -78,7 +95,8 @@ private[scala] trait DataTableTypeDsl extends BaseScalaDsl { ScalaDataTableOptionalCellTypeDetails[T]( replaceWithEmptyString, body, - ev + ev, + Utils.frame(self) ) ) } @@ -87,7 +105,12 @@ private[scala] trait DataTableTypeDsl extends BaseScalaDsl { body: DataTableDefinitionBody[T] )(implicit ev: ClassTag[T]): Unit = { registry.registerDataTableType( - ScalaDataTableTableTypeDetails[T](replaceWithEmptyString, body, ev) + ScalaDataTableTableTypeDetails[T]( + replaceWithEmptyString, + body, + ev, + Utils.frame(self) + ) ) } diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/DefaultTransformerDsl.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/DefaultTransformerDsl.scala index 963d3325..e157a8f6 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/DefaultTransformerDsl.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/DefaultTransformerDsl.scala @@ -6,7 +6,7 @@ import io.cucumber.scala.Aliases.{ DefaultParameterTransformerBody } -private[scala] trait DefaultTransformerDsl extends BaseScalaDsl { +private[scala] trait DefaultTransformerDsl extends BaseScalaDsl { self => /** Register default parameter type transformer. * @@ -17,7 +17,7 @@ private[scala] trait DefaultTransformerDsl extends BaseScalaDsl { body: DefaultParameterTransformerBody ): Unit = { registry.registerDefaultParameterTransformer( - ScalaDefaultParameterTransformerDetails(body) + ScalaDefaultParameterTransformerDetails(body, Utils.frame(self)) ) } @@ -52,7 +52,11 @@ private[scala] trait DefaultTransformerDsl extends BaseScalaDsl { replaceWithEmptyString: Seq[String] )(body: DefaultDataTableCellTransformerBody): Unit = { registry.registerDefaultDataTableCellTransformer( - ScalaDefaultDataTableCellTransformerDetails(replaceWithEmptyString, body) + ScalaDefaultDataTableCellTransformerDetails( + replaceWithEmptyString, + body, + Utils.frame(self) + ) ) } @@ -89,7 +93,11 @@ private[scala] trait DefaultTransformerDsl extends BaseScalaDsl { replaceWithEmptyString: Seq[String] )(body: DefaultDataTableEntryTransformerBody): Unit = { registry.registerDefaultDataTableEntryTransformer( - ScalaDefaultDataTableEntryTransformerDetails(replaceWithEmptyString, body) + ScalaDefaultDataTableEntryTransformerDetails( + replaceWithEmptyString, + body, + Utils.frame(self) + ) ) } diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/DocStringTypeDsl.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/DocStringTypeDsl.scala index dfc74e9a..3d17067b 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/DocStringTypeDsl.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/DocStringTypeDsl.scala @@ -2,7 +2,7 @@ package io.cucumber.scala import io.cucumber.scala.Aliases.DocStringDefinitionBody -private[scala] trait DocStringTypeDsl extends BaseScalaDsl { +private[scala] trait DocStringTypeDsl extends BaseScalaDsl { self => /** Register doc string type. * @@ -18,7 +18,12 @@ private[scala] trait DocStringTypeDsl extends BaseScalaDsl { contentType: String )(body: DocStringDefinitionBody[T])(implicit ev: Stepable[T]): Unit = { registry.registerDocStringType( - ScalaDocStringTypeDetails[T](contentType, body, ev.asJavaType) + ScalaDocStringTypeDetails[T]( + contentType, + body, + ev.asJavaType, + Utils.frame(self) + ) ) } diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ParameterTypeDsl.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ParameterTypeDsl.scala index cbb1c93f..958f10c0 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ParameterTypeDsl.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ParameterTypeDsl.scala @@ -2,7 +2,7 @@ package io.cucumber.scala import scala.reflect.ClassTag -private[scala] trait ParameterTypeDsl extends BaseScalaDsl { +private[scala] trait ParameterTypeDsl extends BaseScalaDsl { self => /** Register parameter type. * @@ -748,7 +748,7 @@ private[scala] trait ParameterTypeDsl extends BaseScalaDsl { pf: PartialFunction[List[String], R] )(implicit tag: ClassTag[R]): Unit = { registry.registerParameterType( - ScalaParameterTypeDetails[R](name, regex, pf, tag) + ScalaParameterTypeDetails[R](name, regex, pf, tag, Utils.frame(self)) ) } diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableCellDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableCellDefinition.scala index 8030548a..bea1470d 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableCellDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableCellDefinition.scala @@ -7,11 +7,7 @@ import scala.annotation.nowarn trait ScalaDataTableCellDefinition[T] extends ScalaDataTableTypeDefinition { - val details: ScalaDataTableCellTypeDetails[T] - - override val emptyPatterns: Seq[String] = details.emptyPatterns - - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val details: ScalaDataTableCellTypeDetails[T] private val transformer: TableCellTransformer[T] = (cell: String) => { details.body.transform(replaceEmptyPatternsWithEmptyString(cell)) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableDefinition.scala index edf586a8..afa2eb50 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableDefinition.scala @@ -7,11 +7,7 @@ import scala.annotation.nowarn trait ScalaDataTableDefinition[T] extends ScalaDataTableTypeDefinition { - val details: ScalaDataTableTableTypeDetails[T] - - override val emptyPatterns: Seq[String] = details.emptyPatterns - - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val details: ScalaDataTableTableTypeDetails[T] private val transformer: TableTransformer[T] = (table: DataTable) => { details.body.transform(replaceEmptyPatternsWithEmptyString(table)) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableEntryDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableEntryDefinition.scala index 68bad38a..47b569ec 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableEntryDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableEntryDefinition.scala @@ -9,11 +9,7 @@ import scala.jdk.CollectionConverters._ trait ScalaDataTableEntryDefinition[T] extends ScalaDataTableTypeDefinition { - val details: ScalaDataTableEntryTypeDetails[T] - - override val emptyPatterns: Seq[String] = details.emptyPatterns - - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val details: ScalaDataTableEntryTypeDetails[T] private val transformer: TableEntryTransformer[T] = (entry: JavaMap[String, String]) => { diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalCellDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalCellDefinition.scala index b1746bbe..391e6863 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalCellDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalCellDefinition.scala @@ -8,11 +8,7 @@ import scala.annotation.nowarn trait ScalaDataTableOptionalCellDefinition[T] extends ScalaDataTableTypeDefinition { - val details: ScalaDataTableOptionalCellTypeDetails[T] - - override val emptyPatterns: Seq[String] = details.emptyPatterns - - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val details: ScalaDataTableOptionalCellTypeDetails[T] private val transformer: TableCellTransformer[T] = (cell: String) => { details.body.transform(Option(replaceEmptyPatternsWithEmptyString(cell))) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalEntryDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalEntryDefinition.scala index aad9481c..350619a7 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalEntryDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalEntryDefinition.scala @@ -10,11 +10,7 @@ import scala.jdk.CollectionConverters._ trait ScalaDataTableOptionalEntryDefinition[T] extends ScalaDataTableTypeDefinition { - val details: ScalaDataTableOptionalEntryTypeDetails[T] - - override val emptyPatterns: Seq[String] = details.emptyPatterns - - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val details: ScalaDataTableOptionalEntryTypeDetails[T] private val transformer: TableEntryTransformer[T] = (entry: JavaMap[String, String]) => { diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalRowDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalRowDefinition.scala index ee64bbb6..8adba9a5 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalRowDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableOptionalRowDefinition.scala @@ -10,11 +10,7 @@ import scala.jdk.CollectionConverters._ trait ScalaDataTableOptionalRowDefinition[T] extends ScalaDataTableTypeDefinition { - val details: ScalaDataTableOptionalRowTypeDetails[T] - - override val emptyPatterns: Seq[String] = details.emptyPatterns - - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val details: ScalaDataTableOptionalRowTypeDetails[T] private val transformer: TableRowTransformer[T] = (row: JavaList[String]) => { details.body.transform( diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableRowDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableRowDefinition.scala index 526a857e..48322d25 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableRowDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableRowDefinition.scala @@ -9,11 +9,7 @@ import scala.jdk.CollectionConverters._ trait ScalaDataTableRowDefinition[T] extends ScalaDataTableTypeDefinition { - val details: ScalaDataTableRowTypeDetails[T] - - override val emptyPatterns: Seq[String] = details.emptyPatterns - - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val details: ScalaDataTableRowTypeDetails[T] private val transformer: TableRowTransformer[T] = (row: JavaList[String]) => { details.body.transform( diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableTypeDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableTypeDefinition.scala index df4c4598..6a6fcf51 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableTypeDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableTypeDefinition.scala @@ -4,7 +4,15 @@ import io.cucumber.core.backend.DataTableTypeDefinition trait ScalaDataTableTypeDefinition extends DataTableTypeDefinition - with AbstractDatatableElementTransformerDefinition {} + with AbstractDatatableElementTransformerDefinition { + + val details: ScalaDataTableTypeDetails[_] + + override val location: StackTraceElement = details.stackTraceElement + + override val emptyPatterns: Seq[String] = details.emptyPatterns + +} object ScalaDataTableTypeDefinition { @@ -13,13 +21,13 @@ object ScalaDataTableTypeDefinition { scenarioScoped: Boolean ): ScalaDataTableTypeDefinition = { details match { - case entryDetails @ ScalaDataTableEntryTypeDetails(_, _, _) => + case entryDetails: ScalaDataTableEntryTypeDetails[_] => if (scenarioScoped) { new ScalaScenarioScopedDataTableEntryDefinition[T](entryDetails) } else { new ScalaGlobalDataTableEntryDefinition[T](entryDetails) } - case entryDetails @ ScalaDataTableOptionalEntryTypeDetails(_, _, _) => + case entryDetails: ScalaDataTableOptionalEntryTypeDetails[_] => if (scenarioScoped) { new ScalaScenarioScopedDataTableOptionalEntryDefinition[T]( entryDetails @@ -27,31 +35,31 @@ object ScalaDataTableTypeDefinition { } else { new ScalaGlobalDataTableOptionalEntryDefinition[T](entryDetails) } - case rowDetails @ ScalaDataTableRowTypeDetails(_, _, _) => + case rowDetails: ScalaDataTableRowTypeDetails[_] => if (scenarioScoped) { new ScalaScenarioScopedDataTableRowDefinition[T](rowDetails) } else { new ScalaGlobalDataTableRowDefinition[T](rowDetails) } - case rowDetails @ ScalaDataTableOptionalRowTypeDetails(_, _, _) => + case rowDetails: ScalaDataTableOptionalRowTypeDetails[_] => if (scenarioScoped) { new ScalaScenarioScopedDataTableOptionalRowDefinition[T](rowDetails) } else { new ScalaGlobalDataTableOptionalRowDefinition[T](rowDetails) } - case cellDetails @ ScalaDataTableCellTypeDetails(_, _, _) => + case cellDetails: ScalaDataTableCellTypeDetails[_] => if (scenarioScoped) { new ScalaScenarioScopedDataTableCellDefinition[T](cellDetails) } else { new ScalaGlobalDataTableCellDefinition[T](cellDetails) } - case cellDetails @ ScalaDataTableOptionalCellTypeDetails(_, _, _) => + case cellDetails: ScalaDataTableOptionalCellTypeDetails[_] => if (scenarioScoped) { new ScalaScenarioScopedDataTableOptionalCellDefinition[T](cellDetails) } else { new ScalaGlobalDataTableOptionalCellDefinition[T](cellDetails) } - case rowDetails @ ScalaDataTableTableTypeDetails(_, _, _) => + case rowDetails: ScalaDataTableTableTypeDetails[_] => if (scenarioScoped) { new ScalaScenarioScopedDataTableDefinition[T](rowDetails) } else { diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableTypeDetails.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableTypeDetails.scala index 18a4c14c..3e7a8919 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableTypeDetails.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDataTableTypeDetails.scala @@ -2,46 +2,57 @@ package io.cucumber.scala import scala.reflect.ClassTag -sealed trait ScalaDataTableTypeDetails[T] +sealed trait ScalaDataTableTypeDetails[T] { + def emptyPatterns: Seq[String] + def tag: ClassTag[T] + def stackTraceElement: StackTraceElement +} case class ScalaDataTableEntryTypeDetails[T]( emptyPatterns: Seq[String], body: DataTableEntryDefinitionBody[T], - tag: ClassTag[T] + tag: ClassTag[T], + stackTraceElement: StackTraceElement ) extends ScalaDataTableTypeDetails[T] case class ScalaDataTableOptionalEntryTypeDetails[T]( emptyPatterns: Seq[String], body: DataTableOptionalEntryDefinitionBody[T], - tag: ClassTag[T] + tag: ClassTag[T], + stackTraceElement: StackTraceElement ) extends ScalaDataTableTypeDetails[T] case class ScalaDataTableRowTypeDetails[T]( emptyPatterns: Seq[String], body: DataTableRowDefinitionBody[T], - tag: ClassTag[T] + tag: ClassTag[T], + stackTraceElement: StackTraceElement ) extends ScalaDataTableTypeDetails[T] case class ScalaDataTableOptionalRowTypeDetails[T]( emptyPatterns: Seq[String], body: DataTableOptionalRowDefinitionBody[T], - tag: ClassTag[T] + tag: ClassTag[T], + stackTraceElement: StackTraceElement ) extends ScalaDataTableTypeDetails[T] case class ScalaDataTableCellTypeDetails[T]( emptyPatterns: Seq[String], body: DataTableCellDefinitionBody[T], - tag: ClassTag[T] + tag: ClassTag[T], + stackTraceElement: StackTraceElement ) extends ScalaDataTableTypeDetails[T] case class ScalaDataTableOptionalCellTypeDetails[T]( emptyPatterns: Seq[String], body: DataTableOptionalCellDefinitionBody[T], - tag: ClassTag[T] + tag: ClassTag[T], + stackTraceElement: StackTraceElement ) extends ScalaDataTableTypeDetails[T] case class ScalaDataTableTableTypeDetails[T]( emptyPatterns: Seq[String], body: DataTableDefinitionBody[T], - tag: ClassTag[T] + tag: ClassTag[T], + stackTraceElement: StackTraceElement ) extends ScalaDataTableTypeDetails[T] diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultDataTableCellTransformerDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultDataTableCellTransformerDefinition.scala index 72edfaf0..f8e5c807 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultDataTableCellTransformerDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultDataTableCellTransformerDefinition.scala @@ -17,7 +17,7 @@ trait ScalaDefaultDataTableCellTransformerDefinition override val emptyPatterns: Seq[String] = details.emptyPatterns - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val location: StackTraceElement = details.stackTraceElement override val tableCellByTypeTransformer: TableCellByTypeTransformer = (fromValue: String, toTypeValue: Type) => { diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultDataTableEntryTransformerDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultDataTableEntryTransformerDefinition.scala index df5646c0..95cfb844 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultDataTableEntryTransformerDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultDataTableEntryTransformerDefinition.scala @@ -22,7 +22,7 @@ trait ScalaDefaultDataTableEntryTransformerDefinition override val emptyPatterns: Seq[String] = details.emptyPatterns - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val location: StackTraceElement = details.stackTraceElement override val tableEntryByTypeTransformer: TableEntryByTypeTransformer = ( fromValue: JavaMap[String, String], diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultParameterTransformerDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultParameterTransformerDefinition.scala index 6c06a76e..30edc276 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultParameterTransformerDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultParameterTransformerDefinition.scala @@ -15,7 +15,7 @@ trait ScalaDefaultParameterTransformerDefinition val details: ScalaDefaultParameterTransformerDetails - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val location: StackTraceElement = details.stackTraceElement override val parameterByTypeTransformer: ParameterByTypeTransformer = (fromValue: String, toValue: Type) => { diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultTransformerDetails.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultTransformerDetails.scala index 74b73e40..2ac51735 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultTransformerDetails.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDefaultTransformerDetails.scala @@ -7,15 +7,18 @@ import Aliases.{ } case class ScalaDefaultParameterTransformerDetails( - body: DefaultParameterTransformerBody + body: DefaultParameterTransformerBody, + stackTraceElement: StackTraceElement ) case class ScalaDefaultDataTableCellTransformerDetails( emptyPatterns: Seq[String], - body: DefaultDataTableCellTransformerBody + body: DefaultDataTableCellTransformerBody, + stackTraceElement: StackTraceElement ) case class ScalaDefaultDataTableEntryTransformerDetails( emptyPatterns: Seq[String], - body: DefaultDataTableEntryTransformerBody + body: DefaultDataTableEntryTransformerBody, + stackTraceElement: StackTraceElement ) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDocStringTypeDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDocStringTypeDefinition.scala index 92f5f526..abecd0d6 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDocStringTypeDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDocStringTypeDefinition.scala @@ -12,7 +12,7 @@ abstract class ScalaDocStringTypeDefinition[T] val details: ScalaDocStringTypeDetails[T] - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val location: StackTraceElement = details.stackTraceElement private val transformer: Transformer[T] = (s: String) => { details.body.apply(s) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDocStringTypeDetails.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDocStringTypeDetails.scala index 7112323b..992a9991 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDocStringTypeDetails.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaDocStringTypeDetails.scala @@ -7,5 +7,6 @@ import java.lang.reflect.{Type => JType} case class ScalaDocStringTypeDetails[T]( contentType: String, body: DocStringDefinitionBody[T], - `type`: JType + `type`: JType, + stackTraceElement: StackTraceElement ) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaHookDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaHookDefinition.scala index 48034835..aa7fb3ae 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaHookDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaHookDefinition.scala @@ -10,7 +10,7 @@ trait ScalaHookDefinition extends HookDefinition with AbstractGlueDefinition { val hookDetails: ScalaHookDetails - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val location: StackTraceElement = hookDetails.stackTraceElement override def execute(state: TestCaseState): Unit = { executeAsCucumber(hookDetails.body.apply(new Scenario(state))) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaParameterTypeDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaParameterTypeDefinition.scala index ec6ce321..75c51905 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaParameterTypeDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaParameterTypeDefinition.scala @@ -12,7 +12,7 @@ trait ScalaParameterTypeDefinition[R] val details: ScalaParameterTypeDetails[R] - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val location: StackTraceElement = details.stackTraceElement private val transformer: CaptureGroupTransformer[R] = (parameterContent: Array[String]) => { diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaParameterTypeDetails.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaParameterTypeDetails.scala index 5523db93..633b1b81 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaParameterTypeDetails.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaParameterTypeDetails.scala @@ -6,5 +6,6 @@ case class ScalaParameterTypeDetails[R]( name: String, regex: String, body: List[String] => R, - tag: ClassTag[R] + tag: ClassTag[R], + stackTraceElement: StackTraceElement ) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaStaticHookDefinition.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaStaticHookDefinition.scala index 68250082..ca78f091 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaStaticHookDefinition.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/ScalaStaticHookDefinition.scala @@ -8,7 +8,7 @@ trait ScalaStaticHookDefinition val hookDetails: ScalaStaticHookDetails - override val location: StackTraceElement = new Exception().getStackTrace()(3) + override val location: StackTraceElement = hookDetails.stackTraceElement override def execute(): Unit = { executeAsCucumber(hookDetails.body.apply()) From 667692daa4cfad15390f006d402c1d91547e1f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Jourdan-Weil?= Date: Sat, 26 Jul 2025 17:12:35 +0200 Subject: [PATCH 2/2] refactor: simplify and make errors more explicit for Utils#frame method --- CHANGELOG.md | 3 +++ .../main/scala/io/cucumber/scala/Utils.scala | 22 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fbfe966..d5da5fac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ See also the [CHANGELOG](https://github.com/cucumber/cucumber-jvm/blob/master/CH ### Changed +- [Internal] Fix `getLocation` wherever it was wrongly defined. ([#404](https://github.com/cucumber/cucumber-jvm-scala/issues/404)) + ### Deprecated ### Removed @@ -24,6 +26,7 @@ See also the [CHANGELOG](https://github.com/cucumber/cucumber-jvm/blob/master/CH ### Changed - [Internal] Implement `HookDefinition.getHookType` and unimplement `Location.getLocation`. No impact expected for users. +([#401](https://github.com/cucumber/cucumber-jvm-scala/issues/401)) ## [8.29.0] (2025-07-15) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/Utils.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/Utils.scala index 522dc174..bdcdaec0 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/Utils.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/Utils.scala @@ -9,9 +9,25 @@ private[scala] object Utils { val frames = Thread.currentThread().getStackTrace val currentClass = self.getClass.getName // Note: the -1 check is here for Scala < 2.13 and objects - frames.reverse - .find(f => f.getClassName == currentClass && f.getLineNumber != -1) - .get + findLast(frames)(f => + f.getClassName == currentClass && f.getLineNumber != -1 + ) match { + case Some(stackFrame) => stackFrame + case None => + throw new IllegalStateException( + s"Not able to find stack frame for $currentClass" + ) + } + } + + // Copied from Scala 2.13 library, not available in 2.12 nor in scala-collections-compat + private def findLast[A](seq: Array[A])(p: A => Boolean): Option[A] = { + val it = seq.reverseIterator + while (it.hasNext) { + val elem = it.next() + if (p(elem)) return Some(elem) + } + None } }