From ea6ecec96d7a6b918d8316d0ae886e88741f0a79 Mon Sep 17 00:00:00 2001 From: Daniele Segato Date: Wed, 1 Mar 2023 16:48:59 +0100 Subject: [PATCH] CsvReport: escape special characters #223 the default escape character for CSV is " which has to be escaped with a double "" Additionally, when a column contains any of these character it has to be put inside quotes: - " (double quote) - , (comma) - ' (single quote) - \ (backslash) - \n (new line) --- .../license/internal/report/CsvReport.kt | 24 +++++++++----- .../internal/report/CsvReportSpec.groovy | 33 +++++++++++++++++++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/gradle-license-plugin/src/main/kotlin/com/jaredsburrows/license/internal/report/CsvReport.kt b/gradle-license-plugin/src/main/kotlin/com/jaredsburrows/license/internal/report/CsvReport.kt index a155f685..b9969e08 100644 --- a/gradle-license-plugin/src/main/kotlin/com/jaredsburrows/license/internal/report/CsvReport.kt +++ b/gradle-license-plugin/src/main/kotlin/com/jaredsburrows/license/internal/report/CsvReport.kt @@ -66,7 +66,21 @@ class CsvReport(private val projects: List) : Report { /** Add elements to Csv. */ private fun MutableList.addCsvString(element: String): Boolean { - return this.add(element.valueOrNull()) + val escaped = element.valueOrNull() + ?.replace("\"", "\"\"") + ?.let { el -> + when { + el.contains(",") || + el.contains("\n") || + el.contains("'") || + el.contains("\\") || + el.contains("\"") + -> "\"$el\"" + + else -> el + } + } + return this.add(escaped) } /** Add List of elements to Csv as comma separated list with quotes. */ @@ -76,13 +90,7 @@ class CsvReport(private val projects: List) : Report { ): Boolean { return when { elements.isEmpty() -> this.add(null) - else -> { - val element = elements.joinToString(separator = ",", transform = transform) - when (elements.size) { - 1 -> this.add(element) - else -> this.add("\"${element}\"") - } - } + else -> addCsvString(elements.joinToString(separator = ",", transform = transform)) } } diff --git a/gradle-license-plugin/src/test/groovy/com/jaredsburrows/license/internal/report/CsvReportSpec.groovy b/gradle-license-plugin/src/test/groovy/com/jaredsburrows/license/internal/report/CsvReportSpec.groovy index 3d432728..7746b44a 100644 --- a/gradle-license-plugin/src/test/groovy/com/jaredsburrows/license/internal/report/CsvReportSpec.groovy +++ b/gradle-license-plugin/src/test/groovy/com/jaredsburrows/license/internal/report/CsvReportSpec.groovy @@ -92,4 +92,37 @@ final class CsvReportSpec extends Specification { then: assertCsv(expected, actual) } + + def 'open source csv - escape characters'() { + given: + def developerA = new Developer(id: 'Joe') + def developerB = new Developer(id: '5\" Above Ground') + def developers = [developerA, developerB] + def license = new License( + name: 'Apache, 2.0', + url: 'url' + ) + def project = new Model( + name: "Joe's project", + description: 'Copyright "Joe" 2023\n\nAll right reserved\\to me', + licenses: [license], + url: 'url', + developers: developers, + inceptionYear: 'year', + groupId: 'foo', + artifactId: 'bar', + version: '1.2.3', + ) + def projects = [project] + def sut = new CsvReport(projects) + + when: + def actual = sut.toString() + def expected = + "project,description,version,developers,url,year,licenses,license urls,dependency\n" + + "\"Joe\'s project\",\"Copyright \"\"Joe\"\" 2023\n\nAll right reserved\\to me\",1.2.3,\"Joe,5\"\" Above Ground\",url,year,\"Apache, 2.0\",url,foo:bar:1.2.3" + + then: + assertCsv(expected, actual) + } }