From d29eada4bb4e478292d97c46899376381bf72269 Mon Sep 17 00:00:00 2001 From: ryohey Date: Wed, 14 Jul 2021 21:46:03 +0900 Subject: [PATCH] Fix removeEmpty() --- .../ProjectSpec/CollectionExtensions.swift | 59 ++++++++++--------- .../XcodeGenKitTests/SpecGeneratorTests.swift | 45 +++++++++++--- 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/Sources/ProjectSpec/CollectionExtensions.swift b/Sources/ProjectSpec/CollectionExtensions.swift index 40803a24..49888b67 100644 --- a/Sources/ProjectSpec/CollectionExtensions.swift +++ b/Sources/ProjectSpec/CollectionExtensions.swift @@ -1,33 +1,38 @@ import Foundation -private protocol EmptyRemovable { - func removeEmpty() -> Self - var isEmpty: Bool { get } -} - -extension Array: EmptyRemovable { - public func removeEmpty() -> Array { - return compactMap { - if let e = ($0 as? EmptyRemovable)?.removeEmpty() { - return e.isEmpty ? nil : e as? Element - } - return $0 +private func convertEmptyToNil(_ value: T) -> T? { + switch value as Any { + case Optional.none: + return nil + case let arr as Array: + let arr = arr.removeEmpty() + if !arr.isEmpty, + let arr = arr as? T { + return arr + } else { + return nil } - } -} - -extension Dictionary: EmptyRemovable { - // this is a little trick that defines the generics parameter from optional Value to unwrapped Value - private static func removeEmpty(dict: Dictionary) -> Dictionary { - return dict.compactMapValues { - if let e = ($0 as? EmptyRemovable)?.removeEmpty() { - return e.isEmpty ? nil : e as? Value - } - return $0 + case let dict as Dictionary: + let dict = dict.removeEmpty() + if !dict.isEmpty, + let dict = dict as? T { + return dict + } else { + return nil } - } - - public func removeEmpty() -> Dictionary { - return Dictionary.removeEmpty(dict: self) + default: + return value + } +} + +extension Array { + public func removeEmpty() -> Self { + compactMap(convertEmptyToNil) + } +} + +extension Dictionary { + public func removeEmpty() -> Self { + compactMapValues(convertEmptyToNil) } } diff --git a/Tests/XcodeGenKitTests/SpecGeneratorTests.swift b/Tests/XcodeGenKitTests/SpecGeneratorTests.swift index 7f2b3974..2fe89581 100644 --- a/Tests/XcodeGenKitTests/SpecGeneratorTests.swift +++ b/Tests/XcodeGenKitTests/SpecGeneratorTests.swift @@ -86,14 +86,43 @@ class SpecGeneratorTests: XCTestCase { } func testRemoveEmpty() { - let arr = [[], [1, [2], []], [3]] - let removed = arr.removeEmpty() - XCTAssertEqual(removed.count, 2) + describe { + $0.it("removes empty arrays from array") { + let arr = [[], [1], [], [2, 3]] + XCTAssertEqual(arr.removeEmpty(), [[1], [2, 3]]) + } - let dict: [String: Any?] = ["e": nil] - let removed2: [String: Any?] = dict.removeEmpty() - XCTAssertEqual(removed2.count, 0) - let removed3: [String: Any] = dict.compactMapValues { $0 } - XCTAssertEqual(removed3.count, 0) + $0.it("removes nils from array") { + let arr = [nil, 1, nil, 2, 3] + XCTAssertEqual(arr.removeEmpty(), [1, 2, 3]) + } + + $0.it("removes nils and empty arrays from array") { + let arr = [nil, [1], nil, [2], []] + XCTAssertEqual(arr.removeEmpty(), [[1], [2]]) + } + + $0.it("removes nils and empty arrays from nested array") { + let arr: [[[Int?]?]] = [[[1, nil], nil, []]] + XCTAssertEqual(arr.removeEmpty(), [[[1]]]) + } + + $0.it("removes empty dictionaries from array") { + let dict = [["foo": 1], [:], ["bar": 2]] + XCTAssertEqual(dict.removeEmpty(), [["foo": 1], ["bar": 2]]) + } + + $0.it("removes nils from dictionary") { + let dict = ["foo": nil, "bar": 1] + let b = dict.removeEmpty() + XCTAssertEqual(b, ["bar": 1]) + } + + $0.it("removes empty dictionaries from dictionary") { + let dict = ["foo": [:], "bar": ["x": 1]] + let b = dict.removeEmpty() + XCTAssertEqual(b, ["bar": ["x": 1]]) + } + } } }