Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit dbbc598

Browse files
Properly handle newlines in diff results (#432)
* Properly handle newlines in diff results Apply colors to each line of diff result and indent it correctly. * Add unit tests
1 parent 529a11b commit dbbc598

File tree

3 files changed

+59
-14
lines changed

3 files changed

+59
-14
lines changed

core/src/main/scala/com/softwaremill/diffx/DiffResultPrinter.scala

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ object DiffResultPrinter {
1212
case dr: DiffResultString => s"${dr.diffs.map(ds => showIndented(ds, indent)).mkString("\n")}"
1313
case dr: DiffResultStringLine => mergeChunks(dr.diffs).map(ds => showIndented(ds, indent)).mkString
1414
case dr: DiffResultStringWord => mergeChunks(dr.diffs).map(ds => showIndented(ds, indent)).mkString
15-
case dr: DiffResultChunk => arrowColor("[") + showChange(s"${dr.left}", s"${dr.right}") + arrowColor("]")
16-
case dr: DiffResultValue[_] => showChange(s"${dr.left}", s"${dr.right}")
17-
case dr: IdenticalValue[_] => defaultColor(s"${dr.value}")
18-
case dr: DiffResultMissing[_] => missingColor(s"${dr.value}")
19-
case dr: DiffResultMissingChunk => missingColor(s"[${dr.value}]")
20-
case dr: DiffResultAdditional[_] => additionalColor(s"${dr.value}")
21-
case dr: DiffResultAdditionalChunk => additionalColor(s"[${dr.value}]")
15+
case dr: DiffResultChunk => arrowColor("[") + showChange(s"${dr.left}", s"${dr.right}", indent) + arrowColor("]")
16+
case dr: DiffResultValue[_] => showChange(s"${dr.left}", s"${dr.right}", indent)
17+
case dr: IdenticalValue[_] => defaultColor(s"${dr.value}", indent)
18+
case dr: DiffResultMissing[_] => missingColor(s"${dr.value}", indent)
19+
case dr: DiffResultMissingChunk => missingColor(s"[${dr.value}]", indent)
20+
case dr: DiffResultAdditional[_] => additionalColor(s"${dr.value}", indent)
21+
case dr: DiffResultAdditionalChunk => additionalColor(s"[${dr.value}]", indent)
2222
}
2323
}
2424

@@ -89,12 +89,14 @@ object DiffResultPrinter {
8989
}
9090
}
9191

92-
private def leftColor(s: String)(implicit c: ShowConfig): String = c.left(s)
93-
private def missingColor(s: String)(implicit c: ShowConfig): String = c.missing(s)
94-
private def additionalColor(s: String)(implicit c: ShowConfig): String = c.additional(s)
95-
private def rightColor(s: String)(implicit c: ShowConfig): String = c.right(s)
96-
private def defaultColor(s: String)(implicit c: ShowConfig): String = c.default(s)
92+
private def missingColor(s: String, indent: Int)(implicit c: ShowConfig): String = withColor(s, c.missing, indent)
93+
private def additionalColor(s: String, indent: Int)(implicit c: ShowConfig): String = withColor(s, c.additional, indent)
94+
private def defaultColor(s: String, indent: Int = 0)(implicit c: ShowConfig): String = withColor(s, c.default, indent)
9795
private def arrowColor(s: String)(implicit c: ShowConfig): String = c.arrow(s)
98-
private def showChange(l: String, r: String)(implicit c: ShowConfig): String =
99-
leftColor(l) + arrowColor(" -> ") + rightColor(r)
96+
private def showChange(l: String, r: String, indent: Int)(implicit c: ShowConfig): String =
97+
withColor(l, c.left, indent) + arrowColor(" -> ") + withColor(r, c.right, indent)
98+
99+
private def withColor(value: String, color: String => String, indent: Int): String = {
100+
value.split("\n", -1).map(color(_)).mkString("\n" + " ".repeat(indent))
101+
}
100102
}

core/src/test/scala/com/softwaremill/diffx/test/DiffResultTest.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,34 @@ class DiffResultTest extends AnyFreeSpec with Matchers {
168168
).show() shouldBe "abc abc-[ ]"
169169
}
170170
}
171+
172+
"diff iterable output" - {
173+
"it should show an indented diff for objects with multiline toString" in {
174+
val john = new VerboseNonCaseClass("John", 33)
175+
val mary = new VerboseNonCaseClass("Mary", 28)
176+
val jane = new VerboseNonCaseClass("Jane", 5)
177+
DiffResultIterable(
178+
"List",
179+
Map(
180+
"0" -> IdenticalValue(john),
181+
"1" -> DiffResultAdditional(mary),
182+
"2" -> DiffResultMissing(jane),
183+
)
184+
).show() shouldBe
185+
"""List(
186+
| 0: VerboseNonCaseClass(
187+
| key: John,
188+
| value: 33
189+
| ),
190+
| 1: +VerboseNonCaseClass(
191+
| + key: Mary,
192+
| + value: 28
193+
| +),
194+
| 2: -VerboseNonCaseClass(
195+
| - key: Jane,
196+
| - value: 5
197+
| -))""".stripMargin
198+
199+
}
200+
}
171201
}

core/src/test/scala/com/softwaremill/diffx/test/examples.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,16 @@ class NonCaseClass(private val field: String) {
5757
}
5858
}
5959
}
60+
61+
class VerboseNonCaseClass(private val key: String, private val value: Int) {
62+
override def toString: String =
63+
s"""VerboseNonCaseClass(
64+
| key: $key,
65+
| value: $value
66+
|)""".stripMargin
67+
68+
override def equals(obj: Any): Boolean = obj match {
69+
case other: VerboseNonCaseClass => other.key == key && other.value == value
70+
case _ => false
71+
}
72+
}

0 commit comments

Comments
 (0)