diff --git a/ChromaColorPicker.xcodeproj/project.pbxproj b/ChromaColorPicker.xcodeproj/project.pbxproj index e04b788..a7fb596 100644 --- a/ChromaColorPicker.xcodeproj/project.pbxproj +++ b/ChromaColorPicker.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 35C376DB1D5CF5300069D7A1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 35C376D91D5CF5300069D7A1 /* LaunchScreen.storyboard */; }; FC1BD8C02207D7B700817AF3 /* ChromaColorPickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC1BD8BF2207D7B700817AF3 /* ChromaColorPickerTests.swift */; }; FC1BD8C22207D7B700817AF3 /* ChromaColorPicker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3503B82F1F2689BC00750356 /* ChromaColorPicker.framework */; }; + FC4387C422603AE900F739F1 /* ColorWheelViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCCA42AB226038A400BE2FF9 /* ColorWheelViewTests.swift */; }; FCCA42A5226022A800BE2FF9 /* ColorWheelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCCA42A4226022A800BE2FF9 /* ColorWheelView.swift */; }; FCCA42A7226023F000BE2FF9 /* ChromaColorHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCCA42A6226023F000BE2FF9 /* ChromaColorHandle.swift */; }; FCCA42AA2260329900BE2FF9 /* UIKit+DropShadow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCCA42A92260329900BE2FF9 /* UIKit+DropShadow.swift */; }; @@ -77,6 +78,7 @@ FCCA42A4226022A800BE2FF9 /* ColorWheelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorWheelView.swift; sourceTree = ""; }; FCCA42A6226023F000BE2FF9 /* ChromaColorHandle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChromaColorHandle.swift; sourceTree = ""; }; FCCA42A92260329900BE2FF9 /* UIKit+DropShadow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKit+DropShadow.swift"; sourceTree = ""; }; + FCCA42AB226038A400BE2FF9 /* ColorWheelViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorWheelViewTests.swift; sourceTree = ""; }; FCEA4E262235AAA200C0A1B6 /* ChromaColorPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChromaColorPicker.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -157,7 +159,9 @@ FC1BD8BE2207D7B700817AF3 /* Tests */ = { isa = PBXGroup; children = ( + FCCA42AD226038BD00BE2FF9 /* Extensions */, FC1BD8BF2207D7B700817AF3 /* ChromaColorPickerTests.swift */, + FCCA42AB226038A400BE2FF9 /* ColorWheelViewTests.swift */, FC1BD8C12207D7B700817AF3 /* Info.plist */, ); path = Tests; @@ -184,6 +188,13 @@ path = Extensions; sourceTree = ""; }; + FCCA42AD226038BD00BE2FF9 /* Extensions */ = { + isa = PBXGroup; + children = ( + ); + path = Extensions; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -353,6 +364,7 @@ buildActionMask = 2147483647; files = ( FC1BD8C02207D7B700817AF3 /* ChromaColorPickerTests.swift in Sources */, + FC4387C422603AE900F739F1 /* ColorWheelViewTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Tests/ColorWheelViewTests.swift b/Tests/ColorWheelViewTests.swift new file mode 100644 index 0000000..dfd3ff8 --- /dev/null +++ b/Tests/ColorWheelViewTests.swift @@ -0,0 +1,137 @@ +// +// ColorWheelTests.swift +// ChromaColorPickerTests +// +// Created by Jon Cardasis on 4/11/19. +// Copyright © 2019 Jonathan Cardasis. All rights reserved. +// + +import XCTest +@testable import ChromaColorPicker + +class ColorWheelViewTests: XCTestCase { + + var subject: ColorWheelView! + + override func setUp() { + subject = ColorWheelView(frame: CGRect(x: 0, y: 0, width: 300, height: 300)) + } + + func testBackgroundIsClear() { + XCTAssertEqual(subject.backgroundColor, .clear) + } + + func testImageViewUsesAspectFit() { + XCTAssertEqual(subject.imageView.contentMode, .scaleAspectFit) + } + + func testLayerCornerRadiusUpdatesDuringLayout() { + // Given + subject.frame = CGRect(x: 0, y: 0, width: 200, height: 0) + + // When + subject.layoutSubviews() + + // Then + XCTAssertEqual(subject.layer.cornerRadius, subject.radius) + } + + func testRadiusIfHalfOfWidthWhenWidthIsLargestDimension() { + // Given, When + subject.frame = CGRect(x: 0, y: 0, width: 200, height: 0) + + // Then + XCTAssertEqual(subject.radius, 100) + } + + func testRadiusIfHalfOfHeightWhenHeightIsLargestDimension() { + // Given, When + subject.frame = CGRect(x: 0, y: 0, width: 0, height: 200) + + // Then + XCTAssertEqual(subject.radius, 100) + } + + func testColorWheelImageIsGeneratedEveryLayoutCycle() { + // Given + let width: CGFloat = 200.0 + let screenScalar: CGFloat = UIScreen.main.scale + let expectedFinalSize = CGSize(width: width * screenScalar, height: width * screenScalar) + + // When + subject.layoutSubviews() + let firstImage = subject.imageView.image! + subject.frame = CGRect(x: 0, y: 0, width: width, height: width * 2.0) + subject.layoutSubviews() + let secondImage = subject.imageView.image! + + // Then + XCTAssertNotEqual(firstImage, secondImage) + XCTAssertEqual(secondImage.size, expectedFinalSize) + } + + func testPixelColorShouldReturnNilForPointOutsideBounds() { + // Given, When + let testPoint = CGPoint(x: -100, y: -100) + // Then + XCTAssertNil(subject.pixelColor(at: testPoint)) + } + + func testPixelColorShouldReturnNilForPointInBoundsButOutsideRadius() { + // Given, When + let testPoint = CGPoint(x: 0, y: 0) + // Then + XCTAssertNil(subject.pixelColor(at: testPoint)) + } + + func testPixelColorShouldBeRedAtMaxXMidY() { + // Given, When + let size = subject.frame.size + // Note: Due to the wheel being HUE, any angle will share the same value, therefore + // we can safely inset the width to compensate for any color smoothing at the edges. + let testPoint = CGPoint(x: size.width - 25, y: size.height / 2.0) + let (expectedRedValue, _, _) = UIColor.red.rgbValues + + let vc = UIViewController() + vc.view.addSubview(subject) + vc.beginAppearanceTransition(true, animated: false) + vc.endAppearanceTransition() + + // When + let (actualRedValue, _, _) = subject.pixelColor(at: testPoint)!.rgbValues + + // Then + XCTAssertEqual(actualRedValue, expectedRedValue, accuracy: 0.001) + } + + func testPixelColorShouldBeWhiteAtTheCenter() { + // Given, When + let size = subject.frame.size + let testPoint = CGPoint(x: size.width / 2.0, y: size.height / 2.0) + let expectedColorValues = UIColor.white.rgbValues + + let vc = UIViewController() + vc.view.addSubview(subject) + vc.beginAppearanceTransition(true, animated: false) + vc.endAppearanceTransition() + + // When + let actualColorValues = subject.pixelColor(at: testPoint)!.rgbValues + + // Then + XCTAssertEqual(actualColorValues.red, expectedColorValues.red, accuracy: 0.005) + XCTAssertEqual(actualColorValues.green, expectedColorValues.green, accuracy: 0.005) + XCTAssertEqual(actualColorValues.blue, expectedColorValues.blue, accuracy: 0.005) + } + +} + +private extension UIColor { + var rgbValues: (red: CGFloat, green: CGFloat, blue: CGFloat) { + var red: CGFloat = 0 + var green: CGFloat = 0 + var blue: CGFloat = 0 + getRed(&red, green: &green, blue: &blue, alpha: nil) + return (red, green, blue) + } +}