ab87c9fd by 魏小强

ceshi

1 parent acaa02c1
Showing 62 changed files with 2371 additions and 20 deletions
...@@ -208,7 +208,7 @@ ...@@ -208,7 +208,7 @@
208 6003F586195388D20070C39A /* Sources */, 208 6003F586195388D20070C39A /* Sources */,
209 6003F587195388D20070C39A /* Frameworks */, 209 6003F587195388D20070C39A /* Frameworks */,
210 6003F588195388D20070C39A /* Resources */, 210 6003F588195388D20070C39A /* Resources */,
211 D64742FE184E91E0FBAA866F /* [CP] Embed Pods Frameworks */, 211 5ABB5B4107E1A8D5114A0BE8 /* [CP] Embed Pods Frameworks */,
212 ); 212 );
213 buildRules = ( 213 buildRules = (
214 ); 214 );
...@@ -318,44 +318,44 @@ ...@@ -318,44 +318,44 @@
318 shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 318 shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
319 showEnvVarsInLog = 0; 319 showEnvVarsInLog = 0;
320 }; 320 };
321 A3A9A2FA91267A67620EFAA0 /* [CP] Check Pods Manifest.lock */ = { 321 5ABB5B4107E1A8D5114A0BE8 /* [CP] Embed Pods Frameworks */ = {
322 isa = PBXShellScriptBuildPhase; 322 isa = PBXShellScriptBuildPhase;
323 buildActionMask = 2147483647; 323 buildActionMask = 2147483647;
324 files = ( 324 files = (
325 ); 325 );
326 inputFileListPaths = (
327 );
328 inputPaths = ( 326 inputPaths = (
329 "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 327 "${PODS_ROOT}/Target Support Files/Pods-JCategoryKit_Example/Pods-JCategoryKit_Example-frameworks.sh",
330 "${PODS_ROOT}/Manifest.lock", 328 "${BUILT_PRODUCTS_DIR}/JCategoryKit/JCategoryKit.framework",
331 );
332 name = "[CP] Check Pods Manifest.lock";
333 outputFileListPaths = (
334 ); 329 );
330 name = "[CP] Embed Pods Frameworks";
335 outputPaths = ( 331 outputPaths = (
336 "$(DERIVED_FILE_DIR)/Pods-JCategoryKit_Example-checkManifestLockResult.txt", 332 "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JCategoryKit.framework",
337 ); 333 );
338 runOnlyForDeploymentPostprocessing = 0; 334 runOnlyForDeploymentPostprocessing = 0;
339 shellPath = /bin/sh; 335 shellPath = /bin/sh;
340 shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 336 shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-JCategoryKit_Example/Pods-JCategoryKit_Example-frameworks.sh\"\n";
341 showEnvVarsInLog = 0; 337 showEnvVarsInLog = 0;
342 }; 338 };
343 D64742FE184E91E0FBAA866F /* [CP] Embed Pods Frameworks */ = { 339 A3A9A2FA91267A67620EFAA0 /* [CP] Check Pods Manifest.lock */ = {
344 isa = PBXShellScriptBuildPhase; 340 isa = PBXShellScriptBuildPhase;
345 buildActionMask = 2147483647; 341 buildActionMask = 2147483647;
346 files = ( 342 files = (
347 ); 343 );
344 inputFileListPaths = (
345 );
348 inputPaths = ( 346 inputPaths = (
349 "${PODS_ROOT}/Target Support Files/Pods-JCategoryKit_Example/Pods-JCategoryKit_Example-frameworks.sh", 347 "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
350 "${BUILT_PRODUCTS_DIR}/JCategoryKit/JCategoryKit.framework", 348 "${PODS_ROOT}/Manifest.lock",
349 );
350 name = "[CP] Check Pods Manifest.lock";
351 outputFileListPaths = (
351 ); 352 );
352 name = "[CP] Embed Pods Frameworks";
353 outputPaths = ( 353 outputPaths = (
354 "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JCategoryKit.framework", 354 "$(DERIVED_FILE_DIR)/Pods-JCategoryKit_Example-checkManifestLockResult.txt",
355 ); 355 );
356 runOnlyForDeploymentPostprocessing = 0; 356 runOnlyForDeploymentPostprocessing = 0;
357 shellPath = /bin/sh; 357 shellPath = /bin/sh;
358 shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-JCategoryKit_Example/Pods-JCategoryKit_Example-frameworks.sh\"\n"; 358 shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
359 showEnvVarsInLog = 0; 359 showEnvVarsInLog = 0;
360 }; 360 };
361 E7B9F2BB3382B44E49A9CEEE /* [CP] Embed Pods Frameworks */ = { 361 E7B9F2BB3382B44E49A9CEEE /* [CP] Embed Pods Frameworks */ = {
......
1 <?xml version="1.0" encoding="UTF-8"?>
2 <Workspace
3 version = "1.0">
4 <FileRef
5 location = "group:JCategoryKit.xcodeproj">
6 </FileRef>
7 <FileRef
8 location = "group:Pods/Pods.xcodeproj">
9 </FileRef>
10 </Workspace>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>IDEDidComputeMac32BitWarning</key>
6 <true/>
7 </dict>
8 </plist>
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
7 // 7 //
8 8
9 #import "STViewController.h" 9 #import "STViewController.h"
10 #import <Person.h>
10 11
11 @interface STViewController () 12 @interface STViewController ()
12 13
...@@ -17,7 +18,8 @@ ...@@ -17,7 +18,8 @@
17 - (void)viewDidLoad 18 - (void)viewDidLoad
18 { 19 {
19 [super viewDidLoad]; 20 [super viewDidLoad];
20 // Do any additional setup after loading the view, typically from a nib. 21 Person *p = [[Person alloc] init];
22 [p eat];
21 } 23 }
22 24
23 - (void)didReceiveMemoryWarning 25 - (void)didReceiveMemoryWarning
......
1 PODS:
2 - FBSnapshotTestCase (2.1.4):
3 - FBSnapshotTestCase/SwiftSupport (= 2.1.4)
4 - FBSnapshotTestCase/Core (2.1.4)
5 - FBSnapshotTestCase/SwiftSupport (2.1.4):
6 - FBSnapshotTestCase/Core
7 - JCategoryKit (1.0.0)
8
9 DEPENDENCIES:
10 - FBSnapshotTestCase
11 - JCategoryKit (from `../`)
12
13 SPEC REPOS:
14 trunk:
15 - FBSnapshotTestCase
16
17 EXTERNAL SOURCES:
18 JCategoryKit:
19 :path: "../"
20
21 SPEC CHECKSUMS:
22 FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
23 JCategoryKit: 1ee089cd5593b2515c06f8b99e9eb02fdac4eecd
24
25 PODFILE CHECKSUM: 7301f47448ac58a307221e0e73e2a910d76a70ab
26
27 COCOAPODS: 1.11.2
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #import <UIKit/UIKit.h>
12
13 @interface UIApplication (StrictKeyWindow)
14
15 /**
16 @return The receiver's @c keyWindow. Raises an assertion if @c nil.
17 */
18 - (UIWindow *)fb_strictKeyWindow;
19
20 @end
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #import <FBSnapshotTestCase/UIApplication+StrictKeyWindow.h>
12
13 @implementation UIApplication (StrictKeyWindow)
14
15 - (UIWindow *)fb_strictKeyWindow
16 {
17 UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
18 if (!keyWindow) {
19 [NSException raise:@"FBSnapshotTestCaseNilKeyWindowException"
20 format:@"Snapshot tests must be hosted by an application with a key window. Please ensure your test"
21 " host sets up a key window at launch (either via storyboards or programmatically) and doesn't"
22 " do anything to remove it while snapshot tests are running."];
23 }
24 return keyWindow;
25 }
26
27 @end
1 //
2 // Created by Gabriel Handford on 3/1/09.
3 // Copyright 2009-2013. All rights reserved.
4 // Created by John Boiles on 10/20/11.
5 // Copyright (c) 2011. All rights reserved
6 // Modified by Felix Schulze on 2/11/13.
7 // Copyright 2013. All rights reserved.
8 //
9 // Permission is hereby granted, free of charge, to any person
10 // obtaining a copy of this software and associated documentation
11 // files (the "Software"), to deal in the Software without
12 // restriction, including without limitation the rights to use,
13 // copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following
16 // conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 // OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 #import <UIKit/UIKit.h>
32
33 @interface UIImage (Compare)
34
35 - (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance;
36
37 @end
1 //
2 // Created by Gabriel Handford on 3/1/09.
3 // Copyright 2009-2013. All rights reserved.
4 // Created by John Boiles on 10/20/11.
5 // Copyright (c) 2011. All rights reserved
6 // Modified by Felix Schulze on 2/11/13.
7 // Copyright 2013. All rights reserved.
8 //
9 // Permission is hereby granted, free of charge, to any person
10 // obtaining a copy of this software and associated documentation
11 // files (the "Software"), to deal in the Software without
12 // restriction, including without limitation the rights to use,
13 // copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following
16 // conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 // OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 #import <FBSnapshotTestCase/UIImage+Compare.h>
32
33 // This makes debugging much more fun
34 typedef union {
35 uint32_t raw;
36 unsigned char bytes[4];
37 struct {
38 char red;
39 char green;
40 char blue;
41 char alpha;
42 } __attribute__ ((packed)) pixels;
43 } FBComparePixel;
44
45 @implementation UIImage (Compare)
46
47 - (BOOL)fb_compareWithImage:(UIImage *)image tolerance:(CGFloat)tolerance
48 {
49 NSAssert(CGSizeEqualToSize(self.size, image.size), @"Images must be same size.");
50
51 CGSize referenceImageSize = CGSizeMake(CGImageGetWidth(self.CGImage), CGImageGetHeight(self.CGImage));
52 CGSize imageSize = CGSizeMake(CGImageGetWidth(image.CGImage), CGImageGetHeight(image.CGImage));
53
54 // The images have the equal size, so we could use the smallest amount of bytes because of byte padding
55 size_t minBytesPerRow = MIN(CGImageGetBytesPerRow(self.CGImage), CGImageGetBytesPerRow(image.CGImage));
56 size_t referenceImageSizeBytes = referenceImageSize.height * minBytesPerRow;
57 void *referenceImagePixels = calloc(1, referenceImageSizeBytes);
58 void *imagePixels = calloc(1, referenceImageSizeBytes);
59
60 if (!referenceImagePixels || !imagePixels) {
61 free(referenceImagePixels);
62 free(imagePixels);
63 return NO;
64 }
65
66 CGContextRef referenceImageContext = CGBitmapContextCreate(referenceImagePixels,
67 referenceImageSize.width,
68 referenceImageSize.height,
69 CGImageGetBitsPerComponent(self.CGImage),
70 minBytesPerRow,
71 CGImageGetColorSpace(self.CGImage),
72 (CGBitmapInfo)kCGImageAlphaPremultipliedLast
73 );
74 CGContextRef imageContext = CGBitmapContextCreate(imagePixels,
75 imageSize.width,
76 imageSize.height,
77 CGImageGetBitsPerComponent(image.CGImage),
78 minBytesPerRow,
79 CGImageGetColorSpace(image.CGImage),
80 (CGBitmapInfo)kCGImageAlphaPremultipliedLast
81 );
82
83 if (!referenceImageContext || !imageContext) {
84 CGContextRelease(referenceImageContext);
85 CGContextRelease(imageContext);
86 free(referenceImagePixels);
87 free(imagePixels);
88 return NO;
89 }
90
91 CGContextDrawImage(referenceImageContext, CGRectMake(0, 0, referenceImageSize.width, referenceImageSize.height), self.CGImage);
92 CGContextDrawImage(imageContext, CGRectMake(0, 0, imageSize.width, imageSize.height), image.CGImage);
93
94 CGContextRelease(referenceImageContext);
95 CGContextRelease(imageContext);
96
97 BOOL imageEqual = YES;
98
99 // Do a fast compare if we can
100 if (tolerance == 0) {
101 imageEqual = (memcmp(referenceImagePixels, imagePixels, referenceImageSizeBytes) == 0);
102 } else {
103 // Go through each pixel in turn and see if it is different
104 const NSInteger pixelCount = referenceImageSize.width * referenceImageSize.height;
105
106 FBComparePixel *p1 = referenceImagePixels;
107 FBComparePixel *p2 = imagePixels;
108
109 NSInteger numDiffPixels = 0;
110 for (int n = 0; n < pixelCount; ++n) {
111 // If this pixel is different, increment the pixel diff count and see
112 // if we have hit our limit.
113 if (p1->raw != p2->raw) {
114 numDiffPixels ++;
115
116 CGFloat percent = (CGFloat)numDiffPixels / pixelCount;
117 if (percent > tolerance) {
118 imageEqual = NO;
119 break;
120 }
121 }
122
123 p1++;
124 p2++;
125 }
126 }
127
128 free(referenceImagePixels);
129 free(imagePixels);
130
131 return imageEqual;
132 }
133
134 @end
1 //
2 // Created by Gabriel Handford on 3/1/09.
3 // Copyright 2009-2013. All rights reserved.
4 // Created by John Boiles on 10/20/11.
5 // Copyright (c) 2011. All rights reserved
6 // Modified by Felix Schulze on 2/11/13.
7 // Copyright 2013. All rights reserved.
8 //
9 // Permission is hereby granted, free of charge, to any person
10 // obtaining a copy of this software and associated documentation
11 // files (the "Software"), to deal in the Software without
12 // restriction, including without limitation the rights to use,
13 // copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following
16 // conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 // OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 #import <UIKit/UIKit.h>
32
33 @interface UIImage (Diff)
34
35 - (UIImage *)fb_diffWithImage:(UIImage *)image;
36
37 @end
1 //
2 // Created by Gabriel Handford on 3/1/09.
3 // Copyright 2009-2013. All rights reserved.
4 // Created by John Boiles on 10/20/11.
5 // Copyright (c) 2011. All rights reserved
6 // Modified by Felix Schulze on 2/11/13.
7 // Copyright 2013. All rights reserved.
8 //
9 // Permission is hereby granted, free of charge, to any person
10 // obtaining a copy of this software and associated documentation
11 // files (the "Software"), to deal in the Software without
12 // restriction, including without limitation the rights to use,
13 // copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following
16 // conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 // OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 #import <FBSnapshotTestCase/UIImage+Diff.h>
32
33 @implementation UIImage (Diff)
34
35 - (UIImage *)fb_diffWithImage:(UIImage *)image
36 {
37 if (!image) {
38 return nil;
39 }
40 CGSize imageSize = CGSizeMake(MAX(self.size.width, image.size.width), MAX(self.size.height, image.size.height));
41 UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
42 CGContextRef context = UIGraphicsGetCurrentContext();
43 [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
44 CGContextSetAlpha(context, 0.5);
45 CGContextBeginTransparencyLayer(context, NULL);
46 [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
47 CGContextSetBlendMode(context, kCGBlendModeDifference);
48 CGContextSetFillColorWithColor(context,[UIColor whiteColor].CGColor);
49 CGContextFillRect(context, CGRectMake(0, 0, self.size.width, self.size.height));
50 CGContextEndTransparencyLayer(context);
51 UIImage *returnImage = UIGraphicsGetImageFromCurrentImageContext();
52 UIGraphicsEndImageContext();
53 return returnImage;
54 }
55
56 @end
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #import <UIKit/UIKit.h>
12
13 @interface UIImage (Snapshot)
14
15 /// Uses renderInContext: to get a snapshot of the layer.
16 + (UIImage *)fb_imageForLayer:(CALayer *)layer;
17
18 /// Uses renderInContext: to get a snapshot of the view layer.
19 + (UIImage *)fb_imageForViewLayer:(UIView *)view;
20
21 /// Uses drawViewHierarchyInRect: to get a snapshot of the view and adds the view into a window if needed.
22 + (UIImage *)fb_imageForView:(UIView *)view;
23
24 @end
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #import <FBSnapshotTestCase/UIImage+Snapshot.h>
12 #import <FBSnapshotTestCase/UIApplication+StrictKeyWindow.h>
13
14 @implementation UIImage (Snapshot)
15
16 + (UIImage *)fb_imageForLayer:(CALayer *)layer
17 {
18 CGRect bounds = layer.bounds;
19 NSAssert1(CGRectGetWidth(bounds), @"Zero width for layer %@", layer);
20 NSAssert1(CGRectGetHeight(bounds), @"Zero height for layer %@", layer);
21
22 UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
23 CGContextRef context = UIGraphicsGetCurrentContext();
24 NSAssert1(context, @"Could not generate context for layer %@", layer);
25 CGContextSaveGState(context);
26 [layer layoutIfNeeded];
27 [layer renderInContext:context];
28 CGContextRestoreGState(context);
29
30 UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
31 UIGraphicsEndImageContext();
32 return snapshot;
33 }
34
35 + (UIImage *)fb_imageForViewLayer:(UIView *)view
36 {
37 [view layoutIfNeeded];
38 return [self fb_imageForLayer:view.layer];
39 }
40
41 + (UIImage *)fb_imageForView:(UIView *)view
42 {
43 CGRect bounds = view.bounds;
44 NSAssert1(CGRectGetWidth(bounds), @"Zero width for view %@", view);
45 NSAssert1(CGRectGetHeight(bounds), @"Zero height for view %@", view);
46
47 // If the input view is already a UIWindow, then just use that. Otherwise wrap in a window.
48 UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *)view : view.window;
49 BOOL removeFromSuperview = NO;
50 if (!window) {
51 window = [[UIApplication sharedApplication] fb_strictKeyWindow];
52 }
53
54 if (!view.window && view != window) {
55 [window addSubview:view];
56 removeFromSuperview = YES;
57 }
58
59 UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
60 [view layoutIfNeeded];
61 [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
62
63 UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
64 UIGraphicsEndImageContext();
65
66 if (removeFromSuperview) {
67 [view removeFromSuperview];
68 }
69
70 return snapshot;
71 }
72
73 @end
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #import <FBSnapshotTestCase/FBSnapshotTestCasePlatform.h>
12 #import <FBSnapshotTestCase/FBSnapshotTestController.h>
13
14 #import <QuartzCore/QuartzCore.h>
15
16 #import <UIKit/UIKit.h>
17
18 #import <XCTest/XCTest.h>
19
20 /*
21 There are three ways of setting reference image directories.
22
23 1. Set the preprocessor macro FB_REFERENCE_IMAGE_DIR to a double quoted
24 c-string with the path.
25 2. Set an environment variable named FB_REFERENCE_IMAGE_DIR with the path. This
26 takes precedence over the preprocessor macro to allow for run-time override.
27 3. Keep everything unset, which will cause the reference images to be looked up
28 inside the bundle holding the current test, in the
29 Resources/ReferenceImages_* directories.
30 */
31 #ifndef FB_REFERENCE_IMAGE_DIR
32 #define FB_REFERENCE_IMAGE_DIR ""
33 #endif
34
35 /**
36 Similar to our much-loved XCTAssert() macros. Use this to perform your test. No need to write an explanation, though.
37 @param view The view to snapshot
38 @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
39 @param suffixes An NSOrderedSet of strings for the different suffixes
40 @param tolerance The percentage of pixels that can differ and still count as an 'identical' view
41 */
42 #define FBSnapshotVerifyViewWithOptions(view__, identifier__, suffixes__, tolerance__) \
43 FBSnapshotVerifyViewOrLayerWithOptions(View, view__, identifier__, suffixes__, tolerance__)
44
45 #define FBSnapshotVerifyView(view__, identifier__) \
46 FBSnapshotVerifyViewWithOptions(view__, identifier__, FBSnapshotTestCaseDefaultSuffixes(), 0)
47
48
49 /**
50 Similar to our much-loved XCTAssert() macros. Use this to perform your test. No need to write an explanation, though.
51 @param layer The layer to snapshot
52 @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
53 @param suffixes An NSOrderedSet of strings for the different suffixes
54 @param tolerance The percentage of pixels that can differ and still count as an 'identical' layer
55 */
56 #define FBSnapshotVerifyLayerWithOptions(layer__, identifier__, suffixes__, tolerance__) \
57 FBSnapshotVerifyViewOrLayerWithOptions(Layer, layer__, identifier__, suffixes__, tolerance__)
58
59 #define FBSnapshotVerifyLayer(layer__, identifier__) \
60 FBSnapshotVerifyLayerWithOptions(layer__, identifier__, FBSnapshotTestCaseDefaultSuffixes(), 0)
61
62
63 #define FBSnapshotVerifyViewOrLayerWithOptions(what__, viewOrLayer__, identifier__, suffixes__, tolerance__) \
64 { \
65 NSString *errorDescription = [self snapshotVerifyViewOrLayer:viewOrLayer__ identifier:identifier__ suffixes:suffixes__ tolerance:tolerance__]; \
66 BOOL noErrors = (errorDescription == nil); \
67 XCTAssertTrue(noErrors, @"%@", errorDescription); \
68 }
69
70
71 /**
72 The base class of view snapshotting tests. If you have small UI component, it's often easier to configure it in a test
73 and compare an image of the view to a reference image that write lots of complex layout-code tests.
74
75 In order to flip the tests in your subclass to record the reference images set @c recordMode to @c YES.
76
77 @attention When recording, the reference image directory should be explicitly
78 set, otherwise the images may be written to somewhere inside the
79 simulator directory.
80
81 For example:
82 @code
83 - (void)setUp
84 {
85 [super setUp];
86 self.recordMode = YES;
87 }
88 @endcode
89 */
90 @interface FBSnapshotTestCase : XCTestCase
91
92 /**
93 When YES, the test macros will save reference images, rather than performing an actual test.
94 */
95 @property (readwrite, nonatomic, assign) BOOL recordMode;
96
97 /**
98 When @c YES appends the name of the device model and OS to the snapshot file name.
99 The default value is @c NO.
100 */
101 @property (readwrite, nonatomic, assign, getter=isDeviceAgnostic) BOOL deviceAgnostic;
102
103 /**
104 When YES, renders a snapshot of the complete view hierarchy as visible onscreen.
105 There are several things that do not work if renderInContext: is used.
106 - UIVisualEffect #70
107 - UIAppearance #91
108 - Size Classes #92
109
110 @attention If the view does't belong to a UIWindow, it will create one and add the view as a subview.
111 */
112 @property (readwrite, nonatomic, assign) BOOL usesDrawViewHierarchyInRect;
113
114 - (void)setUp NS_REQUIRES_SUPER;
115 - (void)tearDown NS_REQUIRES_SUPER;
116
117 /**
118 Performs the comparison or records a snapshot of the layer if recordMode is YES.
119 @param viewOrLayer The UIView or CALayer to snapshot
120 @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
121 @param suffixes An NSOrderedSet of strings for the different suffixes
122 @param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care
123 @returns nil if the comparison (or saving of the reference image) succeeded. Otherwise it contains an error description.
124 */
125 - (NSString *)snapshotVerifyViewOrLayer:(id)viewOrLayer
126 identifier:(NSString *)identifier
127 suffixes:(NSOrderedSet *)suffixes
128 tolerance:(CGFloat)tolerance;
129
130 /**
131 Performs the comparison or records a snapshot of the layer if recordMode is YES.
132 @param layer The Layer to snapshot
133 @param referenceImagesDirectory The directory in which reference images are stored.
134 @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
135 @param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care
136 @param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
137 @returns YES if the comparison (or saving of the reference image) succeeded.
138 */
139 - (BOOL)compareSnapshotOfLayer:(CALayer *)layer
140 referenceImagesDirectory:(NSString *)referenceImagesDirectory
141 identifier:(NSString *)identifier
142 tolerance:(CGFloat)tolerance
143 error:(NSError **)errorPtr;
144
145 /**
146 Performs the comparison or records a snapshot of the view if recordMode is YES.
147 @param view The view to snapshot
148 @param referenceImagesDirectory The directory in which reference images are stored.
149 @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
150 @param tolerance The percentage difference to still count as identical - 0 mean pixel perfect, 1 means I don't care
151 @param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
152 @returns YES if the comparison (or saving of the reference image) succeeded.
153 */
154 - (BOOL)compareSnapshotOfView:(UIView *)view
155 referenceImagesDirectory:(NSString *)referenceImagesDirectory
156 identifier:(NSString *)identifier
157 tolerance:(CGFloat)tolerance
158 error:(NSError **)errorPtr;
159
160 /**
161 Checks if reference image with identifier based name exists in the reference images directory.
162 @param referenceImagesDirectory The directory in which reference images are stored.
163 @param identifier An optional identifier, used if there are multiple snapshot tests in a given -test method.
164 @param errorPtr An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
165 @returns YES if reference image exists.
166 */
167 - (BOOL)referenceImageRecordedInDirectory:(NSString *)referenceImagesDirectory
168 identifier:(NSString *)identifier
169 error:(NSError **)errorPtr;
170
171 /**
172 Returns the reference image directory.
173
174 Helper function used to implement the assert macros.
175
176 @param dir directory to use if environment variable not specified. Ignored if null or empty.
177 */
178 - (NSString *)getReferenceImageDirectoryWithDefault:(NSString *)dir;
179
180 @end
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #import <FBSnapshotTestCase/FBSnapshotTestCase.h>
12 #import <FBSnapshotTestCase/FBSnapshotTestController.h>
13
14 @implementation FBSnapshotTestCase
15 {
16 FBSnapshotTestController *_snapshotController;
17 }
18
19 #pragma mark - Overrides
20
21 - (void)setUp
22 {
23 [super setUp];
24 _snapshotController = [[FBSnapshotTestController alloc] initWithTestName:NSStringFromClass([self class])];
25 }
26
27 - (void)tearDown
28 {
29 _snapshotController = nil;
30 [super tearDown];
31 }
32
33 - (BOOL)recordMode
34 {
35 return _snapshotController.recordMode;
36 }
37
38 - (void)setRecordMode:(BOOL)recordMode
39 {
40 NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
41 _snapshotController.recordMode = recordMode;
42 }
43
44 - (BOOL)isDeviceAgnostic
45 {
46 return _snapshotController.deviceAgnostic;
47 }
48
49 - (void)setDeviceAgnostic:(BOOL)deviceAgnostic
50 {
51 NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
52 _snapshotController.deviceAgnostic = deviceAgnostic;
53 }
54
55 - (BOOL)usesDrawViewHierarchyInRect
56 {
57 return _snapshotController.usesDrawViewHierarchyInRect;
58 }
59
60 - (void)setUsesDrawViewHierarchyInRect:(BOOL)usesDrawViewHierarchyInRect
61 {
62 NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
63 _snapshotController.usesDrawViewHierarchyInRect = usesDrawViewHierarchyInRect;
64 }
65
66 #pragma mark - Public API
67
68 - (NSString *)snapshotVerifyViewOrLayer:(id)viewOrLayer
69 identifier:(NSString *)identifier
70 suffixes:(NSOrderedSet *)suffixes
71 tolerance:(CGFloat)tolerance
72 {
73 if (nil == viewOrLayer) {
74 return @"Object to be snapshotted must not be nil";
75 }
76 NSString *referenceImageDirectory = [self getReferenceImageDirectoryWithDefault:(@ FB_REFERENCE_IMAGE_DIR)];
77 if (referenceImageDirectory == nil) {
78 return @"Missing value for referenceImagesDirectory - Set FB_REFERENCE_IMAGE_DIR as Environment variable in your scheme.";
79 }
80 if (suffixes.count == 0) {
81 return [NSString stringWithFormat:@"Suffixes set cannot be empty %@", suffixes];
82 }
83
84 BOOL testSuccess = NO;
85 NSError *error = nil;
86 NSMutableArray *errors = [NSMutableArray array];
87
88 if (self.recordMode) {
89 NSString *referenceImagesDirectory = [NSString stringWithFormat:@"%@%@", referenceImageDirectory, suffixes.firstObject];
90 BOOL referenceImageSaved = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:(identifier) tolerance:tolerance error:&error];
91 if (!referenceImageSaved) {
92 [errors addObject:error];
93 }
94 } else {
95 for (NSString *suffix in suffixes) {
96 NSString *referenceImagesDirectory = [NSString stringWithFormat:@"%@%@", referenceImageDirectory, suffix];
97 BOOL referenceImageAvailable = [self referenceImageRecordedInDirectory:referenceImagesDirectory identifier:(identifier) error:&error];
98
99 if (referenceImageAvailable) {
100 BOOL comparisonSuccess = [self _compareSnapshotOfViewOrLayer:viewOrLayer referenceImagesDirectory:referenceImagesDirectory identifier:identifier tolerance:tolerance error:&error];
101 [errors removeAllObjects];
102 if (comparisonSuccess) {
103 testSuccess = YES;
104 break;
105 } else {
106 [errors addObject:error];
107 }
108 } else {
109 [errors addObject:error];
110 }
111 }
112 }
113
114 if (!testSuccess) {
115 return [NSString stringWithFormat:@"Snapshot comparison failed: %@", errors.firstObject];
116 }
117 if (self.recordMode) {
118 return @"Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!";
119 }
120
121 return nil;
122 }
123
124 - (BOOL)compareSnapshotOfLayer:(CALayer *)layer
125 referenceImagesDirectory:(NSString *)referenceImagesDirectory
126 identifier:(NSString *)identifier
127 tolerance:(CGFloat)tolerance
128 error:(NSError **)errorPtr
129 {
130 return [self _compareSnapshotOfViewOrLayer:layer
131 referenceImagesDirectory:referenceImagesDirectory
132 identifier:identifier
133 tolerance:tolerance
134 error:errorPtr];
135 }
136
137 - (BOOL)compareSnapshotOfView:(UIView *)view
138 referenceImagesDirectory:(NSString *)referenceImagesDirectory
139 identifier:(NSString *)identifier
140 tolerance:(CGFloat)tolerance
141 error:(NSError **)errorPtr
142 {
143 return [self _compareSnapshotOfViewOrLayer:view
144 referenceImagesDirectory:referenceImagesDirectory
145 identifier:identifier
146 tolerance:tolerance
147 error:errorPtr];
148 }
149
150 - (BOOL)referenceImageRecordedInDirectory:(NSString *)referenceImagesDirectory
151 identifier:(NSString *)identifier
152 error:(NSError **)errorPtr
153 {
154 NSAssert1(_snapshotController, @"%s cannot be called before [super setUp]", __FUNCTION__);
155 _snapshotController.referenceImagesDirectory = referenceImagesDirectory;
156 UIImage *referenceImage = [_snapshotController referenceImageForSelector:self.invocation.selector
157 identifier:identifier
158 error:errorPtr];
159
160 return (referenceImage != nil);
161 }
162
163 - (NSString *)getReferenceImageDirectoryWithDefault:(NSString *)dir
164 {
165 NSString *envReferenceImageDirectory = [NSProcessInfo processInfo].environment[@"FB_REFERENCE_IMAGE_DIR"];
166 if (envReferenceImageDirectory) {
167 return envReferenceImageDirectory;
168 }
169 if (dir && dir.length > 0) {
170 return dir;
171 }
172 return [[NSBundle bundleForClass:self.class].resourcePath stringByAppendingPathComponent:@"ReferenceImages"];
173 }
174
175
176 #pragma mark - Private API
177
178 - (BOOL)_compareSnapshotOfViewOrLayer:(id)viewOrLayer
179 referenceImagesDirectory:(NSString *)referenceImagesDirectory
180 identifier:(NSString *)identifier
181 tolerance:(CGFloat)tolerance
182 error:(NSError **)errorPtr
183 {
184 _snapshotController.referenceImagesDirectory = referenceImagesDirectory;
185 return [_snapshotController compareSnapshotOfViewOrLayer:viewOrLayer
186 selector:self.invocation.selector
187 identifier:identifier
188 tolerance:tolerance
189 error:errorPtr];
190 }
191
192 @end
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #import <Foundation/Foundation.h>
12
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16
17 /**
18 Returns a Boolean value that indicates whether the snapshot test is running in 64Bit.
19 This method is a convenience for creating the suffixes set based on the architecture
20 that the test is running.
21
22 @returns @c YES if the test is running in 64bit, otherwise @c NO.
23 */
24 BOOL FBSnapshotTestCaseIs64Bit(void);
25
26 /**
27 Returns a default set of strings that is used to append a suffix based on the architectures.
28 @warning Do not modify this function, you can create your own and use it with @c FBSnapshotVerifyViewWithOptions()
29
30 @returns An @c NSOrderedSet object containing strings that are appended to the reference images directory.
31 */
32 NSOrderedSet *FBSnapshotTestCaseDefaultSuffixes(void);
33
34 /**
35 Returns a fully «normalized» file name.
36 Strips punctuation and spaces and replaces them with @c _. Also appends the device model, running OS and screen size to the file name.
37
38 @returns An @c NSString object containing the passed @c fileName with the device model, OS and screen size appended at the end.
39 */
40 NSString *FBDeviceAgnosticNormalizedFileName(NSString *fileName);
41
42 #ifdef __cplusplus
43 }
44 #endif
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #import <FBSnapshotTestCase/FBSnapshotTestCasePlatform.h>
12 #import <FBSnapshotTestCase/UIApplication+StrictKeyWindow.h>
13 #import <UIKit/UIKit.h>
14
15 BOOL FBSnapshotTestCaseIs64Bit(void)
16 {
17 #if __LP64__
18 return YES;
19 #else
20 return NO;
21 #endif
22 }
23
24 NSOrderedSet *FBSnapshotTestCaseDefaultSuffixes(void)
25 {
26 NSMutableOrderedSet *suffixesSet = [[NSMutableOrderedSet alloc] init];
27 [suffixesSet addObject:@"_32"];
28 [suffixesSet addObject:@"_64"];
29 if (FBSnapshotTestCaseIs64Bit()) {
30 return [suffixesSet reversedOrderedSet];
31 }
32 return [suffixesSet copy];
33 }
34
35 NSString *FBDeviceAgnosticNormalizedFileName(NSString *fileName)
36 {
37 UIDevice *device = [UIDevice currentDevice];
38 UIWindow *keyWindow = [[UIApplication sharedApplication] fb_strictKeyWindow];
39 CGSize screenSize = keyWindow.bounds.size;
40 NSString *os = device.systemVersion;
41
42 fileName = [NSString stringWithFormat:@"%@_%@%@_%.0fx%.0f", fileName, device.model, os, screenSize.width, screenSize.height];
43
44 NSMutableCharacterSet *invalidCharacters = [NSMutableCharacterSet new];
45 [invalidCharacters formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
46 [invalidCharacters formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
47 NSArray *validComponents = [fileName componentsSeparatedByCharactersInSet:invalidCharacters];
48 fileName = [validComponents componentsJoinedByString:@"_"];
49
50 return fileName;
51 }
...\ No newline at end of file ...\ No newline at end of file
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #import <Foundation/Foundation.h>
12 #import <UIKit/UIKit.h>
13
14 typedef NS_ENUM(NSInteger, FBSnapshotTestControllerErrorCode) {
15 FBSnapshotTestControllerErrorCodeUnknown,
16 FBSnapshotTestControllerErrorCodeNeedsRecord,
17 FBSnapshotTestControllerErrorCodePNGCreationFailed,
18 FBSnapshotTestControllerErrorCodeImagesDifferentSizes,
19 FBSnapshotTestControllerErrorCodeImagesDifferent,
20 };
21 /**
22 Errors returned by the methods of FBSnapshotTestController use this domain.
23 */
24 extern NSString *const FBSnapshotTestControllerErrorDomain;
25
26 /**
27 Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
28 */
29 extern NSString *const FBReferenceImageFilePathKey;
30
31 /**
32 Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
33 */
34 extern NSString *const FBReferenceImageKey;
35
36 /**
37 Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
38 */
39 extern NSString *const FBCapturedImageKey;
40
41 /**
42 Errors returned by the methods of FBSnapshotTestController sometimes contain this key in the `userInfo` dictionary.
43 */
44 extern NSString *const FBDiffedImageKey;
45
46 /**
47 Provides the heavy-lifting for FBSnapshotTestCase. It loads and saves images, along with performing the actual pixel-
48 by-pixel comparison of images.
49 Instances are initialized with the test class, and directories to read and write to.
50 */
51 @interface FBSnapshotTestController : NSObject
52
53 /**
54 Record snapshots.
55 */
56 @property (readwrite, nonatomic, assign) BOOL recordMode;
57
58 /**
59 When @c YES appends the name of the device model and OS to the snapshot file name.
60 The default value is @c NO.
61 */
62 @property (readwrite, nonatomic, assign, getter=isDeviceAgnostic) BOOL deviceAgnostic;
63
64 /**
65 Uses drawViewHierarchyInRect:afterScreenUpdates: to draw the image instead of renderInContext:
66 */
67 @property (readwrite, nonatomic, assign) BOOL usesDrawViewHierarchyInRect;
68
69 /**
70 The directory in which referfence images are stored.
71 */
72 @property (readwrite, nonatomic, copy) NSString *referenceImagesDirectory;
73
74 /**
75 @param testClass The subclass of FBSnapshotTestCase that is using this controller.
76 @returns An instance of FBSnapshotTestController.
77 */
78 - (instancetype)initWithTestClass:(Class)testClass;
79
80 /**
81 Designated initializer.
82 @param testName The name of the tests.
83 @returns An instance of FBSnapshotTestController.
84 */
85 - (instancetype)initWithTestName:(NSString *)testName;
86
87 /**
88 Performs the comparison of the layer.
89 @param layer The Layer to snapshot.
90 @param selector The test method being run.
91 @param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
92 @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
93 @returns YES if the comparison (or saving of the reference image) succeeded.
94 */
95 - (BOOL)compareSnapshotOfLayer:(CALayer *)layer
96 selector:(SEL)selector
97 identifier:(NSString *)identifier
98 error:(NSError **)errorPtr;
99
100 /**
101 Performs the comparison of the view.
102 @param view The view to snapshot.
103 @param selector The test method being run.
104 @param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
105 @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
106 @returns YES if the comparison (or saving of the reference image) succeeded.
107 */
108 - (BOOL)compareSnapshotOfView:(UIView *)view
109 selector:(SEL)selector
110 identifier:(NSString *)identifier
111 error:(NSError **)errorPtr;
112
113 /**
114 Performs the comparison of a view or layer.
115 @param view The view or layer to snapshot.
116 @param selector The test method being run.
117 @param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
118 @param tolerance The percentage of pixels that can differ and still be considered 'identical'
119 @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
120 @returns YES if the comparison (or saving of the reference image) succeeded.
121 */
122 - (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
123 selector:(SEL)selector
124 identifier:(NSString *)identifier
125 tolerance:(CGFloat)tolerance
126 error:(NSError **)errorPtr;
127
128 /**
129 Loads a reference image.
130 @param selector The test method being run.
131 @param identifier The optional identifier, used when multiple images are tested in a single -test method.
132 @param errorPtr An error, if this methods returns nil, the error will be something useful.
133 @returns An image.
134 */
135 - (UIImage *)referenceImageForSelector:(SEL)selector
136 identifier:(NSString *)identifier
137 error:(NSError **)errorPtr;
138
139 /**
140 Performs a pixel-by-pixel comparison of the two images with an allowable margin of error.
141 @param referenceImage The reference (correct) image.
142 @param image The image to test against the reference.
143 @param tolerance The percentage of pixels that can differ and still be considered 'identical'
144 @param errorPtr An error that indicates why the comparison failed if it does.
145 @returns YES if the comparison succeeded and the images are the same(ish).
146 */
147 - (BOOL)compareReferenceImage:(UIImage *)referenceImage
148 toImage:(UIImage *)image
149 tolerance:(CGFloat)tolerance
150 error:(NSError **)errorPtr;
151
152 /**
153 Saves the reference image and the test image to `failedOutputDirectory`.
154 @param referenceImage The reference (correct) image.
155 @param testImage The image to test against the reference.
156 @param selector The test method being run.
157 @param identifier The optional identifier, used when multiple images are tested in a single -test method.
158 @param errorPtr An error that indicates why the comparison failed if it does.
159 @returns YES if the save succeeded.
160 */
161 - (BOOL)saveFailedReferenceImage:(UIImage *)referenceImage
162 testImage:(UIImage *)testImage
163 selector:(SEL)selector
164 identifier:(NSString *)identifier
165 error:(NSError **)errorPtr;
166 @end
1 /*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11 #if swift(>=3)
12 public extension FBSnapshotTestCase {
13 public func FBSnapshotVerifyView(_ view: UIView, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
14 FBSnapshotVerifyViewOrLayer(view, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
15 }
16
17 public func FBSnapshotVerifyLayer(_ layer: CALayer, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
18 FBSnapshotVerifyViewOrLayer(layer, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
19 }
20
21 private func FBSnapshotVerifyViewOrLayer(_ viewOrLayer: AnyObject, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
22 let envReferenceImageDirectory = self.getReferenceImageDirectory(withDefault: FB_REFERENCE_IMAGE_DIR)
23 var error: NSError?
24 var comparisonSuccess = false
25
26 if let envReferenceImageDirectory = envReferenceImageDirectory {
27 for suffix in suffixes {
28 let referenceImagesDirectory = "\(envReferenceImageDirectory)\(suffix)"
29 if viewOrLayer.isKind(of: UIView.self) {
30 do {
31 try compareSnapshot(of: viewOrLayer as! UIView, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
32 comparisonSuccess = true
33 } catch let error1 as NSError {
34 error = error1
35 comparisonSuccess = false
36 }
37 } else if viewOrLayer.isKind(of: CALayer.self) {
38 do {
39 try compareSnapshot(of: viewOrLayer as! CALayer, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
40 comparisonSuccess = true
41 } catch let error1 as NSError {
42 error = error1
43 comparisonSuccess = false
44 }
45 } else {
46 assertionFailure("Only UIView and CALayer classes can be snapshotted")
47 }
48
49 assert(recordMode == false, message: "Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!", file: file, line: line)
50
51 if comparisonSuccess || recordMode {
52 break
53 }
54
55 assert(comparisonSuccess, message: "Snapshot comparison failed: \(error)", file: file, line: line)
56 }
57 } else {
58 XCTFail("Missing value for referenceImagesDirectory - Set FB_REFERENCE_IMAGE_DIR as Environment variable in your scheme.")
59 }
60 }
61
62 func assert(_ assertion: Bool, message: String, file: StaticString, line: UInt) {
63 if !assertion {
64 XCTFail(message, file: file, line: line)
65 }
66 }
67 }
68 #else
69 public extension FBSnapshotTestCase {
70 public func FBSnapshotVerifyView(view: UIView, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
71 FBSnapshotVerifyViewOrLayer(view, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
72 }
73
74 public func FBSnapshotVerifyLayer(layer: CALayer, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
75 FBSnapshotVerifyViewOrLayer(layer, identifier: identifier, suffixes: suffixes, tolerance: tolerance, file: file, line: line)
76 }
77
78 private func FBSnapshotVerifyViewOrLayer(viewOrLayer: AnyObject, identifier: String = "", suffixes: NSOrderedSet = FBSnapshotTestCaseDefaultSuffixes(), tolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) {
79 let envReferenceImageDirectory = self.getReferenceImageDirectoryWithDefault(FB_REFERENCE_IMAGE_DIR)
80 var error: NSError?
81 var comparisonSuccess = false
82
83 if let envReferenceImageDirectory = envReferenceImageDirectory {
84 for suffix in suffixes {
85 let referenceImagesDirectory = "\(envReferenceImageDirectory)\(suffix)"
86 if viewOrLayer.isKindOfClass(UIView) {
87 do {
88 try compareSnapshotOfView(viewOrLayer as! UIView, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
89 comparisonSuccess = true
90 } catch let error1 as NSError {
91 error = error1
92 comparisonSuccess = false
93 }
94 } else if viewOrLayer.isKindOfClass(CALayer) {
95 do {
96 try compareSnapshotOfLayer(viewOrLayer as! CALayer, referenceImagesDirectory: referenceImagesDirectory, identifier: identifier, tolerance: tolerance)
97 comparisonSuccess = true
98 } catch let error1 as NSError {
99 error = error1
100 comparisonSuccess = false
101 }
102 } else {
103 assertionFailure("Only UIView and CALayer classes can be snapshotted")
104 }
105
106 assert(recordMode == false, message: "Test ran in record mode. Reference image is now saved. Disable record mode to perform an actual snapshot comparison!", file: file, line: line)
107
108 if comparisonSuccess || recordMode {
109 break
110 }
111
112 assert(comparisonSuccess, message: "Snapshot comparison failed: \(error)", file: file, line: line)
113 }
114 } else {
115 XCTFail("Missing value for referenceImagesDirectory - Set FB_REFERENCE_IMAGE_DIR as Environment variable in your scheme.")
116 }
117 }
118
119 func assert(assertion: Bool, message: String, file: StaticString, line: UInt) {
120 if !assertion {
121 XCTFail(message, file: file, line: line)
122 }
123 }
124 }
125 #endif
1 BSD License
2
3 For the FBSnapshotTestCase software
4
5 Copyright (c) 2013, Facebook, Inc.
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10
11 * Redistributions of source code must retain the above copyright notice,
12 this list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above copyright notice,
14 this list of conditions and the following disclaimer in the documentation
15 and/or other materials provided with the distribution.
16 * Neither the name Facebook nor the names of its contributors may be used to
17 endorse or promote products derived from this software without specific
18 prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1 FBSnapshotTestCase
2 ======================
3
4 [![Build Status](https://travis-ci.org/facebook/ios-snapshot-test-case.svg)](https://travis-ci.org/facebook/ios-snapshot-test-case) [![Cocoa Pod Version](https://cocoapod-badges.herokuapp.com/v/FBSnapshotTestCase/badge.svg)](http://cocoadocs.org/docsets/FBSnapshotTestCase/)
5
6 What it does
7 ------------
8
9 A "snapshot test case" takes a configured `UIView` or `CALayer` and uses the
10 `renderInContext:` method to get an image snapshot of its contents. It
11 compares this snapshot to a "reference image" stored in your source code
12 repository and fails the test if the two images don't match.
13
14 Why?
15 ----
16
17 At Facebook we write a lot of UI code. As you might imagine, each type of
18 feed story is rendered using a subclass of `UIView`. There are a lot of edge
19 cases that we want to handle correctly:
20
21 - What if there is more text than can fit in the space available?
22 - What if an image doesn't match the size of an image view?
23 - What should the highlighted state look like?
24
25 It's straightforward to test logic code, but less obvious how you should test
26 views. You can do a lot of rectangle asserts, but these are hard to understand
27 or visualize. Looking at an image diff shows you exactly what changed and how
28 it will look to users.
29
30 We developed `FBSnapshotTestCase` to make snapshot tests easy.
31
32 Installation with CocoaPods
33 ---------------------------
34
35 1. Add the following lines to your Podfile:
36
37 ```
38 target "Tests" do
39 pod 'FBSnapshotTestCase'
40 end
41 ```
42
43 If you support iOS 7 use `FBSnapshotTestCase/Core` instead, which doesn't contain Swift support.
44
45 Replace "Tests" with the name of your test project.
46
47 2. There are [three ways](https://github.com/facebook/ios-snapshot-test-case/blob/master/FBSnapshotTestCase/FBSnapshotTestCase.h#L19-L29) of setting reference image directories, the recommended one is to define `FB_REFERENCE_IMAGE_DIR` in your scheme. This should point to the directory where you want reference images to be stored. At Facebook, we normally use this:
48
49 |Name|Value|
50 |:---|:----|
51 |`FB_REFERENCE_IMAGE_DIR`|`$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages`|
52
53
54 ![](FBSnapshotTestCaseDemo/Scheme_FB_REFERENCE_IMAGE_DIR.png)
55
56 Creating a snapshot test
57 ------------------------
58
59 1. Subclass `FBSnapshotTestCase` instead of `XCTestCase`.
60 2. From within your test, use `FBSnapshotVerifyView`.
61 3. Run the test once with `self.recordMode = YES;` in the test's `-setUp`
62 method. (This creates the reference images on disk.)
63 4. Remove the line enabling record mode and run the test.
64
65 Features
66 --------
67
68 - Automatically names reference images on disk according to test class and
69 selector.
70 - Prints a descriptive error message to the console on failure. (Bonus:
71 failure message includes a one-line command to see an image diff if
72 you have [Kaleidoscope](http://www.kaleidoscopeapp.com) installed.)
73 - Supply an optional "identifier" if you want to perform multiple snapshots
74 in a single test method.
75 - Support for `CALayer` via `FBSnapshotVerifyLayer`.
76 - `usesDrawViewHierarchyInRect` to handle cases like `UIVisualEffect`, `UIAppearance` and Size Classes.
77 - `isDeviceAgnostic` to allow appending the device model (`iPhone`, `iPad`, `iPod Touch`, etc), OS version and screen size to the images (allowing to have multiple tests for the same «snapshot» for different `OS`s and devices).
78
79 Notes
80 -----
81
82 Your unit test must be an "application test", not a "logic test." (That is, it
83 must be run within the Simulator so that it has access to UIKit.) In Xcode 5
84 and later new projects only offer application tests, but older projects will
85 have separate targets for the two types.
86
87 Authors
88 -------
89
90 `FBSnapshotTestCase` was written at Facebook by
91 [Jonathan Dann](https://facebook.com/j.p.dann) with significant contributions by
92 [Todd Krabach](https://facebook.com/toddkrabach).
93
94 License
95 -------
96
97 `FBSnapshotTestCase` is BSD-licensed. See `LICENSE`.
1 {
2 "name": "JCategoryKit",
3 "version": "1.0.0",
4 "summary": "A short description of JCategoryKit.",
5 "description": "TODO: Add long description of the pod here.",
6 "homepage": "https://github.com/weixq/JCategoryKit",
7 "license": {
8 "type": "MIT",
9 "file": "LICENSE"
10 },
11 "authors": {
12 "weixq": "weixiaoqiang@situdata.com"
13 },
14 "source": {
15 "git": "http://gitlab.situdata.com/weixiaoqiang/JCategoryKit.git",
16 "tag": "1.0.0"
17 },
18 "platforms": {
19 "ios": "9.0"
20 },
21 "source_files": "JCategoryKit/Classes/**/*"
22 }
1 PODS:
2 - FBSnapshotTestCase (2.1.4):
3 - FBSnapshotTestCase/SwiftSupport (= 2.1.4)
4 - FBSnapshotTestCase/Core (2.1.4)
5 - FBSnapshotTestCase/SwiftSupport (2.1.4):
6 - FBSnapshotTestCase/Core
7 - JCategoryKit (1.0.0)
8
9 DEPENDENCIES:
10 - FBSnapshotTestCase
11 - JCategoryKit (from `../`)
12
13 SPEC REPOS:
14 trunk:
15 - FBSnapshotTestCase
16
17 EXTERNAL SOURCES:
18 JCategoryKit:
19 :path: "../"
20
21 SPEC CHECKSUMS:
22 FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
23 JCategoryKit: 1ee089cd5593b2515c06f8b99e9eb02fdac4eecd
24
25 PODFILE CHECKSUM: 7301f47448ac58a307221e0e73e2a910d76a70ab
26
27 COCOAPODS: 1.11.2
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>CFBundleDevelopmentRegion</key>
6 <string>en</string>
7 <key>CFBundleExecutable</key>
8 <string>${EXECUTABLE_NAME}</string>
9 <key>CFBundleIdentifier</key>
10 <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
11 <key>CFBundleInfoDictionaryVersion</key>
12 <string>6.0</string>
13 <key>CFBundleName</key>
14 <string>${PRODUCT_NAME}</string>
15 <key>CFBundlePackageType</key>
16 <string>FMWK</string>
17 <key>CFBundleShortVersionString</key>
18 <string>2.1.4</string>
19 <key>CFBundleSignature</key>
20 <string>????</string>
21 <key>CFBundleVersion</key>
22 <string>${CURRENT_PROJECT_VERSION}</string>
23 <key>NSPrincipalClass</key>
24 <string></string>
25 </dict>
26 </plist>
1 #import <Foundation/Foundation.h>
2 @interface PodsDummy_FBSnapshotTestCase : NSObject
3 @end
4 @implementation PodsDummy_FBSnapshotTestCase
5 @end
1 #ifdef __OBJC__
2 #import <UIKit/UIKit.h>
3 #else
4 #ifndef FOUNDATION_EXPORT
5 #if defined(__cplusplus)
6 #define FOUNDATION_EXPORT extern "C"
7 #else
8 #define FOUNDATION_EXPORT extern
9 #endif
10 #endif
11 #endif
12
1 #ifdef __OBJC__
2 #import <UIKit/UIKit.h>
3 #else
4 #ifndef FOUNDATION_EXPORT
5 #if defined(__cplusplus)
6 #define FOUNDATION_EXPORT extern "C"
7 #else
8 #define FOUNDATION_EXPORT extern
9 #endif
10 #endif
11 #endif
12
13 #import "FBSnapshotTestCase.h"
14 #import "FBSnapshotTestCasePlatform.h"
15 #import "FBSnapshotTestController.h"
16
17 FOUNDATION_EXPORT double FBSnapshotTestCaseVersionNumber;
18 FOUNDATION_EXPORT const unsigned char FBSnapshotTestCaseVersionString[];
19
1 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase
3 ENABLE_BITCODE = NO
4 FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"
5 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
6 LIBRARY_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
7 OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "QuartzCore" -framework "UIKit" -framework "XCTest"
8 OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
9 PODS_BUILD_DIR = ${BUILD_DIR}
10 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
11 PODS_ROOT = ${SRCROOT}
12 PODS_TARGET_SRCROOT = ${PODS_ROOT}/FBSnapshotTestCase
13 PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
14 PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
15 SKIP_INSTALL = YES
16 SWIFT_INCLUDE_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib"
17 SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"
18 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
1 framework module FBSnapshotTestCase {
2 umbrella header "FBSnapshotTestCase-umbrella.h"
3
4 export *
5 module * { export * }
6 }
1 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase
3 ENABLE_BITCODE = NO
4 FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"
5 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
6 LIBRARY_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib" "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
7 OTHER_LDFLAGS = $(inherited) -framework "Foundation" -framework "QuartzCore" -framework "UIKit" -framework "XCTest"
8 OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
9 PODS_BUILD_DIR = ${BUILD_DIR}
10 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
11 PODS_ROOT = ${SRCROOT}
12 PODS_TARGET_SRCROOT = ${PODS_ROOT}/FBSnapshotTestCase
13 PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
14 PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
15 SKIP_INSTALL = YES
16 SWIFT_INCLUDE_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/usr/lib"
17 SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"
18 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>CFBundleDevelopmentRegion</key>
6 <string>en</string>
7 <key>CFBundleExecutable</key>
8 <string>${EXECUTABLE_NAME}</string>
9 <key>CFBundleIdentifier</key>
10 <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
11 <key>CFBundleInfoDictionaryVersion</key>
12 <string>6.0</string>
13 <key>CFBundleName</key>
14 <string>${PRODUCT_NAME}</string>
15 <key>CFBundlePackageType</key>
16 <string>FMWK</string>
17 <key>CFBundleShortVersionString</key>
18 <string>1.0.0</string>
19 <key>CFBundleSignature</key>
20 <string>????</string>
21 <key>CFBundleVersion</key>
22 <string>${CURRENT_PROJECT_VERSION}</string>
23 <key>NSPrincipalClass</key>
24 <string></string>
25 </dict>
26 </plist>
1 #import <Foundation/Foundation.h>
2 @interface PodsDummy_JCategoryKit : NSObject
3 @end
4 @implementation PodsDummy_JCategoryKit
5 @end
1 #ifdef __OBJC__
2 #import <UIKit/UIKit.h>
3 #else
4 #ifndef FOUNDATION_EXPORT
5 #if defined(__cplusplus)
6 #define FOUNDATION_EXPORT extern "C"
7 #else
8 #define FOUNDATION_EXPORT extern
9 #endif
10 #endif
11 #endif
12
1 #ifdef __OBJC__
2 #import <UIKit/UIKit.h>
3 #else
4 #ifndef FOUNDATION_EXPORT
5 #if defined(__cplusplus)
6 #define FOUNDATION_EXPORT extern "C"
7 #else
8 #define FOUNDATION_EXPORT extern
9 #endif
10 #endif
11 #endif
12
13 #import "Person.h"
14
15 FOUNDATION_EXPORT double JCategoryKitVersionNumber;
16 FOUNDATION_EXPORT const unsigned char JCategoryKitVersionString[];
17
1 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit
3 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 PODS_BUILD_DIR = ${BUILD_DIR}
5 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
6 PODS_ROOT = ${SRCROOT}
7 PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
8 PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
9 PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 SKIP_INSTALL = YES
11 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
1 framework module JCategoryKit {
2 umbrella header "JCategoryKit-umbrella.h"
3
4 export *
5 module * { export * }
6 }
1 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit
3 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 PODS_BUILD_DIR = ${BUILD_DIR}
5 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
6 PODS_ROOT = ${SRCROOT}
7 PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
8 PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
9 PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 SKIP_INSTALL = YES
11 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>CFBundleDevelopmentRegion</key>
6 <string>en</string>
7 <key>CFBundleExecutable</key>
8 <string>${EXECUTABLE_NAME}</string>
9 <key>CFBundleIdentifier</key>
10 <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
11 <key>CFBundleInfoDictionaryVersion</key>
12 <string>6.0</string>
13 <key>CFBundleName</key>
14 <string>${PRODUCT_NAME}</string>
15 <key>CFBundlePackageType</key>
16 <string>FMWK</string>
17 <key>CFBundleShortVersionString</key>
18 <string>1.0.0</string>
19 <key>CFBundleSignature</key>
20 <string>????</string>
21 <key>CFBundleVersion</key>
22 <string>${CURRENT_PROJECT_VERSION}</string>
23 <key>NSPrincipalClass</key>
24 <string></string>
25 </dict>
26 </plist>
1 # Acknowledgements
2 This application makes use of the following third party libraries:
3
4 ## JCategoryKit
5
6 Copyright (c) 2021 weixq <weixiaoqiang@situdata.com>
7
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE SOFTWARE.
25
26 Generated by CocoaPods - https://cocoapods.org
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>PreferenceSpecifiers</key>
6 <array>
7 <dict>
8 <key>FooterText</key>
9 <string>This application makes use of the following third party libraries:</string>
10 <key>Title</key>
11 <string>Acknowledgements</string>
12 <key>Type</key>
13 <string>PSGroupSpecifier</string>
14 </dict>
15 <dict>
16 <key>FooterText</key>
17 <string>Copyright (c) 2021 weixq &lt;weixiaoqiang@situdata.com&gt;
18
19 Permission is hereby granted, free of charge, to any person obtaining a copy
20 of this software and associated documentation files (the "Software"), to deal
21 in the Software without restriction, including without limitation the rights
22 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 copies of the Software, and to permit persons to whom the Software is
24 furnished to do so, subject to the following conditions:
25
26 The above copyright notice and this permission notice shall be included in
27 all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 THE SOFTWARE.
36 </string>
37 <key>License</key>
38 <string>MIT</string>
39 <key>Title</key>
40 <string>JCategoryKit</string>
41 <key>Type</key>
42 <string>PSGroupSpecifier</string>
43 </dict>
44 <dict>
45 <key>FooterText</key>
46 <string>Generated by CocoaPods - https://cocoapods.org</string>
47 <key>Title</key>
48 <string></string>
49 <key>Type</key>
50 <string>PSGroupSpecifier</string>
51 </dict>
52 </array>
53 <key>StringsTable</key>
54 <string>Acknowledgements</string>
55 <key>Title</key>
56 <string>Acknowledgements</string>
57 </dict>
58 </plist>
1 #import <Foundation/Foundation.h>
2 @interface PodsDummy_Pods_JCategoryKit_Example : NSObject
3 @end
4 @implementation PodsDummy_Pods_JCategoryKit_Example
5 @end
1 #!/bin/sh
2 set -e
3 set -u
4 set -o pipefail
5
6 function on_error {
7 echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 }
9 trap 'on_error $LINENO' ERR
10
11 if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 # frameworks to, so exit 0 (signalling the script phase was successful).
14 exit 0
15 fi
16
17 echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19
20 COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 BCSYMBOLMAP_DIR="BCSymbolMaps"
23
24
25 # This protects against multiple targets copying the same framework dependency at the same time. The solution
26 # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
27 RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
28
29 # Copies and strips a vendored framework
30 install_framework()
31 {
32 if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
33 local source="${BUILT_PRODUCTS_DIR}/$1"
34 elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
35 local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
36 elif [ -r "$1" ]; then
37 local source="$1"
38 fi
39
40 local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
41
42 if [ -L "${source}" ]; then
43 echo "Symlinked..."
44 source="$(readlink "${source}")"
45 fi
46
47 if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
48 # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
49 find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
50 echo "Installing $f"
51 install_bcsymbolmap "$f" "$destination"
52 rm "$f"
53 done
54 rmdir "${source}/${BCSYMBOLMAP_DIR}"
55 fi
56
57 # Use filter instead of exclude so missing patterns don't throw errors.
58 echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
59 rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
60
61 local basename
62 basename="$(basename -s .framework "$1")"
63 binary="${destination}/${basename}.framework/${basename}"
64
65 if ! [ -r "$binary" ]; then
66 binary="${destination}/${basename}"
67 elif [ -L "${binary}" ]; then
68 echo "Destination binary is symlinked..."
69 dirname="$(dirname "${binary}")"
70 binary="${dirname}/$(readlink "${binary}")"
71 fi
72
73 # Strip invalid architectures so "fat" simulator / device frameworks work on device
74 if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
75 strip_invalid_archs "$binary"
76 fi
77
78 # Resign the code if required by the build settings to avoid unstable apps
79 code_sign_if_enabled "${destination}/$(basename "$1")"
80
81 # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
82 if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
83 local swift_runtime_libs
84 swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
85 for lib in $swift_runtime_libs; do
86 echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
87 rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
88 code_sign_if_enabled "${destination}/${lib}"
89 done
90 fi
91 }
92 # Copies and strips a vendored dSYM
93 install_dsym() {
94 local source="$1"
95 warn_missing_arch=${2:-true}
96 if [ -r "$source" ]; then
97 # Copy the dSYM into the targets temp dir.
98 echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
99 rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
100
101 local basename
102 basename="$(basename -s .dSYM "$source")"
103 binary_name="$(ls "$source/Contents/Resources/DWARF")"
104 binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
105
106 # Strip invalid architectures from the dSYM.
107 if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
108 strip_invalid_archs "$binary" "$warn_missing_arch"
109 fi
110 if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
111 # Move the stripped file into its final destination.
112 echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
113 rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
114 else
115 # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
116 mkdir -p "${DWARF_DSYM_FOLDER_PATH}"
117 touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
118 fi
119 fi
120 }
121
122 # Used as a return value for each invocation of `strip_invalid_archs` function.
123 STRIP_BINARY_RETVAL=0
124
125 # Strip invalid architectures
126 strip_invalid_archs() {
127 binary="$1"
128 warn_missing_arch=${2:-true}
129 # Get architectures for current target binary
130 binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
131 # Intersect them with the architectures we are building for
132 intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
133 # If there are no archs supported by this binary then warn the user
134 if [[ -z "$intersected_archs" ]]; then
135 if [[ "$warn_missing_arch" == "true" ]]; then
136 echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
137 fi
138 STRIP_BINARY_RETVAL=1
139 return
140 fi
141 stripped=""
142 for arch in $binary_archs; do
143 if ! [[ "${ARCHS}" == *"$arch"* ]]; then
144 # Strip non-valid architectures in-place
145 lipo -remove "$arch" -output "$binary" "$binary"
146 stripped="$stripped $arch"
147 fi
148 done
149 if [[ "$stripped" ]]; then
150 echo "Stripped $binary of architectures:$stripped"
151 fi
152 STRIP_BINARY_RETVAL=0
153 }
154
155 # Copies the bcsymbolmap files of a vendored framework
156 install_bcsymbolmap() {
157 local bcsymbolmap_path="$1"
158 local destination="${BUILT_PRODUCTS_DIR}"
159 echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
160 rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
161 }
162
163 # Signs a framework with the provided identity
164 code_sign_if_enabled() {
165 if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
166 # Use the current code_sign_identity
167 echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
168 local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
169
170 if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
171 code_sign_cmd="$code_sign_cmd &"
172 fi
173 echo "$code_sign_cmd"
174 eval "$code_sign_cmd"
175 fi
176 }
177
178 if [[ "$CONFIGURATION" == "Debug" ]]; then
179 install_framework "${BUILT_PRODUCTS_DIR}/JCategoryKit/JCategoryKit.framework"
180 fi
181 if [[ "$CONFIGURATION" == "Release" ]]; then
182 install_framework "${BUILT_PRODUCTS_DIR}/JCategoryKit/JCategoryKit.framework"
183 fi
184 if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
185 wait
186 fi
1 #ifdef __OBJC__
2 #import <UIKit/UIKit.h>
3 #else
4 #ifndef FOUNDATION_EXPORT
5 #if defined(__cplusplus)
6 #define FOUNDATION_EXPORT extern "C"
7 #else
8 #define FOUNDATION_EXPORT extern
9 #endif
10 #endif
11 #endif
12
13
14 FOUNDATION_EXPORT double Pods_JCategoryKit_ExampleVersionNumber;
15 FOUNDATION_EXPORT const unsigned char Pods_JCategoryKit_ExampleVersionString[];
16
1 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit"
3 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit/JCategoryKit.framework/Headers"
5 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 OTHER_LDFLAGS = $(inherited) -framework "JCategoryKit"
7 PODS_BUILD_DIR = ${BUILD_DIR}
8 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
10 PODS_ROOT = ${SRCROOT}/Pods
11 PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
12 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
1 framework module Pods_JCategoryKit_Example {
2 umbrella header "Pods-JCategoryKit_Example-umbrella.h"
3
4 export *
5 module * { export * }
6 }
1 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit"
3 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit/JCategoryKit.framework/Headers"
5 LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 OTHER_LDFLAGS = $(inherited) -framework "JCategoryKit"
7 PODS_BUILD_DIR = ${BUILD_DIR}
8 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
10 PODS_ROOT = ${SRCROOT}/Pods
11 PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
12 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>CFBundleDevelopmentRegion</key>
6 <string>en</string>
7 <key>CFBundleExecutable</key>
8 <string>${EXECUTABLE_NAME}</string>
9 <key>CFBundleIdentifier</key>
10 <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
11 <key>CFBundleInfoDictionaryVersion</key>
12 <string>6.0</string>
13 <key>CFBundleName</key>
14 <string>${PRODUCT_NAME}</string>
15 <key>CFBundlePackageType</key>
16 <string>FMWK</string>
17 <key>CFBundleShortVersionString</key>
18 <string>1.0.0</string>
19 <key>CFBundleSignature</key>
20 <string>????</string>
21 <key>CFBundleVersion</key>
22 <string>${CURRENT_PROJECT_VERSION}</string>
23 <key>NSPrincipalClass</key>
24 <string></string>
25 </dict>
26 </plist>
1 # Acknowledgements
2 This application makes use of the following third party libraries:
3
4 ## FBSnapshotTestCase
5
6 BSD License
7
8 For the FBSnapshotTestCase software
9
10 Copyright (c) 2013, Facebook, Inc.
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are met:
15
16 * Redistributions of source code must retain the above copyright notice,
17 this list of conditions and the following disclaimer.
18 * Redistributions in binary form must reproduce the above copyright notice,
19 this list of conditions and the following disclaimer in the documentation
20 and/or other materials provided with the distribution.
21 * Neither the name Facebook nor the names of its contributors may be used to
22 endorse or promote products derived from this software without specific
23 prior written permission.
24
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
36 Generated by CocoaPods - https://cocoapods.org
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 <plist version="1.0">
4 <dict>
5 <key>PreferenceSpecifiers</key>
6 <array>
7 <dict>
8 <key>FooterText</key>
9 <string>This application makes use of the following third party libraries:</string>
10 <key>Title</key>
11 <string>Acknowledgements</string>
12 <key>Type</key>
13 <string>PSGroupSpecifier</string>
14 </dict>
15 <dict>
16 <key>FooterText</key>
17 <string>BSD License
18
19 For the FBSnapshotTestCase software
20
21 Copyright (c) 2013, Facebook, Inc.
22 All rights reserved.
23
24 Redistribution and use in source and binary forms, with or without
25 modification, are permitted provided that the following conditions are met:
26
27 * Redistributions of source code must retain the above copyright notice,
28 this list of conditions and the following disclaimer.
29 * Redistributions in binary form must reproduce the above copyright notice,
30 this list of conditions and the following disclaimer in the documentation
31 and/or other materials provided with the distribution.
32 * Neither the name Facebook nor the names of its contributors may be used to
33 endorse or promote products derived from this software without specific
34 prior written permission.
35
36 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
37 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
40 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
42 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
43 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 </string>
47 <key>License</key>
48 <string>BSD</string>
49 <key>Title</key>
50 <string>FBSnapshotTestCase</string>
51 <key>Type</key>
52 <string>PSGroupSpecifier</string>
53 </dict>
54 <dict>
55 <key>FooterText</key>
56 <string>Generated by CocoaPods - https://cocoapods.org</string>
57 <key>Title</key>
58 <string></string>
59 <key>Type</key>
60 <string>PSGroupSpecifier</string>
61 </dict>
62 </array>
63 <key>StringsTable</key>
64 <string>Acknowledgements</string>
65 <key>Title</key>
66 <string>Acknowledgements</string>
67 </dict>
68 </plist>
1 #import <Foundation/Foundation.h>
2 @interface PodsDummy_Pods_JCategoryKit_Tests : NSObject
3 @end
4 @implementation PodsDummy_Pods_JCategoryKit_Tests
5 @end
1 #!/bin/sh
2 set -e
3 set -u
4 set -o pipefail
5
6 function on_error {
7 echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 }
9 trap 'on_error $LINENO' ERR
10
11 if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 # frameworks to, so exit 0 (signalling the script phase was successful).
14 exit 0
15 fi
16
17 echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19
20 COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 BCSYMBOLMAP_DIR="BCSymbolMaps"
23
24
25 # This protects against multiple targets copying the same framework dependency at the same time. The solution
26 # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
27 RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
28
29 # Copies and strips a vendored framework
30 install_framework()
31 {
32 if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
33 local source="${BUILT_PRODUCTS_DIR}/$1"
34 elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
35 local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
36 elif [ -r "$1" ]; then
37 local source="$1"
38 fi
39
40 local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
41
42 if [ -L "${source}" ]; then
43 echo "Symlinked..."
44 source="$(readlink "${source}")"
45 fi
46
47 if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
48 # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
49 find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
50 echo "Installing $f"
51 install_bcsymbolmap "$f" "$destination"
52 rm "$f"
53 done
54 rmdir "${source}/${BCSYMBOLMAP_DIR}"
55 fi
56
57 # Use filter instead of exclude so missing patterns don't throw errors.
58 echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
59 rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
60
61 local basename
62 basename="$(basename -s .framework "$1")"
63 binary="${destination}/${basename}.framework/${basename}"
64
65 if ! [ -r "$binary" ]; then
66 binary="${destination}/${basename}"
67 elif [ -L "${binary}" ]; then
68 echo "Destination binary is symlinked..."
69 dirname="$(dirname "${binary}")"
70 binary="${dirname}/$(readlink "${binary}")"
71 fi
72
73 # Strip invalid architectures so "fat" simulator / device frameworks work on device
74 if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
75 strip_invalid_archs "$binary"
76 fi
77
78 # Resign the code if required by the build settings to avoid unstable apps
79 code_sign_if_enabled "${destination}/$(basename "$1")"
80
81 # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
82 if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
83 local swift_runtime_libs
84 swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
85 for lib in $swift_runtime_libs; do
86 echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
87 rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
88 code_sign_if_enabled "${destination}/${lib}"
89 done
90 fi
91 }
92 # Copies and strips a vendored dSYM
93 install_dsym() {
94 local source="$1"
95 warn_missing_arch=${2:-true}
96 if [ -r "$source" ]; then
97 # Copy the dSYM into the targets temp dir.
98 echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
99 rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
100
101 local basename
102 basename="$(basename -s .dSYM "$source")"
103 binary_name="$(ls "$source/Contents/Resources/DWARF")"
104 binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
105
106 # Strip invalid architectures from the dSYM.
107 if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
108 strip_invalid_archs "$binary" "$warn_missing_arch"
109 fi
110 if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
111 # Move the stripped file into its final destination.
112 echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
113 rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
114 else
115 # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
116 mkdir -p "${DWARF_DSYM_FOLDER_PATH}"
117 touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
118 fi
119 fi
120 }
121
122 # Used as a return value for each invocation of `strip_invalid_archs` function.
123 STRIP_BINARY_RETVAL=0
124
125 # Strip invalid architectures
126 strip_invalid_archs() {
127 binary="$1"
128 warn_missing_arch=${2:-true}
129 # Get architectures for current target binary
130 binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
131 # Intersect them with the architectures we are building for
132 intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
133 # If there are no archs supported by this binary then warn the user
134 if [[ -z "$intersected_archs" ]]; then
135 if [[ "$warn_missing_arch" == "true" ]]; then
136 echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
137 fi
138 STRIP_BINARY_RETVAL=1
139 return
140 fi
141 stripped=""
142 for arch in $binary_archs; do
143 if ! [[ "${ARCHS}" == *"$arch"* ]]; then
144 # Strip non-valid architectures in-place
145 lipo -remove "$arch" -output "$binary" "$binary"
146 stripped="$stripped $arch"
147 fi
148 done
149 if [[ "$stripped" ]]; then
150 echo "Stripped $binary of architectures:$stripped"
151 fi
152 STRIP_BINARY_RETVAL=0
153 }
154
155 # Copies the bcsymbolmap files of a vendored framework
156 install_bcsymbolmap() {
157 local bcsymbolmap_path="$1"
158 local destination="${BUILT_PRODUCTS_DIR}"
159 echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
160 rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
161 }
162
163 # Signs a framework with the provided identity
164 code_sign_if_enabled() {
165 if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
166 # Use the current code_sign_identity
167 echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
168 local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
169
170 if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
171 code_sign_cmd="$code_sign_cmd &"
172 fi
173 echo "$code_sign_cmd"
174 eval "$code_sign_cmd"
175 fi
176 }
177
178 if [[ "$CONFIGURATION" == "Debug" ]]; then
179 install_framework "${BUILT_PRODUCTS_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework"
180 fi
181 if [[ "$CONFIGURATION" == "Release" ]]; then
182 install_framework "${BUILT_PRODUCTS_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework"
183 fi
184 if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
185 wait
186 fi
1 #ifdef __OBJC__
2 #import <UIKit/UIKit.h>
3 #else
4 #ifndef FOUNDATION_EXPORT
5 #if defined(__cplusplus)
6 #define FOUNDATION_EXPORT extern "C"
7 #else
8 #define FOUNDATION_EXPORT extern
9 #endif
10 #endif
11 #endif
12
13
14 FOUNDATION_EXPORT double Pods_JCategoryKit_TestsVersionNumber;
15 FOUNDATION_EXPORT const unsigned char Pods_JCategoryKit_TestsVersionString[];
16
1 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase" "${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit"
4 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit/JCategoryKit.framework/Headers"
6 LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer/Library/Frameworks" '@executable_path/Frameworks' '@loader_path/Frameworks'
7 LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 OTHER_LDFLAGS = $(inherited) -framework "FBSnapshotTestCase" -framework "Foundation" -framework "JCategoryKit" -framework "QuartzCore" -framework "UIKit" -framework "XCTest"
9 OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 PODS_BUILD_DIR = ${BUILD_DIR}
11 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 PODS_ROOT = ${SRCROOT}/Pods
14 PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
1 framework module Pods_JCategoryKit_Tests {
2 umbrella header "Pods-JCategoryKit_Tests-umbrella.h"
3
4 export *
5 module * { export * }
6 }
1 ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase" "${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit"
4 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FBSnapshotTestCase/FBSnapshotTestCase.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/JCategoryKit/JCategoryKit.framework/Headers"
6 LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer/Library/Frameworks" '@executable_path/Frameworks' '@loader_path/Frameworks'
7 LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
8 OTHER_LDFLAGS = $(inherited) -framework "FBSnapshotTestCase" -framework "Foundation" -framework "JCategoryKit" -framework "QuartzCore" -framework "UIKit" -framework "XCTest"
9 OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
10 PODS_BUILD_DIR = ${BUILD_DIR}
11 PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
12 PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
13 PODS_ROOT = ${SRCROOT}/Pods
14 PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
15 USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
8 8
9 Pod::Spec.new do |s| 9 Pod::Spec.new do |s|
10 s.name = 'JCategoryKit' 10 s.name = 'JCategoryKit'
11 s.version = '0.1.0' 11 s.version = '1.0.0'
12 s.summary = 'A short description of JCategoryKit.' 12 s.summary = 'A short description of JCategoryKit.'
13 13
14 # This description is used to generate tags and improve search results. 14 # This description is used to generate tags and improve search results.
...@@ -25,7 +25,7 @@ TODO: Add long description of the pod here. ...@@ -25,7 +25,7 @@ TODO: Add long description of the pod here.
25 # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 25 # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
26 s.license = { :type => 'MIT', :file => 'LICENSE' } 26 s.license = { :type => 'MIT', :file => 'LICENSE' }
27 s.author = { 'weixq' => 'weixiaoqiang@situdata.com' } 27 s.author = { 'weixq' => 'weixiaoqiang@situdata.com' }
28 s.source = { :git => 'https://github.com/weixq/JCategoryKit.git', :tag => s.version.to_s } 28 s.source = { :git => 'http://gitlab.situdata.com/weixiaoqiang/JCategoryKit.git', :tag => s.version.to_s }
29 # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>' 29 # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
30 30
31 s.ios.deployment_target = '9.0' 31 s.ios.deployment_target = '9.0'
......
1 //
2 // Person.h
3 // FBSnapshotTestCase
4 //
5 // Created by weixq on 2021/12/21.
6 //
7
8 #import <Foundation/Foundation.h>
9
10 NS_ASSUME_NONNULL_BEGIN
11
12 @interface Person : NSObject
13 -(void)eat;
14 @end
15
16 NS_ASSUME_NONNULL_END
1 //
2 // Person.m
3 // FBSnapshotTestCase
4 //
5 // Created by weixq on 2021/12/21.
6 //
7
8 #import "Person.h"
9
10 @implementation Person
11 -(void)eat{
12 NSLog(@"eat");
13 }
14 @end
1 This project is licensed under the MIT license.
2
3 Copyright (c) 2013 - 2014 CocoaPods Dev Team
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 THE SOFTWARE.
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!