~jan0sch/smederee

Showing details for patch c2f2de0476156ddff922d7593c4316b8c06b294f.
2022-11-04 (Fri), 3:21 PM - Jens Grassel - c2f2de0476156ddff922d7593c4316b8c06b294f

VCS: Fix showing of wrong line counts for modified files.

- fix the bug
- add a base for unit tests
Summary of changes
1 files added
  • modules/hub/src/test/scala/de/smederee/hub/VcsRepositoryPatchMetadataTest.scala
2 files modified with 17 lines added and 3 lines removed
  • CHANGELOG.md with 4 added and 0 removed lines
  • modules/hub/src/main/scala/de/smederee/hub/VcsRepository.scala with 13 added and 3 removed lines
diff -rN -u old-smederee/CHANGELOG.md new-smederee/CHANGELOG.md
--- old-smederee/CHANGELOG.md	2025-02-01 19:02:02.848647153 +0000
+++ new-smederee/CHANGELOG.md	2025-02-01 19:02:02.848647153 +0000
@@ -20,6 +20,10 @@
 
 ## Unreleased
 
+### Fixed
+
+- history summary shows wrong number of lines that were added/removed
+
 ## 0.2.0 (2022-11-03)
 
 ### Changed
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepository.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepository.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepository.scala	2025-02-01 19:02:02.848647153 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepository.scala	2025-02-01 19:02:02.848647153 +0000
@@ -360,9 +360,19 @@
         .map(summary =>
           (summary \ "modify_file").toList.flatMap { file =>
             val filename      = VcsPatchFilename.from(file.text)
-            val added_lines   = (file \ "added_lines" \@ "num").headOption.map(_.toInt).getOrElse(0)
-            val removed_lines = (file \ "removed_lines" \@ "num").headOption.map(_.toInt).getOrElse(0)
-            filename.map(filename => VcsPatchSummaryFileModification(added_lines, filename, removed_lines))
+            val added_lines   = file \ "added_lines" \@ "num"
+            val removed_lines = file \ "removed_lines" \@ "num"
+            val added =
+              if (added_lines.nonEmpty && added_lines.forall(_.isDigit))
+                added_lines.toInt
+              else
+                0
+            val removed =
+              if (removed_lines.nonEmpty && removed_lines.forall(_.isDigit))
+                removed_lines.toInt
+              else
+                0
+            filename.map(filename => VcsPatchSummaryFileModification(added, filename, removed))
           }
         )
         .getOrElse(List.empty)
diff -rN -u old-smederee/modules/hub/src/test/scala/de/smederee/hub/VcsRepositoryPatchMetadataTest.scala new-smederee/modules/hub/src/test/scala/de/smederee/hub/VcsRepositoryPatchMetadataTest.scala
--- old-smederee/modules/hub/src/test/scala/de/smederee/hub/VcsRepositoryPatchMetadataTest.scala	1970-01-01 00:00:00.000000000 +0000
+++ new-smederee/modules/hub/src/test/scala/de/smederee/hub/VcsRepositoryPatchMetadataTest.scala	2025-02-01 19:02:02.848647153 +0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2022  Contributors as noted in the AUTHORS.md file
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.smederee.hub
+
+import cats.syntax.all._
+import de.smederee.hub.Generators.given
+
+import munit._
+import org.scalacheck._
+import org.scalacheck.Prop._
+
+final class VcsRepositoryPatchMetadataTest extends ScalaCheckSuite {
+  private val genVcsPatchFilename: Gen[VcsPatchFilename] =
+    Gen.nonEmptyListOf(Gen.alphaNumChar).map(chars => VcsPatchFilename(chars.mkString))
+  private val genVcsPatchFilenames: Gen[List[VcsPatchFilename]] = Gen.listOf(genVcsPatchFilename)
+  private val genVcsPatchSummaryFileModification: Gen[VcsPatchSummaryFileModification] = for {
+    name    <- genVcsPatchFilename
+    added   <- Gen.choose(0, Int.MaxValue)
+    removed <- Gen.choose(0, Int.MaxValue)
+  } yield VcsPatchSummaryFileModification(added, name, removed)
+  private val genVcsPatchSummaryFileModifications: Gen[List[VcsPatchSummaryFileModification]] =
+    Gen.listOf(genVcsPatchSummaryFileModification)
+
+  /** Create a darcs xml patch element from the given input for testing purposes.
+    *
+    * @return
+    *   An xml node which holds all information required to mimick a darcs log xml-output patch entry.
+    */
+  private def createPatchXml(
+      added: List[VcsPatchFilename],
+      modified: List[VcsPatchSummaryFileModification],
+      removed: List[VcsPatchFilename]
+  ): scala.xml.Node = {
+    // We need to preserve the xml parts as they are because line breaks etc. would be added to file names!
+    // format: off
+    val added_files   = added.map(filename => <add_file>{filename.toString}</add_file>)
+    val removed_files = removed.map(filename => <remove_file>{filename.toString}</remove_file>)
+    val modified_files = modified.map { summary =>
+      <modify_file>{summary.name.toString}<removed_lines num={summary.removed.toString}/><added_lines num={summary.added.toString}/></modify_file>
+    }
+    val patch =
+      <patch>
+        <name>TEST</name>
+        <comment>A test comment...</comment>
+        <summary>
+          {added_files}
+          {modified_files}
+          {removed_files}
+        </summary>
+      </patch>
+    // format: on
+    patch
+  }
+
+  property("VcsPatchSummary#fromDarcsXmlLog must parse a given XML node correctly") {
+    forAll(genVcsPatchFilenames, genVcsPatchSummaryFileModifications, genVcsPatchFilenames) {
+      (
+          added: List[VcsPatchFilename],
+          modified: List[VcsPatchSummaryFileModification],
+          removed: List[VcsPatchFilename]
+      ) =>
+        val xmlInput = createPatchXml(added, modified, removed)
+        val expected = VcsPatchSummary(added, modified, removed)
+        VcsPatchSummary.fromDarcsXmlLog(xmlInput) match {
+          case None           => fail("VcsPatchSummary could not be generated!")
+          case Some(obtained) => assertEquals(obtained, expected)
+        }
+    }
+  }
+
+}