Skip to content

Getting ready to support AppKit #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Sources/SnapshotTestingStitch/ConditionalTypes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#if canImport(UIKit)
import UIKit
public typealias Image = UIImage
public typealias Color = UIColor
public typealias Font = UIFont
public typealias ViewController = UIViewController
#elseif canImport(AppKit)
import AppKit
public typealias Image = NSImage
public typealias Color = NSColor
public typealias Font = NSFont
public typealias ViewController = NSViewController
#endif
16 changes: 8 additions & 8 deletions Sources/SnapshotTestingStitch/Snapshotting.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import UIKit
import CoreGraphics
import SnapshotTesting
import SnapshotTestingHEIC

public extension Snapshotting where Format == UIImage {
public extension Snapshotting where Format == Image {
/// Stitches multiple visual snapshot strategies into a single image asset.
///
/// - Parameters:
Expand Down Expand Up @@ -66,7 +66,7 @@ public extension Snapshotting where Format == UIImage {
/// - Parameters:
/// - tasks: The tasks which should be carried out, in the order that they should be displayed.
/// Tasks can include a title which will be displayed above their respectful image,
/// allowing for easier identification. Any strategy can be used as long as the output format is UIImage.
/// allowing for easier identification. Any strategy can be used as long as the output format is Image.
/// Tasks can can also contain a configuration block which allows for you to modify
/// the value just before it's snapshot is taken.
/// - style: The style configuration which allows for you to customise the appearance of the output image,
Expand All @@ -83,7 +83,7 @@ public extension Snapshotting where Format == UIImage {
perceptualPrecision: Float = 1,
format: ImageFormat = .png
) -> Snapshotting {
let internalStrategy: Snapshotting<UIViewController, UIImage>
let internalStrategy: Snapshotting<ViewController, Image>

switch format {
case .png:
Expand All @@ -96,20 +96,20 @@ public extension Snapshotting where Format == UIImage {
pathExtension: internalStrategy.pathExtension,
diffing: internalStrategy.diffing
) { value in
Async<UIImage> { callback in
Async<Image> { callback in
// Fail fast: Ensure we have tasks to complete, otherwise return an empty image.
//
// An empty image will render an error as part of the SnapshotTesting flow.
guard tasks.isEmpty == false else {
callback(UIImage())
callback(Image())
return
}

// Create a dispatch group to keep track of the remaining tasks
let dispatchGroup = DispatchGroup()

// Create an array to store the final outputs to be stitched
var values = [(index: Int, title: String?, output: UIImage)]()
var values = [(index: Int, title: String?, output: Image)]()

// Loop over each of the user-provided strategies, snapshot them,
// store the output, and update the dispatch group.
Expand All @@ -128,7 +128,7 @@ public extension Snapshotting where Format == UIImage {
// Once all strategies have been completed...
dispatchGroup.notify(queue: .main) {
// Sort values based on input order
let sortedValues: [(String?, UIImage)] = values
let sortedValues: [(String?, Image)] = values
.sorted(by: { lhs, rhs in lhs.index < rhs.index })
.map { result in (result.title, result.output) }

Expand Down
14 changes: 7 additions & 7 deletions Sources/SnapshotTestingStitch/StitchStyle.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import UIKit
import CoreGraphics

public struct StitchStyle {
/// How large should the font size be for the optional titles which appear above each stitched image?
public let fontSize: CGFloat

/// What color should the title text be?
public let titleColor: UIColor
public let titleColor: Color

/// What color should the border be which surrounds each individual stitched image?
public let borderColor: UIColor
public let borderColor: Color

/// How thick should the border be which surrounds each individual stitched image?
public let borderWidth: CGFloat
Expand All @@ -23,7 +23,7 @@ public struct StitchStyle {
public let titleSpacing: CGFloat

/// What color should the background of the image be?
public let backgroundColor: UIColor
public let backgroundColor: Color

/// Creates a defintion of how a stitched snapshot should be presented.
///
Expand All @@ -40,13 +40,13 @@ public struct StitchStyle {
/// - backgroundColor: What color should the background of the image be?
public init(
fontSize: CGFloat = 20,
titleColor: UIColor = .white,
borderColor: UIColor = .red,
titleColor: Color = .white,
borderColor: Color = .red,
borderWidth: CGFloat = 5,
itemSpacing: CGFloat = 32,
framePadding: CGFloat = 32,
titleSpacing: CGFloat = 32,
backgroundColor: UIColor = .black
backgroundColor: Color = .black
) {
assert(borderWidth >= 0, "The provided border width should be a positive integer, or zero if you do not want a border to be displayed.")
assert(itemSpacing >= 0, "The provided item spacing should be a positive integer.")
Expand Down
14 changes: 10 additions & 4 deletions Sources/SnapshotTestingStitch/Stitcher.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import CoreGraphics

#if canImport(UIKit)
import UIKit
#elseif canImport(AppKit)
import AppKit
#endif

struct ImageStitcher {
let inputs: [(title: String?, image: Image)]

let inputs: [(title: String?, image: UIImage)]

func stitch(style: StitchStyle) -> UIImage {
func stitch(style: StitchStyle) -> Image {

// Check whether or not any inputs contain a valid title
let allTitles = inputs
Expand Down Expand Up @@ -88,7 +94,7 @@ struct ImageStitcher {
paragraphStyle.alignment = .center

let titleAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: style.fontSize),
.font: Font.systemFont(ofSize: style.fontSize),
.paragraphStyle: paragraphStyle,
.foregroundColor: style.titleColor
]
Expand Down Expand Up @@ -116,7 +122,7 @@ struct ImageStitcher {
context.fill(CGRect(origin: .zero, size: size))
}

func calculateImageSize(images: [UIImage], includeTitles: Bool, style: StitchStyle) -> CGSize {
func calculateImageSize(images: [Image], includeTitles: Bool, style: StitchStyle) -> CGSize {
let largestHeight = images
.map { $0.size.height }
.max()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ final class SnapshotTestingStitchTests: XCTestCase {
func test_withNoStrategies() {
// You actually get a compiler warning for ambiguity by default, so you have to go through some loops to pass
// literally nothing through.
let tasks: [Snapshotting<UIView, UIImage>] = []
let tasks: [Snapshotting<UIView, Image>] = []

assertSnapshot(
matching: createTestView(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ final class SnapshotTestingStitchHEICTests: XCTestCase {
func test_withNoStrategies() {
// You actually get a compiler warning for ambiguity by default, so you have to go through some loops to pass
// literally nothing through.
let tasks: [Snapshotting<UIView, UIImage>] = []
let tasks: [Snapshotting<UIView, Image>] = []

assertSnapshot(
matching: createTestView(),
Expand Down