mirror of
https://github.com/exyte/Macaw.git
synced 2024-09-11 13:15:35 +03:00
Merge remote-tracking branch 'origin/master' into rendering-respects-screen-scale
# Conflicts: # Source/views/MacawView.swift
This commit is contained in:
commit
dafca2d1f6
@ -1,12 +1,12 @@
|
|||||||
language: swift
|
language: swift
|
||||||
osx_image: xcode10.2
|
osx_image: xcode11.5
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- set -o pipefail && xcodebuild test -project Macaw.xcodeproj -scheme 'Macaw iOS' -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -destination 'platform=iOS Simulator,OS=12.2,name=iPhone X' | xcpretty;
|
- set -o pipefail && xcodebuild test -project Macaw.xcodeproj -scheme 'Macaw iOS' -sdk iphonesimulator13.5 ONLY_ACTIVE_ARCH=NO -destination 'platform=iOS Simulator,OS=13.5,name=iPhone 11 Pro' | xcpretty;
|
||||||
- set -o pipefail && xcodebuild test -project Macaw.xcodeproj -scheme 'MacawOSX' ONLY_ACTIVE_ARCH=NO | xcpretty;
|
- set -o pipefail && xcodebuild test -project Macaw.xcodeproj -scheme 'MacawOSX' ONLY_ACTIVE_ARCH=NO | xcpretty;
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,6 +13,9 @@ class AnimationsHierarchyViewController: UIViewController {
|
|||||||
|
|
||||||
@IBOutlet weak var animView: MacawView!
|
@IBOutlet weak var animView: MacawView!
|
||||||
|
|
||||||
|
var startCallbacks: [()->()] = []
|
||||||
|
var stopCallbacks: [()->()] = []
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
@ -20,6 +23,22 @@ class AnimationsHierarchyViewController: UIViewController {
|
|||||||
animView.zoom.enable()
|
animView.zoom.enable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
|
startCallbacks.forEach {
|
||||||
|
$0()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillDisappear(_ animated: Bool) {
|
||||||
|
super.viewWillDisappear(animated)
|
||||||
|
|
||||||
|
stopCallbacks.forEach {
|
||||||
|
$0()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createTree(height: Int) -> Node {
|
func createTree(height: Int) -> Node {
|
||||||
let rect = Rect(w: 10, h: 10)
|
let rect = Rect(w: 10, h: 10)
|
||||||
|
|
||||||
@ -52,7 +71,14 @@ class AnimationsHierarchyViewController: UIViewController {
|
|||||||
func createLeaf(childForm: Locus, xDelta: Double, yDelta: Double) -> Group {
|
func createLeaf(childForm: Locus, xDelta: Double, yDelta: Double) -> Group {
|
||||||
let inset = childForm.bounds().w / 2
|
let inset = childForm.bounds().w / 2
|
||||||
let leaf = Shape(form: childForm, fill: Color.teal, place: .move(dx: -inset, dy: -inset))
|
let leaf = Shape(form: childForm, fill: Color.teal, place: .move(dx: -inset, dy: -inset))
|
||||||
leaf.placeVar.animation(angle: 2 * .pi, during: 5).cycle().play()
|
|
||||||
|
let animation = leaf.placeVar.animation(angle: 2 * .pi, during: 5).cycle()
|
||||||
|
startCallbacks.append({
|
||||||
|
animation.play()
|
||||||
|
})
|
||||||
|
stopCallbacks.append({
|
||||||
|
animation.stop()
|
||||||
|
})
|
||||||
|
|
||||||
let leafGroup = [leaf].group(place: .move(dx: xDelta, dy: yDelta))
|
let leafGroup = [leaf].group(place: .move(dx: xDelta, dy: yDelta))
|
||||||
leaf.onTap { _ in
|
leaf.onTap { _ in
|
||||||
|
@ -233,7 +233,6 @@
|
|||||||
57614B661F83D15600875933 /* PinchEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E10C1E3B393900D1CB28 /* PinchEvent.swift */; };
|
57614B661F83D15600875933 /* PinchEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E10C1E3B393900D1CB28 /* PinchEvent.swift */; };
|
||||||
57614B671F83D15600875933 /* ContentsInterpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57A27BCE1E44C4EC0057BD3A /* ContentsInterpolation.swift */; };
|
57614B671F83D15600875933 /* ContentsInterpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57A27BCE1E44C4EC0057BD3A /* ContentsInterpolation.swift */; };
|
||||||
57614B681F83D15600875933 /* GroupRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E13E1E3B393900D1CB28 /* GroupRenderer.swift */; };
|
57614B681F83D15600875933 /* GroupRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E13E1E3B393900D1CB28 /* GroupRenderer.swift */; };
|
||||||
57614B691F83D15600875933 /* SVGParserRegexHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1491E3B393900D1CB28 /* SVGParserRegexHelper.swift */; };
|
|
||||||
57614B6B1F83D15600875933 /* NSTimer+Closure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14E1E3B393900D1CB28 /* NSTimer+Closure.swift */; };
|
57614B6B1F83D15600875933 /* NSTimer+Closure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14E1E3B393900D1CB28 /* NSTimer+Closure.swift */; };
|
||||||
57614B6C1F83D15600875933 /* SWXMLHash+TypeConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572CEFC51E2CED4B008C7C83 /* SWXMLHash+TypeConversion.swift */; };
|
57614B6C1F83D15600875933 /* SWXMLHash+TypeConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 572CEFC51E2CED4B008C7C83 /* SWXMLHash+TypeConversion.swift */; };
|
||||||
57614B6D1F83D15600875933 /* AnimationSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E0FF1E3B393900D1CB28 /* AnimationSequence.swift */; };
|
57614B6D1F83D15600875933 /* AnimationSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E0FF1E3B393900D1CB28 /* AnimationSequence.swift */; };
|
||||||
@ -330,7 +329,6 @@
|
|||||||
57E5E1AA1E3B393900D1CB28 /* SVGConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1461E3B393900D1CB28 /* SVGConstants.swift */; };
|
57E5E1AA1E3B393900D1CB28 /* SVGConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1461E3B393900D1CB28 /* SVGConstants.swift */; };
|
||||||
57E5E1AB1E3B393900D1CB28 /* SVGParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1471E3B393900D1CB28 /* SVGParser.swift */; };
|
57E5E1AB1E3B393900D1CB28 /* SVGParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1471E3B393900D1CB28 /* SVGParser.swift */; };
|
||||||
57E5E1AC1E3B393900D1CB28 /* SVGParserError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1481E3B393900D1CB28 /* SVGParserError.swift */; };
|
57E5E1AC1E3B393900D1CB28 /* SVGParserError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1481E3B393900D1CB28 /* SVGParserError.swift */; };
|
||||||
57E5E1AD1E3B393900D1CB28 /* SVGParserRegexHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1491E3B393900D1CB28 /* SVGParserRegexHelper.swift */; };
|
|
||||||
57E5E1AE1E3B393900D1CB28 /* SVGView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14A1E3B393900D1CB28 /* SVGView.swift */; };
|
57E5E1AE1E3B393900D1CB28 /* SVGView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14A1E3B393900D1CB28 /* SVGView.swift */; };
|
||||||
57E5E1AF1E3B393900D1CB28 /* CAAnimationClosure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14C1E3B393900D1CB28 /* CAAnimationClosure.swift */; };
|
57E5E1AF1E3B393900D1CB28 /* CAAnimationClosure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14C1E3B393900D1CB28 /* CAAnimationClosure.swift */; };
|
||||||
57E5E1B01E3B393900D1CB28 /* CGFloat+Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14D1E3B393900D1CB28 /* CGFloat+Double.swift */; };
|
57E5E1B01E3B393900D1CB28 /* CGFloat+Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E14D1E3B393900D1CB28 /* CGFloat+Double.swift */; };
|
||||||
@ -950,7 +948,6 @@
|
|||||||
57E5E1461E3B393900D1CB28 /* SVGConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGConstants.swift; sourceTree = "<group>"; };
|
57E5E1461E3B393900D1CB28 /* SVGConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGConstants.swift; sourceTree = "<group>"; };
|
||||||
57E5E1471E3B393900D1CB28 /* SVGParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGParser.swift; sourceTree = "<group>"; };
|
57E5E1471E3B393900D1CB28 /* SVGParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGParser.swift; sourceTree = "<group>"; };
|
||||||
57E5E1481E3B393900D1CB28 /* SVGParserError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGParserError.swift; sourceTree = "<group>"; };
|
57E5E1481E3B393900D1CB28 /* SVGParserError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGParserError.swift; sourceTree = "<group>"; };
|
||||||
57E5E1491E3B393900D1CB28 /* SVGParserRegexHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGParserRegexHelper.swift; sourceTree = "<group>"; };
|
|
||||||
57E5E14A1E3B393900D1CB28 /* SVGView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGView.swift; sourceTree = "<group>"; };
|
57E5E14A1E3B393900D1CB28 /* SVGView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVGView.swift; sourceTree = "<group>"; };
|
||||||
57E5E14C1E3B393900D1CB28 /* CAAnimationClosure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAAnimationClosure.swift; sourceTree = "<group>"; };
|
57E5E14C1E3B393900D1CB28 /* CAAnimationClosure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CAAnimationClosure.swift; sourceTree = "<group>"; };
|
||||||
57E5E14D1E3B393900D1CB28 /* CGFloat+Double.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Double.swift"; sourceTree = "<group>"; };
|
57E5E14D1E3B393900D1CB28 /* CGFloat+Double.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGFloat+Double.swift"; sourceTree = "<group>"; };
|
||||||
@ -1731,7 +1728,6 @@
|
|||||||
5B1A8C7520A15F7300E5FFAE /* SVGNodeLayout.swift */,
|
5B1A8C7520A15F7300E5FFAE /* SVGNodeLayout.swift */,
|
||||||
57E5E1471E3B393900D1CB28 /* SVGParser.swift */,
|
57E5E1471E3B393900D1CB28 /* SVGParser.swift */,
|
||||||
57E5E1481E3B393900D1CB28 /* SVGParserError.swift */,
|
57E5E1481E3B393900D1CB28 /* SVGParserError.swift */,
|
||||||
57E5E1491E3B393900D1CB28 /* SVGParserRegexHelper.swift */,
|
|
||||||
C4820B171F458D0E008CE0FF /* SVGSerializer.swift */,
|
C4820B171F458D0E008CE0FF /* SVGSerializer.swift */,
|
||||||
57E5E14A1E3B393900D1CB28 /* SVGView.swift */,
|
57E5E14A1E3B393900D1CB28 /* SVGView.swift */,
|
||||||
);
|
);
|
||||||
@ -2811,7 +2807,6 @@
|
|||||||
57614B671F83D15600875933 /* ContentsInterpolation.swift in Sources */,
|
57614B671F83D15600875933 /* ContentsInterpolation.swift in Sources */,
|
||||||
57614B681F83D15600875933 /* GroupRenderer.swift in Sources */,
|
57614B681F83D15600875933 /* GroupRenderer.swift in Sources */,
|
||||||
5B6E192820AC58F900454E7E /* RadialGradient.swift in Sources */,
|
5B6E192820AC58F900454E7E /* RadialGradient.swift in Sources */,
|
||||||
57614B691F83D15600875933 /* SVGParserRegexHelper.swift in Sources */,
|
|
||||||
5B6E192A20AC58F900454E7E /* Align.swift in Sources */,
|
5B6E192A20AC58F900454E7E /* Align.swift in Sources */,
|
||||||
57614B6B1F83D15600875933 /* NSTimer+Closure.swift in Sources */,
|
57614B6B1F83D15600875933 /* NSTimer+Closure.swift in Sources */,
|
||||||
5B6E193620AC58F900454E7E /* Stop.swift in Sources */,
|
5B6E193620AC58F900454E7E /* Stop.swift in Sources */,
|
||||||
@ -2954,7 +2949,6 @@
|
|||||||
57A27BCF1E44C4EC0057BD3A /* ContentsInterpolation.swift in Sources */,
|
57A27BCF1E44C4EC0057BD3A /* ContentsInterpolation.swift in Sources */,
|
||||||
57E5E1A31E3B393900D1CB28 /* GroupRenderer.swift in Sources */,
|
57E5E1A31E3B393900D1CB28 /* GroupRenderer.swift in Sources */,
|
||||||
5B6E192720AC58F900454E7E /* RadialGradient.swift in Sources */,
|
5B6E192720AC58F900454E7E /* RadialGradient.swift in Sources */,
|
||||||
57E5E1AD1E3B393900D1CB28 /* SVGParserRegexHelper.swift in Sources */,
|
|
||||||
5B6E192920AC58F900454E7E /* Align.swift in Sources */,
|
5B6E192920AC58F900454E7E /* Align.swift in Sources */,
|
||||||
57E5E1B11E3B393900D1CB28 /* NSTimer+Closure.swift in Sources */,
|
57E5E1B11E3B393900D1CB28 /* NSTimer+Closure.swift in Sources */,
|
||||||
30FF4962215CE97300FF653C /* MCAMediaTimingFillMode_iOS.swift in Sources */,
|
30FF4962215CE97300FF653C /* MCAMediaTimingFillMode_iOS.swift in Sources */,
|
||||||
@ -3004,6 +2998,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
@ -3029,6 +3024,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||||
DEFINES_MODULE = YES;
|
DEFINES_MODULE = YES;
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
@ -3226,8 +3222,8 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||||
DEVELOPMENT_TEAM = 7T95R85V93;
|
DEVELOPMENT_TEAM = "";
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(SDKROOT)",
|
"$(SDKROOT)",
|
||||||
@ -3249,8 +3245,8 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||||
DEVELOPMENT_TEAM = 7T95R85V93;
|
DEVELOPMENT_TEAM = "";
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(SDKROOT)",
|
"$(SDKROOT)",
|
||||||
|
@ -5,6 +5,22 @@
|
|||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
buildImplicitDependencies = "YES">
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "57FCD26B1D76EA4600CC0FB6"
|
||||||
|
BuildableName = "Macaw.framework"
|
||||||
|
BlueprintName = "Macaw"
|
||||||
|
ReferencedContainer = "container:Macaw.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
</BuildAction>
|
</BuildAction>
|
||||||
<TestAction
|
<TestAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
@ -23,8 +39,6 @@
|
|||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
</Testables>
|
</Testables>
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
@ -36,8 +50,6 @@
|
|||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
debugServiceExtension = "internal"
|
debugServiceExtension = "internal"
|
||||||
allowLocationSimulation = "YES">
|
allowLocationSimulation = "YES">
|
||||||
<AdditionalOptions>
|
|
||||||
</AdditionalOptions>
|
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
@ -45,6 +57,15 @@
|
|||||||
savedToolIdentifier = ""
|
savedToolIdentifier = ""
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
debugDocumentVersioning = "YES">
|
debugDocumentVersioning = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "57FCD26B1D76EA4600CC0FB6"
|
||||||
|
BuildableName = "Macaw.framework"
|
||||||
|
BlueprintName = "Macaw"
|
||||||
|
ReferencedContainer = "container:Macaw.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
</ProfileAction>
|
</ProfileAction>
|
||||||
<AnalyzeAction
|
<AnalyzeAction
|
||||||
buildConfiguration = "Debug">
|
buildConfiguration = "Debug">
|
||||||
|
@ -20,13 +20,13 @@ class MacawSVGTests: XCTestCase {
|
|||||||
private let testFolderName = "MacawTestOutputData"
|
private let testFolderName = "MacawTestOutputData"
|
||||||
private let shouldComparePNGImages = true
|
private let shouldComparePNGImages = true
|
||||||
private let multipleTestsWillRun = false
|
private let multipleTestsWillRun = false
|
||||||
private let shouldSaveFaildedTestImage = false
|
private let shouldSaveFailedTestImage = false
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
super.setUp()
|
super.setUp()
|
||||||
|
|
||||||
if shouldSaveFaildedTestImage {
|
if shouldSaveFailedTestImage {
|
||||||
setupTestFolderDirectory()
|
setupTestFolderDirectory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,6 +36,21 @@ class MacawSVGTests: XCTestCase {
|
|||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func compareResults(nodeContent: String?, referenceContent: String?) {
|
||||||
|
guard let nodeContent = nodeContent else {
|
||||||
|
XCTFail("nodeContent is empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let referenceContent = referenceContent else {
|
||||||
|
XCTFail("referenceContent is empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if nodeContent != referenceContent {
|
||||||
|
XCTFail("nodeContent is not equal to referenceContent" + TestUtils.prettyFirstDifferenceBetweenStrings(s1: nodeContent, s2: referenceContent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func validate(node: Node, referenceFile: String) {
|
func validate(node: Node, referenceFile: String) {
|
||||||
let bundle = Bundle(for: type(of: TestUtils()))
|
let bundle = Bundle(for: type(of: TestUtils()))
|
||||||
|
|
||||||
@ -43,7 +58,7 @@ class MacawSVGTests: XCTestCase {
|
|||||||
if let path = bundle.path(forResource: referenceFile, ofType: "reference") {
|
if let path = bundle.path(forResource: referenceFile, ofType: "reference") {
|
||||||
let clipReferenceContent = try String.init(contentsOfFile: path).trimmingCharacters(in: .newlines)
|
let clipReferenceContent = try String.init(contentsOfFile: path).trimmingCharacters(in: .newlines)
|
||||||
let result = SVGSerializer.serialize(node: node)
|
let result = SVGSerializer.serialize(node: node)
|
||||||
XCTAssertEqual(result, clipReferenceContent)
|
compareResults(nodeContent: result, referenceContent: clipReferenceContent)
|
||||||
} else {
|
} else {
|
||||||
XCTFail("No file \(referenceFile)")
|
XCTFail("No file \(referenceFile)")
|
||||||
}
|
}
|
||||||
@ -192,13 +207,10 @@ class MacawSVGTests: XCTestCase {
|
|||||||
let bundle = Bundle(for: type(of: TestUtils()))
|
let bundle = Bundle(for: type(of: TestUtils()))
|
||||||
do {
|
do {
|
||||||
if let path = bundle.path(forResource: referenceFile, ofType: "reference") {
|
if let path = bundle.path(forResource: referenceFile, ofType: "reference") {
|
||||||
|
|
||||||
let referenceContent = try String(contentsOfFile: path)
|
let referenceContent = try String(contentsOfFile: path)
|
||||||
|
|
||||||
let nodeContent = String(data: getJSONData(node: node), encoding: String.Encoding.utf8)
|
let nodeContent = String(data: getJSONData(node: node), encoding: String.Encoding.utf8)
|
||||||
|
compareResults(nodeContent: nodeContent, referenceContent: referenceContent)
|
||||||
if nodeContent != referenceContent {
|
|
||||||
XCTFail("nodeContent is not equal to referenceContent")
|
|
||||||
}
|
|
||||||
|
|
||||||
let nativeImage = getImage(from: referenceFile)
|
let nativeImage = getImage(from: referenceFile)
|
||||||
|
|
||||||
@ -261,9 +273,9 @@ class MacawSVGTests: XCTestCase {
|
|||||||
|
|
||||||
if referenceContentData != nodeContentData {
|
if referenceContentData != nodeContentData {
|
||||||
|
|
||||||
var failInfo = "referenceContentData is not equal to nodeContentData"
|
var failInfo = "referenceImageData is not equal to nodeImageData"
|
||||||
|
|
||||||
if shouldSaveFaildedTestImage {
|
if shouldSaveFailedTestImage {
|
||||||
let _ = saveImage(image: referenceImage, fileName: referenceFile + "_reference")
|
let _ = saveImage(image: referenceImage, fileName: referenceFile + "_reference")
|
||||||
let _ = saveImage(image: nodeImage, fileName: referenceFile + "_incorrect")
|
let _ = saveImage(image: nodeImage, fileName: referenceFile + "_incorrect")
|
||||||
|
|
||||||
@ -314,7 +326,7 @@ class MacawSVGTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func writeToFile(string: String, fileName: String) -> URL? {
|
func writeToFile(string: String, fileName: String) -> URL? {
|
||||||
guard let directory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) as NSURL else {
|
guard let directory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) as NSURL else {
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
@ -25,4 +25,133 @@ class TestUtils {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class func prettyFirstDifferenceBetweenStrings(s1: String, s2: String) -> String {
|
||||||
|
return prettyFirstDifferenceBetweenNSStrings(s1: s1 as NSString, s2: s2 as NSString) as String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find first differing character between two strings
|
||||||
|
///
|
||||||
|
/// :param: s1 First String
|
||||||
|
/// :param: s2 Second String
|
||||||
|
///
|
||||||
|
/// :returns: .DifferenceAtIndex(i) or .NoDifference
|
||||||
|
fileprivate func firstDifferenceBetweenStrings(s1: NSString, s2: NSString) -> FirstDifferenceResult {
|
||||||
|
let len1 = s1.length
|
||||||
|
let len2 = s2.length
|
||||||
|
|
||||||
|
let lenMin = min(len1, len2)
|
||||||
|
|
||||||
|
for i in 0..<lenMin {
|
||||||
|
if s1.character(at: i) != s2.character(at: i) {
|
||||||
|
return .DifferenceAtIndex(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len1 < len2 {
|
||||||
|
return .DifferenceAtIndex(len1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len2 < len1 {
|
||||||
|
return .DifferenceAtIndex(len2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return .NoDifference
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Create a formatted String representation of difference between strings
|
||||||
|
///
|
||||||
|
/// :param: s1 First string
|
||||||
|
/// :param: s2 Second string
|
||||||
|
///
|
||||||
|
/// :returns: a string, possibly containing significant whitespace and newlines
|
||||||
|
fileprivate func prettyFirstDifferenceBetweenNSStrings(s1: NSString, s2: NSString) -> NSString {
|
||||||
|
let firstDifferenceResult = firstDifferenceBetweenStrings(s1: s1, s2: s2)
|
||||||
|
return prettyDescriptionOfFirstDifferenceResult(firstDifferenceResult: firstDifferenceResult, s1: s1, s2: s2)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Create a formatted String representation of a FirstDifferenceResult for two strings
|
||||||
|
///
|
||||||
|
/// :param: firstDifferenceResult FirstDifferenceResult
|
||||||
|
/// :param: s1 First string used in generation of firstDifferenceResult
|
||||||
|
/// :param: s2 Second string used in generation of firstDifferenceResult
|
||||||
|
///
|
||||||
|
/// :returns: a printable string, possibly containing significant whitespace and newlines
|
||||||
|
fileprivate func prettyDescriptionOfFirstDifferenceResult(firstDifferenceResult: FirstDifferenceResult, s1: NSString, s2: NSString) -> NSString {
|
||||||
|
|
||||||
|
func diffString(index: Int, s1: NSString, s2: NSString) -> NSString {
|
||||||
|
let markerArrow = "\u{2b06}" // "⬆"
|
||||||
|
let ellipsis = "\u{2026}" // "…"
|
||||||
|
/// Given a string and a range, return a string representing that substring.
|
||||||
|
///
|
||||||
|
/// If the range starts at a position other than 0, an ellipsis
|
||||||
|
/// will be included at the beginning.
|
||||||
|
///
|
||||||
|
/// If the range ends before the actual end of the string,
|
||||||
|
/// an ellipsis is added at the end.
|
||||||
|
func windowSubstring(s: NSString, range: NSRange) -> String {
|
||||||
|
let validRange = NSMakeRange(range.location, min(range.length, s.length - range.location))
|
||||||
|
let substring = s.substring(with: validRange)
|
||||||
|
|
||||||
|
let prefix = range.location > 0 ? ellipsis : ""
|
||||||
|
let suffix = (s.length - range.location > range.length) ? ellipsis : ""
|
||||||
|
|
||||||
|
return "\(prefix)\(substring)\(suffix)"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show this many characters before and after the first difference
|
||||||
|
let windowPrefixLength = 10
|
||||||
|
let windowSuffixLength = 10
|
||||||
|
let windowLength = windowPrefixLength + 1 + windowSuffixLength
|
||||||
|
|
||||||
|
let windowIndex = max(index - windowPrefixLength, 0)
|
||||||
|
let windowRange = NSMakeRange(windowIndex, windowLength)
|
||||||
|
|
||||||
|
let sub1 = windowSubstring(s: s1, range: windowRange)
|
||||||
|
let sub2 = windowSubstring(s: s2, range: windowRange)
|
||||||
|
|
||||||
|
let markerPosition = min(windowSuffixLength, index) + (windowIndex > 0 ? 1 : 0)
|
||||||
|
|
||||||
|
let markerPrefix = String(repeating: " ", count: markerPosition)
|
||||||
|
let markerLine = "\(markerPrefix)\(markerArrow)"
|
||||||
|
|
||||||
|
return "Difference at index \(index):\n\(sub1)\n\(sub2)\n\(markerLine)" as NSString
|
||||||
|
}
|
||||||
|
|
||||||
|
switch firstDifferenceResult {
|
||||||
|
case .NoDifference: return "No difference"
|
||||||
|
case .DifferenceAtIndex(let index): return diffString(index: index, s1: s1, s2: s2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Result type for firstDifferenceBetweenStrings()
|
||||||
|
public enum FirstDifferenceResult {
|
||||||
|
/// Strings are identical
|
||||||
|
case NoDifference
|
||||||
|
|
||||||
|
/// Strings differ at the specified index.
|
||||||
|
///
|
||||||
|
/// This could mean that characters at the specified index are different,
|
||||||
|
/// or that one string is longer than the other
|
||||||
|
case DifferenceAtIndex(Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FirstDifferenceResult: CustomStringConvertible {
|
||||||
|
/// Textual representation of a FirstDifferenceResult
|
||||||
|
public var description: String {
|
||||||
|
switch self {
|
||||||
|
case .NoDifference:
|
||||||
|
return "NoDifference"
|
||||||
|
case .DifferenceAtIndex(let index):
|
||||||
|
return "DifferenceAtIndex(\(index))"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Textual representation of a FirstDifferenceResult for debugging purposes
|
||||||
|
public var debugDescription: String {
|
||||||
|
return self.description
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user