From 2d505c12f727bc33aed3911fdfbdf72ffc4a83ef Mon Sep 17 00:00:00 2001 From: Danilo Pianini Date: Mon, 27 Dec 2021 14:12:52 +0100 Subject: [PATCH] fix: require predictable iteration order for extractors in CSVExporter, fixes #1002 --- .../loader/export/exporters/CSVExporter.kt | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/loader/export/exporters/CSVExporter.kt b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/loader/export/exporters/CSVExporter.kt index 7d3544e72a..17f09189e8 100644 --- a/alchemist-loading/src/main/kotlin/it/unibo/alchemist/loader/export/exporters/CSVExporter.kt +++ b/alchemist-loading/src/main/kotlin/it/unibo/alchemist/loader/export/exporters/CSVExporter.kt @@ -21,6 +21,7 @@ import java.io.PrintStream import java.text.SimpleDateFormat import java.util.Date import java.util.Locale +import java.util.SortedMap import java.util.TimeZone import kotlin.io.path.absolutePathString import kotlin.io.path.createTempDirectory @@ -83,10 +84,27 @@ class CSVExporter> @JvmOverloads constructor( override fun exportData(environment: Environment, reaction: Reaction?, time: Time, step: Long) { with(outputPrintStream) { - dataExtractors.forEach { - it.extractData(environment, reaction, time, step).values.forEach { value -> - print(value) - print(' ') + dataExtractors.forEach { extractor -> + val data = extractor.extractData(environment, reaction, time, step) + val names = extractor.columnNames + when { + data.size <= 1 -> data.values.forEach { print("$it ") } + // Labels and keys match + data.size == names.size && data.keys.containsAll(names) -> names.forEach { + print(requireNotNull(data[it]) { "Bug in ${this::class.simpleName}" }) + print(' ') + } + // If the labels do not match keys, require predictable iteration order + else -> { + require(data is LinkedHashMap || data is SortedMap) { + """ + Extractor "${extractor::class.simpleName}" is likely bugged: + 1. the set of labels $names does not match the keys ${data.keys}, but iteration may fail as + 2. it returned a map with non-predictable iteration order of type ${data::class.simpleName}" + """.trimIndent() + } + data.values.forEach { print("$it ") } + } } } println()