From f1af32f2aebb01a432471ed31fbbc8d47a1d0974 Mon Sep 17 00:00:00 2001 From: musketyr Date: Thu, 7 Aug 2025 10:19:20 +0200 Subject: [PATCH] added source line to the assertion failure for better navigation --- docs/guide/src/docs/asciidoc/index.adoc | 21 ++++++ .../dsl/expectations/dsl/DataTable1.java | 13 +++- .../dsl/expectations/dsl/DataTable10.java | 13 +++- .../dsl/expectations/dsl/DataTable2.java | 13 +++- .../dsl/expectations/dsl/DataTable3.java | 13 +++- .../dsl/expectations/dsl/DataTable4.java | 13 +++- .../dsl/expectations/dsl/DataTable5.java | 12 +++- .../dsl/expectations/dsl/DataTable6.java | 13 +++- .../dsl/expectations/dsl/DataTable7.java | 13 +++- .../dsl/expectations/dsl/DataTable8.java | 13 +++- .../dsl/expectations/dsl/DataTable9.java | 13 +++- .../builders/dsl/expectations/dsl/Row1.java | 13 ++++ .../builders/dsl/expectations/dsl/Row10.java | 13 ++++ .../builders/dsl/expectations/dsl/Row2.java | 13 ++++ .../builders/dsl/expectations/dsl/Row3.java | 12 ++++ .../builders/dsl/expectations/dsl/Row4.java | 13 ++++ .../builders/dsl/expectations/dsl/Row5.java | 13 ++++ .../builders/dsl/expectations/dsl/Row6.java | 13 ++++ .../builders/dsl/expectations/dsl/Row7.java | 13 ++++ .../builders/dsl/expectations/dsl/Row8.java | 13 ++++ .../builders/dsl/expectations/dsl/Row9.java | 13 ++++ .../expectations/source/SourceLocation.java | 64 +++++++++++++++++++ 22 files changed, 323 insertions(+), 20 deletions(-) create mode 100644 libs/expectations/src/main/java/builders/dsl/expectations/source/SourceLocation.java diff --git a/docs/guide/src/docs/asciidoc/index.adoc b/docs/guide/src/docs/asciidoc/index.adoc index bbf6f28..ab0e641 100644 --- a/docs/guide/src/docs/asciidoc/index.adoc +++ b/docs/guide/src/docs/asciidoc/index.adoc @@ -86,6 +86,27 @@ include::{root-dir}/libs/expectations/src/test/java/builders/dsl/expectations/Ex <1> Annotate method with `@Test` <2> Use `evaluate()` method to execute all the assertions +== Source Location Tracking + +When your tests fail, Expectations DSL Builder automatically includes source location information in the error messages to help you quickly identify where the failing test data was defined in your code. + +[TIP] +==== +**Enhanced Error Messages**: When a test fails, the error message will show: + +* The template name and values that failed +* The exact source location `(FileName.java:lineNumber)` where the failing data row was created using `is()`, `are()`, or `and()` methods + +This makes debugging much easier, especially when you have many data rows or complex test setups. + +Example error message: +``` +Verification failed for 2 + 3 = 5 with values a=2, b=3, c=6 (ExpectationsTest.java:194) +``` + +The `(ExpectationsTest.java:194)` part shows exactly which line in your test file created the failing data row. +==== + == Using More Dynamic Parameters You can also define the parameter values using `Stream` or `Iterable` objects. In that case the given method will alter header and `Stream` or `Iterable` to define the data rows. diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable1.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable1.java index 22e0312..768b5b6 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable1.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable1.java @@ -86,8 +86,17 @@ Stream generateTests(String template, Assertion1 verification) { return DynamicTest.dynamicTest( title, () -> { - if (!verification.verify(row.getA())) { - throw new AssertionFailedError("Verification failed for " + title + " with values " + headers.getA() + "=" + row.getA()); + boolean verified = false; + Throwable throwable = null; + + try { + verified = verification.verify(row.getA()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + title + " with values " + headers.getA() + "=" + row.getA() + " " + row.getLocation(), throwable); } } ); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable10.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable10.java index e311d51..0d7aa6e 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable10.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable10.java @@ -115,8 +115,17 @@ Stream generateTests(String template, Assertion10 { - if (!verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF(), row.getG(), row.getH(), row.getI(), row.getJ())) { - throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF() + ", " + headers.getG() + "=" + row.getG() + ", " + headers.getH() + "=" + row.getH() + ", " + headers.getI() + "=" + row.getI() + ", " + headers.getJ() + "=" + row.getJ()); + boolean verified = false; + Throwable throwable = null; + + try { + verified = verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF(), row.getG(), row.getH(), row.getI(), row.getJ()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF() + ", " + headers.getG() + "=" + row.getG() + ", " + headers.getH() + "=" + row.getH() + ", " + headers.getI() + "=" + row.getI() + ", " + headers.getJ() + "=" + row.getJ() + " " + row.getLocation(), throwable); } }); }); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable2.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable2.java index 39091cc..1f96661 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable2.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable2.java @@ -86,8 +86,17 @@ Stream generateTests(String template, Assertion2 verification return DynamicTest.dynamicTest( finalTitle, () -> { - if (!verification.verify(row.getA(), row.getB())) { - throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB()); + boolean verified = false; + Throwable throwable = null; + + try { + verified = verification.verify(row.getA(), row.getB()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + " " + row.getLocation(), throwable); } } ); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable3.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable3.java index 33439e1..0ff54bd 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable3.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable3.java @@ -90,8 +90,17 @@ Stream generateTests(String template, Assertion3 verificat return DynamicTest.dynamicTest( finalTitle, () -> { - if (!verification.verify(row.getA(), row.getB(), row.getC())) { - throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC()); + boolean verified = false; + Throwable throwable = null; + + try { + verified = verification.verify(row.getA(), row.getB(), row.getC()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + " " + row.getLocation(), throwable); } } ); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable4.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable4.java index 9bec6c1..67b98ba 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable4.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable4.java @@ -97,8 +97,17 @@ Stream generateTests(String template, Assertion4 verifi return DynamicTest.dynamicTest( finalTitle, () -> { - if (!verification.verify(row.getA(), row.getB(), row.getC(), row.getD())) { - throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD()); + boolean verified = false; + Throwable throwable = null; + + try { + verified = verification.verify(row.getA(), row.getB(), row.getC(), row.getD()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + " " + row.getLocation(), throwable); } } ); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable5.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable5.java index 5cb4e68..8f58504 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable5.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable5.java @@ -100,9 +100,17 @@ Stream generateTests(String template, Assertion5 ver return DynamicTest.dynamicTest( finalTitle, () -> { - if (!verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE())) { - throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE()); + boolean verified = false; + Throwable throwable = null; + try { + verified = verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + " " + row.getLocation(), throwable); } }); }); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable6.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable6.java index 0d2d10a..40b9e4d 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable6.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable6.java @@ -103,8 +103,17 @@ Stream generateTests(String template, Assertion6 return DynamicTest.dynamicTest( finalTitle, () -> { - if (!verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF())) { - throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF()); + boolean verified = false; + Throwable throwable = null; + + try { + verified = verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF() + " " + row.getLocation(), throwable); } }); }); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable7.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable7.java index ed58156..a183c1a 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable7.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable7.java @@ -101,8 +101,17 @@ Stream generateTests(String template, Assertion7 { - if (!verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF(), row.getG())) { - throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF() + ", " + headers.getG() + "=" + row.getG()); + boolean verified = false; + Throwable throwable = null; + + try { + verified = verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF(), row.getG()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF() + ", " + headers.getG() + "=" + row.getG() + " " + row.getLocation(), throwable); } }); }); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable8.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable8.java index b91d0d3..3694166 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable8.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable8.java @@ -104,8 +104,17 @@ Stream generateTests(String template, Assertion8 { - if (!verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF(), row.getG(), row.getH())) { - throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF() + ", " + headers.getG() + "=" + row.getG() + ", " + headers.getH() + "=" + row.getH()); + boolean verified = false; + Throwable throwable = null; + + try { + verified = verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF(), row.getG(), row.getH()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF() + ", " + headers.getG() + "=" + row.getG() + ", " + headers.getH() + "=" + row.getH() + " " + row.getLocation(), throwable); } }); }); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable9.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable9.java index 9a131ee..399676b 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable9.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/DataTable9.java @@ -112,8 +112,17 @@ Stream generateTests(String template, Assertion9 { - if (!verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF(), row.getG(), row.getH(), row.getI())) { - throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF() + ", " + headers.getG() + "=" + row.getG() + ", " + headers.getH() + "=" + row.getH() + ", " + headers.getI() + "=" + row.getI()); + boolean verified = false; + Throwable throwable = null; + + try { + verified = verification.verify(row.getA(), row.getB(), row.getC(), row.getD(), row.getE(), row.getF(), row.getG(), row.getH(), row.getI()); + } catch (Throwable e) { + throwable = e; + } + + if (!verified) { + throw new AssertionFailedError("Verification failed for " + finalTitle + " with values " + headers.getA() + "=" + row.getA() + ", " + headers.getB() + "=" + row.getB() + ", " + headers.getC() + "=" + row.getC() + ", " + headers.getD() + "=" + row.getD() + ", " + headers.getE() + "=" + row.getE() + ", " + headers.getF() + "=" + row.getF() + ", " + headers.getG() + "=" + row.getG() + ", " + headers.getH() + "=" + row.getH() + ", " + headers.getI() + "=" + row.getI() + " " + row.getLocation(), throwable); } }); }); diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row1.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row1.java index 993e1ab..88fd8af 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row1.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row1.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with one element. * @@ -25,6 +27,7 @@ public class Row1 { private final A a; + private final SourceLocation location; /** * Creates a new row with one element. @@ -33,6 +36,7 @@ public class Row1 { */ public Row1(A a) { this.a = a; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -44,4 +48,13 @@ public A getA() { return a; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } + } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row10.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row10.java index 8edbdba..3826709 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row10.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row10.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with ten elements. * @@ -43,6 +45,7 @@ public class Row10 { private final H h; private final I i; private final J j; + private final SourceLocation location; /** * Creates a new row with ten elements. @@ -69,6 +72,7 @@ public Row10(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { this.h = h; this.i = i; this.j = j; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -161,4 +165,13 @@ public J getJ() { return j; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } + } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row2.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row2.java index 61bdf75..73784e4 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row2.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row2.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with two elements. * @@ -27,6 +29,7 @@ public class Row2 { private final A a; private final B b; + private final SourceLocation location; /** * Creates a new row with two elements. @@ -37,6 +40,7 @@ public class Row2 { public Row2(A a, B b) { this.a = a; this.b = b; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -57,4 +61,13 @@ public B getB() { return b; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } + } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row3.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row3.java index 11adfe9..ea8a226 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row3.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row3.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with three elements. * @@ -29,6 +31,7 @@ public class Row3 { private final A a; private final B b; private final C c; + private final SourceLocation location; /** * Creates a new row with three elements. @@ -41,6 +44,7 @@ public Row3(A a, B b, C c) { this.a = a; this.b = b; this.c = c; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -70,6 +74,14 @@ public C getC() { return c; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row4.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row4.java index 5038dc6..d02aaaf 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row4.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row4.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with four elements. * @@ -31,6 +33,7 @@ public class Row4 { private final B b; private final C c; private final D d; + private final SourceLocation location; /** * Creates a new row with four elements. @@ -45,6 +48,7 @@ public Row4(A a, B b, C c, D d) { this.b = b; this.c = c; this.d = d; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -83,4 +87,13 @@ public D getD() { return d; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } + } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row5.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row5.java index 7abea76..570a63d 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row5.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row5.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with five elements. * @@ -33,6 +35,7 @@ public class Row5 { private final C c; private final D d; private final E e; + private final SourceLocation location; /** * Creates a new row with five elements. @@ -49,6 +52,7 @@ public Row5(A a, B b, C c, D d, E e) { this.c = c; this.d = d; this.e = e; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -96,4 +100,13 @@ public E getE() { return e; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } + } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row6.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row6.java index 3648048..b4273c3 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row6.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row6.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with six elements. * @@ -35,6 +37,7 @@ public class Row6 { private final D d; private final E e; private final F f; + private final SourceLocation location; /** * Creates a new row with six elements. @@ -53,6 +56,7 @@ public Row6(A a, B b, C c, D d, E e, F f) { this.d = d; this.e = e; this.f = f; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -109,4 +113,13 @@ public F getF() { return f; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } + } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row7.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row7.java index a5ce3de..ebbdd38 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row7.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row7.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with seven elements. * @@ -37,6 +39,7 @@ public class Row7 { private final E e; private final F f; private final G g; + private final SourceLocation location; /** * Creates a new row with seven elements. @@ -57,6 +60,7 @@ public Row7(A a, B b, C c, D d, E e, F f, G g) { this.e = e; this.f = f; this.g = g; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -122,4 +126,13 @@ public G getG() { return g; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } + } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row8.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row8.java index 86074a4..5e8f446 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row8.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row8.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with eight elements. * @@ -39,6 +41,7 @@ public class Row8 { private final F f; private final G g; private final H h; + private final SourceLocation location; /** * Creates a new row with eight elements. @@ -61,6 +64,7 @@ public Row8(A a, B b, C c, D d, E e, F f, G g, H h) { this.f = f; this.g = g; this.h = h; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -135,4 +139,13 @@ public H getH() { return h; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } + } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row9.java b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row9.java index 08fb69f..83d6f78 100644 --- a/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row9.java +++ b/libs/expectations/src/main/java/builders/dsl/expectations/dsl/Row9.java @@ -17,6 +17,8 @@ */ package builders.dsl.expectations.dsl; +import builders.dsl.expectations.source.SourceLocation; + /** * Represents a row with nine elements. * @@ -41,6 +43,7 @@ public class Row9 { private final G g; private final H h; private final I i; + private final SourceLocation location; /** * Creates a new row with nine elements. @@ -65,6 +68,7 @@ public Row9(A a, B b, C c, D d, E e, F f, G g, H h, I i) { this.g = g; this.h = h; this.i = i; + this.location = SourceLocation.createLocationInTheTestClass(); } /** @@ -148,4 +152,13 @@ public I getI() { return i; } + /** + * Returns the source location where the row was created. + * + * @return the source location + */ + public SourceLocation getLocation() { + return location; + } + } diff --git a/libs/expectations/src/main/java/builders/dsl/expectations/source/SourceLocation.java b/libs/expectations/src/main/java/builders/dsl/expectations/source/SourceLocation.java new file mode 100644 index 0000000..c16976c --- /dev/null +++ b/libs/expectations/src/main/java/builders/dsl/expectations/source/SourceLocation.java @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2024-2025 Vladimir Orany. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package builders.dsl.expectations.source; + +public class SourceLocation { + + public static final SourceLocation UNKNOWN = new SourceLocation("Unknown", -1); + + public static SourceLocation createLocationInTheTestClass() { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + + // Find the first stack trace element that is not from the Java standard library or this class + StackTraceElement element = null; + for (StackTraceElement e : stackTrace) { + if (!e.getClassName().startsWith("java.") && !e.getClassName().startsWith("builders.dsl.expectations") || e.getClassName().endsWith("Test")) { + element = e; + break; + } + } + + if (element == null) { + return UNKNOWN; + } + + return new SourceLocation(element.getFileName(), element.getLineNumber()); + } + + private final String fileName; + private final int lineNumber; + + public SourceLocation(String fileName, int lineNumber) { + this.fileName = fileName; + this.lineNumber = lineNumber; + } + + public String getFileName() { + return fileName; + } + + public int getLineNumber() { + return lineNumber; + } + + @Override + public String toString() { + return String.format("(%s:%d)", fileName, lineNumber); + } + +}