CyborgTests/TestUtilities.swift (170 lines of code) (raw):

// // Copyright (c) 2018. Uber Technologies // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // @testable import Cyborg import XCTest class NoTheme: ResourceProviding, ThemeProviding { func colorFromResources(named _: String) -> UIColor { return .black } func colorFromTheme(named _: String) -> UIColor { return .black } } extension CGPoint { init(_ xy: (CGFloat, CGFloat)) { self.init(x: xy.0, y: xy.1) } } extension CGSize { static let identity = CGSize(width: 1, height: 1) } func createPath(from pathSegment: PathSegment, start: PriorContext = .zero, path: CGMutablePath = CGMutablePath()) -> CGMutablePath { var priorContext: PriorContext = start for segment in pathSegment { priorContext = segment.apply(to: path, using: priorContext, in: .identity) } return path } extension String { func withXMLString<T>(_ function: (XMLString) -> (T)) -> T { let (string, buffer) = XMLString.create(from: self) defer { buffer.deallocate() } return function(string) } } extension XMLString { static func create(from string: String) -> (XMLString, UnsafeMutablePointer<UInt8>) { return string.withCString { pointer in pointer.withMemoryRebound(to: UInt8.self, capacity: string.utf8.count + 1, { pointer in let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: string.count + 1) for i in 0..<string.utf8.count + 1 { buffer.advanced(by: i).pointee = pointer.advanced(by: i).pointee } return (XMLString(buffer, count: Int32(string.utf8.count)), buffer) }) } } } extension ParseResult { var asOptional: (Wrapped, Int32)? { switch self { case .ok(let wrapped, let int): return (wrapped, int) case .error: return nil } } } extension Result { func expectSuccess() -> Wrapped { switch self { case .ok(let wrapped): return wrapped case .error(let error): fatalError(error) } } func expectFailure() -> ParseError { switch self { case .ok(let wrapped): fatalError("\(wrapped)") case .error(let error): return error } } } extension VectorDrawable { static func create(from string: String) -> Result<VectorDrawable> { return create(from: string.data(using: .utf8)!) } } extension CALayer { func layerInHierarchy(named name: String) -> CALayer? { if self.name == name { return self } for layer in sublayers ?? [] { if layer.name == name { return layer } else if let sublayer = layer.layerInHierarchy(named: name) { return sublayer } } return nil } } extension CGSize { func intoBounds() -> CGRect { return CGRect(origin: .zero, size: self) } } extension CGRect { static func boundsRect(_ width: CGFloat, _ height: CGFloat) -> CGRect { return .init(origin: .zero, size: .init(width: width, height: height)) } } indirect enum ElementType { static let path: ElementType = .pathWithGradient(nil) case clipPath case pathWithGradient(ElementType?) case group([ElementType]) case gradient var asType: AnyClass { switch self { case .clipPath: return VectorDrawable.ClipPath.self case .pathWithGradient: return VectorDrawable.Path.self case .group: return VectorDrawable.Group.self case .gradient: return VectorDrawable.Gradient.self } } var children: [ElementType] { if case .group(let children) = self { return children } else if case .pathWithGradient(let optionalChild) = self, let child = optionalChild { return [child] } else { return [] } } } func assertHierarchiesEqual(_ lhs: DrawableHierarchyProviding, _ rhs: [ElementType], file: StaticString = #file, line: UInt = #line) { XCTAssert( lhs.hierarchyMatches(rhs), "Hierarchies didn't match: \n Expected: \(lhs), Actual: \(rhs)", file: file, line: line ) } protocol DrawableHierarchyProviding: AnyObject { var hierarchy: [GroupChild] { get } } extension DrawableHierarchyProviding { func hierarchyMatches(_ expectedHierarchy: [ElementType]) -> Bool { if hierarchy.count != expectedHierarchy.count { print(hierarchy) return false } for (child, elementType) in zip(hierarchy, expectedHierarchy) { if type(of: child) == elementType.asType { if let child = child as? DrawableHierarchyProviding, !child.hierarchyMatches(elementType.children) { return false } } else { return false } } return true } } extension VectorDrawable: DrawableHierarchyProviding { var hierarchy: [GroupChild] { return groups } } extension VectorDrawable.Group: DrawableHierarchyProviding { var hierarchy: [GroupChild] { return children } }