From b0f3640eb6654c397ee9c80add67007bf87c1821 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Sun, 7 Jan 2024 15:33:34 +0000 Subject: [PATCH] Do not allow folder contents to have duplicate names. --- src/main/kotlin/filesystem/FSCreator.kt | 15 +++++++++++---- src/main/kotlin/filesystem/FSEntry.kt | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/filesystem/FSCreator.kt b/src/main/kotlin/filesystem/FSCreator.kt index 7a9f4a6..84b4487 100644 --- a/src/main/kotlin/filesystem/FSCreator.kt +++ b/src/main/kotlin/filesystem/FSCreator.kt @@ -10,15 +10,21 @@ class FSCreator { /** * Create entry, leaving existing folders' contents, but overwriting existing files. * @throws CyclicFolderException Cyclic folders cannot be created. + * @throws DuplicateEntryNameException A folder or sub-folder contains entries with duplicate names. */ - @Throws(CyclicFolderException::class) + @Throws(CyclicFolderException::class, DuplicateEntryNameException::class) fun create( entryToCreate: FSEntry, destination: String, ) { // No point in running anything if we know the input is invalid. - if (entryToCreate is FSFolder && entryToCreate.isCyclic()) { - throw CyclicFolderException() + if (entryToCreate is FSFolder) { + if (entryToCreate.isCyclic()) { + throw CyclicFolderException() + } + if (entryToCreate.deepHasDuplicateNames()) { + throw DuplicateEntryNameException() + } } val queue = @@ -46,4 +52,5 @@ class FSCreator { } } -class CyclicFolderException : Exception("Cyclic FSFolders are not supported") \ No newline at end of file +class CyclicFolderException : Exception("Cyclic FSFolders are not supported") +class DuplicateEntryNameException : Exception("Folder contains entries with duplicate names") \ No newline at end of file diff --git a/src/main/kotlin/filesystem/FSEntry.kt b/src/main/kotlin/filesystem/FSEntry.kt index 214b3a2..534972b 100644 --- a/src/main/kotlin/filesystem/FSEntry.kt +++ b/src/main/kotlin/filesystem/FSEntry.kt @@ -34,6 +34,26 @@ class FSFolder(name: String, val entries: List) : FSEntry(name) { } return false } + + /** + * Check whether a folder contains multiple entries with the same name. + */ + fun hasDuplicateNames(): Boolean { + val seen = HashSet() + return entries.any { !seen.add(it.name) } + } + + internal fun deepHasDuplicateNames(): Boolean { + val queue = ArrayDeque(listOf(this)) + while (queue.isNotEmpty()) { + val entry = queue.removeFirst() + if (entry.hasDuplicateNames()) { + return true + } + queue.addAll(entry.entries.mapNotNull { it as? FSFolder }) + } + return false + } } class InvalidEntryNameException(name: String) : Exception("Invalid FSEntry name: '$name'") \ No newline at end of file