diff --git a/Sources/SwiftFrameCore/Config/DeviceData.swift b/Sources/SwiftFrameCore/Config/DeviceData.swift index 0110563..6b6f609 100644 --- a/Sources/SwiftFrameCore/Config/DeviceData.swift +++ b/Sources/SwiftFrameCore/Config/DeviceData.swift @@ -114,6 +114,14 @@ struct DeviceData: Decodable, ConfigValidateable { ) } + if let templateImage { + _ = try SliceSizeCalculator.calculateSliceSize( + templateImageSize: templateImage.ky_nativeSize, + numberOfSlices: numberOfSlices, + gapWidth: gapWidth + ) + } + try screenshotData.forEach { try $0.validate() } try textData.forEach { try $0.validate() } @@ -134,12 +142,12 @@ struct DeviceData: Decodable, ConfigValidateable { CommandLineFormatter.printKeyValue("Gap Width", value: gapWidth, insetBy: tabs) if let templateImage { - let sliceSize = SliceSizeCalculator.calculateSliceSize( + let sliceSize = try? SliceSizeCalculator.calculateSliceSize( templateImageSize: templateImage.ky_nativeSize, numberOfSlices: numberOfSlices, gapWidth: gapWidth ) - CommandLineFormatter.printKeyValue("Output slice size", value: sliceSize.configValidationRepresentation, insetBy: tabs) + CommandLineFormatter.printKeyValue("Output slice size", value: sliceSize?.configValidationRepresentation, insetBy: tabs) } CommandLineFormatter.printKeyValue( diff --git a/Sources/SwiftFrameCore/Extensions/NSError+Extensions.swift b/Sources/SwiftFrameCore/Extensions/NSError+Extensions.swift index d3d95b9..425a49d 100644 --- a/Sources/SwiftFrameCore/Extensions/NSError+Extensions.swift +++ b/Sources/SwiftFrameCore/Extensions/NSError+Extensions.swift @@ -13,7 +13,8 @@ public extension NSError { NSLocalizedDescriptionKey: description, NSError.kExpectationKey: expectation as Any, NSError.kActualValueKey: actualValue as Any - ]) + ] + ) } var expectation: String? { diff --git a/Sources/SwiftFrameCore/Helper Types/Pluralizer.swift b/Sources/SwiftFrameCore/Helper Types/Pluralizer.swift new file mode 100644 index 0000000..e702b0c --- /dev/null +++ b/Sources/SwiftFrameCore/Helper Types/Pluralizer.swift @@ -0,0 +1,17 @@ +import Foundation + +enum Pluralizer { + + static func pluralize(_ value: Int, singular: String, plural: String, zero: String? = nil) -> String { + let absoluteValue = abs(value) + return switch absoluteValue { + case 0: + "\(value) \(zero ?? plural)" + case 1: + "\(value) \(singular)" + default: + "\(value) \(plural)" + } + } + +} diff --git a/Sources/SwiftFrameCore/Workers/ConfigProcessor.swift b/Sources/SwiftFrameCore/Workers/ConfigProcessor.swift index f9d5f90..766e1ae 100644 --- a/Sources/SwiftFrameCore/Workers/ConfigProcessor.swift +++ b/Sources/SwiftFrameCore/Workers/ConfigProcessor.swift @@ -36,12 +36,8 @@ public class ConfigProcessor: VerbosePrintable { // MARK: - Methods public func validate() throws { - try process() - try data.validate() - } - - private func process() throws { try data.process() + try data.validate() } public func run() throws { @@ -109,7 +105,7 @@ public class ConfigProcessor: VerbosePrintable { throw NSError(description: "No template image found") } - let sliceSize = SliceSizeCalculator.calculateSliceSize( + let sliceSize = try SliceSizeCalculator.calculateSliceSize( templateImageSize: templateImage.ky_nativeSize, numberOfSlices: deviceData.numberOfSlices, gapWidth: deviceData.gapWidth diff --git a/Sources/SwiftFrameCore/Workers/SliceSizeCalculator.swift b/Sources/SwiftFrameCore/Workers/SliceSizeCalculator.swift index 5b9753f..aa28d72 100644 --- a/Sources/SwiftFrameCore/Workers/SliceSizeCalculator.swift +++ b/Sources/SwiftFrameCore/Workers/SliceSizeCalculator.swift @@ -2,10 +2,23 @@ import Foundation struct SliceSizeCalculator { - static func calculateSliceSize(templateImageSize: CGSize, numberOfSlices: Int, gapWidth: Int?) -> CGSize { + static func calculateSliceSize(templateImageSize: CGSize, numberOfSlices: Int, gapWidth: Int?) throws -> CGSize { + guard numberOfSlices > 0 else { + throw NSError(description: "Number of slices must be larger than 0") + } // number of slices minus 1 because gaps are only in between, multiplied by gapWidth let totalGapWidthIfAny = gapWidth.flatMap { (numberOfSlices - 1) * $0 } let templateWidthSubstractingGaps = templateImageSize.width - CGFloat(totalGapWidthIfAny ?? 0) + + guard Int(templateWidthSubstractingGaps) >= numberOfSlices else { + let minimumTemplateWidth = numberOfSlices + (totalGapWidthIfAny ?? 0) + throw NSError( + description: "Template image is not wide enough to accommodate \(Pluralizer.pluralize(numberOfSlices, singular: "slice", plural: "slices"))", + expectation: "Template image should be at least \(minimumTemplateWidth) pixels wide", + actualValue: "Template image is \(templateImageSize.width) pixels wide" + ) + } + // Resulting slice is remaining width divided by expected number of slices, height can just be forwarded return CGSize(width: templateWidthSubstractingGaps / CGFloat(numberOfSlices), height: templateImageSize.height) } diff --git a/Tests/SwiftFrameTests/PluralizerTests.swift b/Tests/SwiftFrameTests/PluralizerTests.swift new file mode 100644 index 0000000..b03fb52 --- /dev/null +++ b/Tests/SwiftFrameTests/PluralizerTests.swift @@ -0,0 +1,23 @@ +import Foundation +import XCTest +@testable import SwiftFrameCore + +class PluralizerTests: XCTestCase { + + func testPluralizer_ProducesSingularString_WhenSpecifyingOne() { + XCTAssertEqual(Pluralizer.pluralize(1, singular: "slice", plural: "slices"), "1 slice") + } + + func testPluralizer_ProducesPluralString_WhenSpecifyingBigNumber() { + XCTAssertEqual(Pluralizer.pluralize(32, singular: "slice", plural: "slices"), "32 slices") + } + + func testPluralizer_ProducesPluralString_WhenSpecifyingZero() { + XCTAssertEqual(Pluralizer.pluralize(0, singular: "slice", plural: "slices"), "0 slices") + } + + func testPluralizer_ProducesZeroString_WhenSpecifyingZero() { + XCTAssertEqual(Pluralizer.pluralize(0, singular: "slice", plural: "slices", zero: "bogus"), "0 bogus") + } + +} diff --git a/Tests/SwiftFrameTests/SliceSizeCalculatorTests.swift b/Tests/SwiftFrameTests/SliceSizeCalculatorTests.swift index b31f288..1150c6c 100644 --- a/Tests/SwiftFrameTests/SliceSizeCalculatorTests.swift +++ b/Tests/SwiftFrameTests/SliceSizeCalculatorTests.swift @@ -3,10 +3,10 @@ import XCTest final class SliceSizeCalculatorTests: BaseTestCase { - func testSliceSizeCalculator_ProducesFiveSlices_WhenNotUsingGapWidth() { + func testSliceSizeCalculator_ProducesFiveSlices_WhenNotUsingGapWidth() throws { let templateSize = CGSize(width: 100, height: 50) - let calculatedSliceSize = SliceSizeCalculator.calculateSliceSize( + let calculatedSliceSize = try SliceSizeCalculator.calculateSliceSize( templateImageSize: templateSize, numberOfSlices: 5, gapWidth: nil @@ -14,10 +14,10 @@ final class SliceSizeCalculatorTests: BaseTestCase { XCTAssertEqual(calculatedSliceSize, CGSize(width: 20, height: 50)) } - func testSliceSizeCalculator_ProducesFiveSlices_WhenUsingGapWidth() { + func testSliceSizeCalculator_ProducesFiveSlices_WhenUsingGapWidth() throws { let templateSize = CGSize(width: 100, height: 50) - let calculatedSliceSize = SliceSizeCalculator.calculateSliceSize( + let calculatedSliceSize = try SliceSizeCalculator.calculateSliceSize( templateImageSize: templateSize, numberOfSlices: 5, gapWidth: 5 @@ -25,4 +25,16 @@ final class SliceSizeCalculatorTests: BaseTestCase { XCTAssertEqual(calculatedSliceSize, CGSize(width: 16, height: 50)) } + func testSliceSizeCalculator_ThrowsError_WhenTotalWidthIsNotEnough() { + let templateSize = CGSize(width: 24, height: 50) + + XCTAssertThrowsError( + try SliceSizeCalculator.calculateSliceSize( + templateImageSize: templateSize, + numberOfSlices: 7, + gapWidth: 6 + ) + ) + } + }