second_curtain 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (316) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +20 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG +20 -0
  5. data/Demo/Demo/ASHAppDelegate.h +15 -0
  6. data/Demo/Demo/ASHAppDelegate.m +18 -0
  7. data/Demo/Demo/ASHViewController.h +13 -0
  8. data/Demo/Demo/ASHViewController.m +30 -0
  9. data/Demo/Demo/Base.lproj/Main.storyboard +30 -0
  10. data/Demo/Demo/Demo-Info.plist +40 -0
  11. data/Demo/Demo/Demo-Prefix.pch +16 -0
  12. data/Demo/Demo/Images.xcassets/AppIcon.appiconset/Contents.json +23 -0
  13. data/Demo/Demo/Images.xcassets/LaunchImage.launchimage/Contents.json +23 -0
  14. data/Demo/Demo/en.lproj/InfoPlist.strings +2 -0
  15. data/Demo/Demo/main.m +18 -0
  16. data/Demo/Demo.xcodeproj/project.pbxproj +517 -0
  17. data/Demo/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  18. data/Demo/Demo.xcodeproj/project.xcworkspace/xcshareddata/Demo.xccheckout +41 -0
  19. data/Demo/Demo.xcodeproj/project.xcworkspace/xcuserdata/ash.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  20. data/Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme +96 -0
  21. data/Demo/Demo.xcodeproj/xcuserdata/ash.xcuserdatad/xcschemes/xcschememanagement.plist +27 -0
  22. data/Demo/Demo.xcodeproj/xcuserdata/orta.xcuserdatad/xcschemes/xcschememanagement.plist +27 -0
  23. data/Demo/Demo.xcworkspace/contents.xcworkspacedata +1 -0
  24. data/Demo/Demo.xcworkspace/xcshareddata/Demo.xccheckout +41 -0
  25. data/Demo/Demo.xcworkspace/xcuserdata/ash.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  26. data/Demo/Demo.xcworkspace/xcuserdata/orta.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  27. data/Demo/DemoTests/DemoTests-Info.plist +22 -0
  28. data/Demo/DemoTests/DemoTests.m +52 -0
  29. data/Demo/DemoTests/ReferenceImages/ASHViewControllerSpec/a_view_controller_with_a_loaded_view_should_have_a_valid_snapshot@2x.png +0 -0
  30. data/Demo/DemoTests/ReferenceImages/ASHViewControllerSpec/views_should_be_green@2x.png +0 -0
  31. data/Demo/DemoTests/ReferenceImages/ASHViewControllerSpec/views_should_be_red@2x.png +0 -0
  32. data/Demo/DemoTests/en.lproj/InfoPlist.strings +2 -0
  33. data/Demo/Makefile +15 -0
  34. data/Demo/Podfile +16 -0
  35. data/Demo/Podfile.lock +21 -0
  36. data/Demo/Pods/BuildHeaders/Expecta/EXPBackwardCompatibility.h +42 -0
  37. data/Demo/Pods/BuildHeaders/Expecta/EXPBlockDefinedMatcher.h +25 -0
  38. data/Demo/Pods/BuildHeaders/Expecta/EXPDefines.h +17 -0
  39. data/Demo/Pods/BuildHeaders/Expecta/EXPDoubleTuple.h +13 -0
  40. data/Demo/Pods/BuildHeaders/Expecta/EXPExpect.h +45 -0
  41. data/Demo/Pods/BuildHeaders/Expecta/EXPFloatTuple.h +13 -0
  42. data/Demo/Pods/BuildHeaders/Expecta/EXPMatcher.h +20 -0
  43. data/Demo/Pods/BuildHeaders/Expecta/EXPMatcherHelpers.h +4 -0
  44. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beCloseTo.h +7 -0
  45. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beFalsy.h +3 -0
  46. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beGreaterThan.h +6 -0
  47. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beGreaterThanOrEqualTo.h +6 -0
  48. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beIdenticalTo.h +10 -0
  49. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beInTheRangeOf.h +6 -0
  50. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beInstanceOf.h +7 -0
  51. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beKindOf.h +5 -0
  52. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beLessThan.h +6 -0
  53. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beLessThanOrEqualTo.h +6 -0
  54. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beNil.h +5 -0
  55. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beSubclassOf.h +5 -0
  56. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beSupersetOf.h +4 -0
  57. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beTruthy.h +3 -0
  58. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+beginWith.h +5 -0
  59. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+conformTo.h +3 -0
  60. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+contain.h +5 -0
  61. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+endWith.h +3 -0
  62. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+equal.h +5 -0
  63. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+haveCountOf.h +10 -0
  64. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+notify.h +4 -0
  65. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+raise.h +4 -0
  66. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+raiseWithReason.h +3 -0
  67. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers+respondTo.h +3 -0
  68. data/Demo/Pods/BuildHeaders/Expecta/EXPMatchers.h +24 -0
  69. data/Demo/Pods/BuildHeaders/Expecta/EXPUnsupportedObject.h +11 -0
  70. data/Demo/Pods/BuildHeaders/Expecta/Expecta.h +27 -0
  71. data/Demo/Pods/BuildHeaders/Expecta/ExpectaSupport.h +64 -0
  72. data/Demo/Pods/BuildHeaders/Expecta/NSObject+Expecta.h +14 -0
  73. data/Demo/Pods/BuildHeaders/Expecta/NSValue+Expecta.h +8 -0
  74. data/Demo/Pods/BuildHeaders/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h +21 -0
  75. data/Demo/Pods/BuildHeaders/FBSnapshotTestCase/FBSnapshotTestCase.h +87 -0
  76. data/Demo/Pods/BuildHeaders/FBSnapshotTestCase/FBSnapshotTestController.h +147 -0
  77. data/Demo/Pods/BuildHeaders/FBSnapshotTestCase/UIImage+Compare.h +37 -0
  78. data/Demo/Pods/BuildHeaders/FBSnapshotTestCase/UIImage+Diff.h +37 -0
  79. data/Demo/Pods/BuildHeaders/Specta/SPTExample.h +14 -0
  80. data/Demo/Pods/BuildHeaders/Specta/SPTExampleGroup.h +40 -0
  81. data/Demo/Pods/BuildHeaders/Specta/SPTNestedReporter.h +5 -0
  82. data/Demo/Pods/BuildHeaders/Specta/SPTReporter.h +33 -0
  83. data/Demo/Pods/BuildHeaders/Specta/SPTSharedExampleGroups.h +17 -0
  84. data/Demo/Pods/BuildHeaders/Specta/SPTSpec.h +21 -0
  85. data/Demo/Pods/BuildHeaders/Specta/SPTXCTestCase.h +27 -0
  86. data/Demo/Pods/BuildHeaders/Specta/SPTXCTestReporter.h +9 -0
  87. data/Demo/Pods/BuildHeaders/Specta/Specta.h +70 -0
  88. data/Demo/Pods/BuildHeaders/Specta/SpectaSupport.h +46 -0
  89. data/Demo/Pods/BuildHeaders/Specta/SpectaTypes.h +3 -0
  90. data/Demo/Pods/BuildHeaders/Specta/SpectaUtility.h +14 -0
  91. data/Demo/Pods/BuildHeaders/Specta/XCTestCase+Specta.h +4 -0
  92. data/Demo/Pods/BuildHeaders/Specta/XCTestLog+Specta.h +7 -0
  93. data/Demo/Pods/BuildHeaders/Specta/XCTestRun+Specta.h +8 -0
  94. data/Demo/Pods/Expecta/LICENSE +19 -0
  95. data/Demo/Pods/Expecta/README.md +308 -0
  96. data/Demo/Pods/Expecta/src/EXPBackwardCompatibility.h +42 -0
  97. data/Demo/Pods/Expecta/src/EXPBackwardCompatibility.m +17 -0
  98. data/Demo/Pods/Expecta/src/EXPBlockDefinedMatcher.h +25 -0
  99. data/Demo/Pods/Expecta/src/EXPBlockDefinedMatcher.m +60 -0
  100. data/Demo/Pods/Expecta/src/EXPDefines.h +17 -0
  101. data/Demo/Pods/Expecta/src/EXPDoubleTuple.h +13 -0
  102. data/Demo/Pods/Expecta/src/EXPDoubleTuple.m +42 -0
  103. data/Demo/Pods/Expecta/src/EXPExpect.h +45 -0
  104. data/Demo/Pods/Expecta/src/EXPExpect.m +214 -0
  105. data/Demo/Pods/Expecta/src/EXPFloatTuple.h +13 -0
  106. data/Demo/Pods/Expecta/src/EXPFloatTuple.m +42 -0
  107. data/Demo/Pods/Expecta/src/EXPMatcher.h +20 -0
  108. data/Demo/Pods/Expecta/src/EXPUnsupportedObject.h +11 -0
  109. data/Demo/Pods/Expecta/src/EXPUnsupportedObject.m +20 -0
  110. data/Demo/Pods/Expecta/src/Expecta.h +27 -0
  111. data/Demo/Pods/Expecta/src/Expecta.m +15 -0
  112. data/Demo/Pods/Expecta/src/ExpectaSupport.h +64 -0
  113. data/Demo/Pods/Expecta/src/ExpectaSupport.m +187 -0
  114. data/Demo/Pods/Expecta/src/NSObject+Expecta.h +14 -0
  115. data/Demo/Pods/Expecta/src/NSValue+Expecta.h +8 -0
  116. data/Demo/Pods/Expecta/src/NSValue+Expecta.m +21 -0
  117. data/Demo/Pods/Expecta/src/matchers/EXPMatcherHelpers.h +4 -0
  118. data/Demo/Pods/Expecta/src/matchers/EXPMatcherHelpers.m +9 -0
  119. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beCloseTo.h +7 -0
  120. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beCloseTo.m +49 -0
  121. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beFalsy.h +3 -0
  122. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beFalsy.m +24 -0
  123. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beGreaterThan.h +6 -0
  124. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beGreaterThan.m +20 -0
  125. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beGreaterThanOrEqualTo.h +6 -0
  126. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beGreaterThanOrEqualTo.m +20 -0
  127. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beIdenticalTo.h +10 -0
  128. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beIdenticalTo.m +24 -0
  129. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beInTheRangeOf.h +6 -0
  130. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beInTheRangeOf.m +30 -0
  131. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beInstanceOf.h +7 -0
  132. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beInstanceOf.m +27 -0
  133. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beKindOf.h +5 -0
  134. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beKindOf.m +27 -0
  135. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beLessThan.h +6 -0
  136. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beLessThan.m +20 -0
  137. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beLessThanOrEqualTo.h +6 -0
  138. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beLessThanOrEqualTo.m +20 -0
  139. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beNil.h +5 -0
  140. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beNil.m +16 -0
  141. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beSubclassOf.h +5 -0
  142. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beSubclassOf.m +27 -0
  143. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beSupersetOf.h +4 -0
  144. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beSupersetOf.m +57 -0
  145. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beTruthy.h +3 -0
  146. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beTruthy.m +24 -0
  147. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beginWith.h +5 -0
  148. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+beginWith.m +49 -0
  149. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+conformTo.h +3 -0
  150. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+conformTo.m +33 -0
  151. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+contain.h +5 -0
  152. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+contain.m +38 -0
  153. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+endWith.h +3 -0
  154. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+endWith.m +49 -0
  155. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+equal.h +5 -0
  156. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+equal.m +24 -0
  157. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+haveCountOf.h +10 -0
  158. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+haveCountOf.m +36 -0
  159. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+notify.h +4 -0
  160. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+notify.m +63 -0
  161. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+raise.h +4 -0
  162. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+raise.m +30 -0
  163. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+raiseWithReason.h +3 -0
  164. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+raiseWithReason.m +35 -0
  165. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+respondTo.h +3 -0
  166. data/Demo/Pods/Expecta/src/matchers/EXPMatchers+respondTo.m +28 -0
  167. data/Demo/Pods/Expecta/src/matchers/EXPMatchers.h +24 -0
  168. data/Demo/Pods/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h +21 -0
  169. data/Demo/Pods/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.m +308 -0
  170. data/Demo/Pods/Expecta+Snapshots/LICENSE.md +22 -0
  171. data/Demo/Pods/Expecta+Snapshots/README.md +85 -0
  172. data/Demo/Pods/FBSnapshotTestCase/FBSnapshotTestCase.h +87 -0
  173. data/Demo/Pods/FBSnapshotTestCase/FBSnapshotTestCase.m +82 -0
  174. data/Demo/Pods/FBSnapshotTestCase/FBSnapshotTestController.h +147 -0
  175. data/Demo/Pods/FBSnapshotTestCase/FBSnapshotTestController.m +376 -0
  176. data/Demo/Pods/FBSnapshotTestCase/LICENSE +29 -0
  177. data/Demo/Pods/FBSnapshotTestCase/README.md +83 -0
  178. data/Demo/Pods/FBSnapshotTestCase/UIImage+Compare.h +37 -0
  179. data/Demo/Pods/FBSnapshotTestCase/UIImage+Compare.m +87 -0
  180. data/Demo/Pods/FBSnapshotTestCase/UIImage+Diff.h +37 -0
  181. data/Demo/Pods/FBSnapshotTestCase/UIImage+Diff.m +56 -0
  182. data/Demo/Pods/Headers/Expecta/EXPBackwardCompatibility.h +42 -0
  183. data/Demo/Pods/Headers/Expecta/EXPBlockDefinedMatcher.h +25 -0
  184. data/Demo/Pods/Headers/Expecta/EXPDefines.h +17 -0
  185. data/Demo/Pods/Headers/Expecta/EXPDoubleTuple.h +13 -0
  186. data/Demo/Pods/Headers/Expecta/EXPExpect.h +45 -0
  187. data/Demo/Pods/Headers/Expecta/EXPFloatTuple.h +13 -0
  188. data/Demo/Pods/Headers/Expecta/EXPMatcher.h +20 -0
  189. data/Demo/Pods/Headers/Expecta/EXPMatcherHelpers.h +4 -0
  190. data/Demo/Pods/Headers/Expecta/EXPMatchers+beCloseTo.h +7 -0
  191. data/Demo/Pods/Headers/Expecta/EXPMatchers+beFalsy.h +3 -0
  192. data/Demo/Pods/Headers/Expecta/EXPMatchers+beGreaterThan.h +6 -0
  193. data/Demo/Pods/Headers/Expecta/EXPMatchers+beGreaterThanOrEqualTo.h +6 -0
  194. data/Demo/Pods/Headers/Expecta/EXPMatchers+beIdenticalTo.h +10 -0
  195. data/Demo/Pods/Headers/Expecta/EXPMatchers+beInTheRangeOf.h +6 -0
  196. data/Demo/Pods/Headers/Expecta/EXPMatchers+beInstanceOf.h +7 -0
  197. data/Demo/Pods/Headers/Expecta/EXPMatchers+beKindOf.h +5 -0
  198. data/Demo/Pods/Headers/Expecta/EXPMatchers+beLessThan.h +6 -0
  199. data/Demo/Pods/Headers/Expecta/EXPMatchers+beLessThanOrEqualTo.h +6 -0
  200. data/Demo/Pods/Headers/Expecta/EXPMatchers+beNil.h +5 -0
  201. data/Demo/Pods/Headers/Expecta/EXPMatchers+beSubclassOf.h +5 -0
  202. data/Demo/Pods/Headers/Expecta/EXPMatchers+beSupersetOf.h +4 -0
  203. data/Demo/Pods/Headers/Expecta/EXPMatchers+beTruthy.h +3 -0
  204. data/Demo/Pods/Headers/Expecta/EXPMatchers+beginWith.h +5 -0
  205. data/Demo/Pods/Headers/Expecta/EXPMatchers+conformTo.h +3 -0
  206. data/Demo/Pods/Headers/Expecta/EXPMatchers+contain.h +5 -0
  207. data/Demo/Pods/Headers/Expecta/EXPMatchers+endWith.h +3 -0
  208. data/Demo/Pods/Headers/Expecta/EXPMatchers+equal.h +5 -0
  209. data/Demo/Pods/Headers/Expecta/EXPMatchers+haveCountOf.h +10 -0
  210. data/Demo/Pods/Headers/Expecta/EXPMatchers+notify.h +4 -0
  211. data/Demo/Pods/Headers/Expecta/EXPMatchers+raise.h +4 -0
  212. data/Demo/Pods/Headers/Expecta/EXPMatchers+raiseWithReason.h +3 -0
  213. data/Demo/Pods/Headers/Expecta/EXPMatchers+respondTo.h +3 -0
  214. data/Demo/Pods/Headers/Expecta/EXPMatchers.h +24 -0
  215. data/Demo/Pods/Headers/Expecta/EXPUnsupportedObject.h +11 -0
  216. data/Demo/Pods/Headers/Expecta/Expecta.h +27 -0
  217. data/Demo/Pods/Headers/Expecta/ExpectaSupport.h +64 -0
  218. data/Demo/Pods/Headers/Expecta/NSObject+Expecta.h +14 -0
  219. data/Demo/Pods/Headers/Expecta/NSValue+Expecta.h +8 -0
  220. data/Demo/Pods/Headers/Expecta+Snapshots/EXPMatchers+FBSnapshotTest.h +21 -0
  221. data/Demo/Pods/Headers/FBSnapshotTestCase/FBSnapshotTestCase.h +87 -0
  222. data/Demo/Pods/Headers/FBSnapshotTestCase/FBSnapshotTestController.h +147 -0
  223. data/Demo/Pods/Headers/FBSnapshotTestCase/UIImage+Compare.h +37 -0
  224. data/Demo/Pods/Headers/FBSnapshotTestCase/UIImage+Diff.h +37 -0
  225. data/Demo/Pods/Headers/Specta/SPTExample.h +14 -0
  226. data/Demo/Pods/Headers/Specta/SPTExampleGroup.h +40 -0
  227. data/Demo/Pods/Headers/Specta/SPTNestedReporter.h +5 -0
  228. data/Demo/Pods/Headers/Specta/SPTReporter.h +33 -0
  229. data/Demo/Pods/Headers/Specta/SPTSharedExampleGroups.h +17 -0
  230. data/Demo/Pods/Headers/Specta/SPTSpec.h +21 -0
  231. data/Demo/Pods/Headers/Specta/SPTXCTestCase.h +27 -0
  232. data/Demo/Pods/Headers/Specta/SPTXCTestReporter.h +9 -0
  233. data/Demo/Pods/Headers/Specta/Specta.h +70 -0
  234. data/Demo/Pods/Headers/Specta/SpectaSupport.h +46 -0
  235. data/Demo/Pods/Headers/Specta/SpectaTypes.h +3 -0
  236. data/Demo/Pods/Headers/Specta/SpectaUtility.h +14 -0
  237. data/Demo/Pods/Headers/Specta/XCTestCase+Specta.h +4 -0
  238. data/Demo/Pods/Headers/Specta/XCTestLog+Specta.h +7 -0
  239. data/Demo/Pods/Headers/Specta/XCTestRun+Specta.h +8 -0
  240. data/Demo/Pods/Manifest.lock +21 -0
  241. data/Demo/Pods/Pods-DemoTests-EXPMatchers+FBSnapshotTest-Private.xcconfig +6 -0
  242. data/Demo/Pods/Pods-DemoTests-EXPMatchers+FBSnapshotTest-dummy.m +5 -0
  243. data/Demo/Pods/Pods-DemoTests-EXPMatchers+FBSnapshotTest-prefix.pch +5 -0
  244. data/Demo/Pods/Pods-DemoTests-EXPMatchers+FBSnapshotTest.xcconfig +2 -0
  245. data/Demo/Pods/Pods-DemoTests-Expecta+Snapshots-Private.xcconfig +6 -0
  246. data/Demo/Pods/Pods-DemoTests-Expecta+Snapshots-dummy.m +5 -0
  247. data/Demo/Pods/Pods-DemoTests-Expecta+Snapshots-prefix.pch +5 -0
  248. data/Demo/Pods/Pods-DemoTests-Expecta+Snapshots.xcconfig +2 -0
  249. data/Demo/Pods/Pods-DemoTests-Expecta-Private.xcconfig +5 -0
  250. data/Demo/Pods/Pods-DemoTests-Expecta-dummy.m +5 -0
  251. data/Demo/Pods/Pods-DemoTests-Expecta-prefix.pch +5 -0
  252. data/Demo/Pods/Pods-DemoTests-Expecta.xcconfig +1 -0
  253. data/Demo/Pods/Pods-DemoTests-FBSnapshotTestCase-Private.xcconfig +6 -0
  254. data/Demo/Pods/Pods-DemoTests-FBSnapshotTestCase-dummy.m +5 -0
  255. data/Demo/Pods/Pods-DemoTests-FBSnapshotTestCase-prefix.pch +6 -0
  256. data/Demo/Pods/Pods-DemoTests-FBSnapshotTestCase.xcconfig +2 -0
  257. data/Demo/Pods/Pods-DemoTests-Specta-Private.xcconfig +6 -0
  258. data/Demo/Pods/Pods-DemoTests-Specta-dummy.m +5 -0
  259. data/Demo/Pods/Pods-DemoTests-Specta-prefix.pch +5 -0
  260. data/Demo/Pods/Pods-DemoTests-Specta.xcconfig +2 -0
  261. data/Demo/Pods/Pods-DemoTests-acknowledgements.markdown +109 -0
  262. data/Demo/Pods/Pods-DemoTests-acknowledgements.plist +151 -0
  263. data/Demo/Pods/Pods-DemoTests-dummy.m +5 -0
  264. data/Demo/Pods/Pods-DemoTests-environment.h +32 -0
  265. data/Demo/Pods/Pods-DemoTests-resources.sh +68 -0
  266. data/Demo/Pods/Pods-DemoTests.xcconfig +6 -0
  267. data/Demo/Pods/Pods.xcodeproj/project.pbxproj +1390 -0
  268. data/Demo/Pods/Pods.xcodeproj/xcuserdata/ash.xcuserdatad/xcschemes/Pods-DemoTests-Expecta+Snapshots.xcscheme +59 -0
  269. data/Demo/Pods/Pods.xcodeproj/xcuserdata/ash.xcuserdatad/xcschemes/Pods-DemoTests-Expecta.xcscheme +59 -0
  270. data/Demo/Pods/Pods.xcodeproj/xcuserdata/ash.xcuserdatad/xcschemes/Pods-DemoTests-FBSnapshotTestCase.xcscheme +59 -0
  271. data/Demo/Pods/Pods.xcodeproj/xcuserdata/ash.xcuserdatad/xcschemes/Pods-DemoTests-Specta.xcscheme +59 -0
  272. data/Demo/Pods/Pods.xcodeproj/xcuserdata/ash.xcuserdatad/xcschemes/Pods-DemoTests.xcscheme +59 -0
  273. data/Demo/Pods/Pods.xcodeproj/xcuserdata/ash.xcuserdatad/xcschemes/xcschememanagement.plist +62 -0
  274. data/Demo/Pods/Specta/LICENSE +20 -0
  275. data/Demo/Pods/Specta/README.md +146 -0
  276. data/Demo/Pods/Specta/src/SPTExample.h +14 -0
  277. data/Demo/Pods/Specta/src/SPTExample.m +16 -0
  278. data/Demo/Pods/Specta/src/SPTExampleGroup.h +40 -0
  279. data/Demo/Pods/Specta/src/SPTExampleGroup.m +326 -0
  280. data/Demo/Pods/Specta/src/SPTNestedReporter.h +5 -0
  281. data/Demo/Pods/Specta/src/SPTNestedReporter.m +194 -0
  282. data/Demo/Pods/Specta/src/SPTReporter.h +33 -0
  283. data/Demo/Pods/Specta/src/SPTReporter.m +134 -0
  284. data/Demo/Pods/Specta/src/SPTSharedExampleGroups.h +17 -0
  285. data/Demo/Pods/Specta/src/SPTSharedExampleGroups.m +62 -0
  286. data/Demo/Pods/Specta/src/SPTSpec.h +21 -0
  287. data/Demo/Pods/Specta/src/SPTSpec.m +31 -0
  288. data/Demo/Pods/Specta/src/SPTXCTestCase.h +27 -0
  289. data/Demo/Pods/Specta/src/SPTXCTestCase.m +151 -0
  290. data/Demo/Pods/Specta/src/SPTXCTestReporter.h +9 -0
  291. data/Demo/Pods/Specta/src/SPTXCTestReporter.m +11 -0
  292. data/Demo/Pods/Specta/src/Specta.h +70 -0
  293. data/Demo/Pods/Specta/src/Specta.m +144 -0
  294. data/Demo/Pods/Specta/src/SpectaSupport.h +46 -0
  295. data/Demo/Pods/Specta/src/SpectaTypes.h +3 -0
  296. data/Demo/Pods/Specta/src/SpectaUtility.h +14 -0
  297. data/Demo/Pods/Specta/src/SpectaUtility.m +65 -0
  298. data/Demo/Pods/Specta/src/XCTestCase+Specta.h +4 -0
  299. data/Demo/Pods/Specta/src/XCTestCase+Specta.m +26 -0
  300. data/Demo/Pods/Specta/src/XCTestLog+Specta.h +7 -0
  301. data/Demo/Pods/Specta/src/XCTestLog+Specta.m +49 -0
  302. data/Demo/Pods/Specta/src/XCTestRun+Specta.h +8 -0
  303. data/Demo/Pods/Specta/src/XCTestRun+Specta.m +44 -0
  304. data/Gemfile +5 -0
  305. data/LICENSE +21 -0
  306. data/README.md +146 -0
  307. data/Rakefile +7 -0
  308. data/second_curtain.gemspec +20 -0
  309. data/spec/sample_output.txt +79 -0
  310. data/spec/second_shutter/kaleidoscope_command_spec.rb +25 -0
  311. data/spec/second_shutter/parser_spec.rb +39 -0
  312. data/spec/second_shutter/test_suite_spec.rb +32 -0
  313. data/spec/second_shutter/upload_manager_spec.rb +60 -0
  314. data/spec/second_shutter/upload_spec.rb +34 -0
  315. data/spec/second_shutter/xcode_test_case_spec.rb +22 -0
  316. metadata +315 -1
@@ -0,0 +1,147 @@
1
+ /*
2
+ * Copyright (c) 2013, 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
+ Provides the heavy-lifting for FBSnapshotTestCase. It loads and saves images, along with performing the actual pixel-
33
+ by-pixel comparison of images.
34
+ Instances are initialized with the test class, and directories to read and write to.
35
+ */
36
+ @interface FBSnapshotTestController : NSObject
37
+
38
+ /**
39
+ Record snapshots.
40
+ **/
41
+ @property(readwrite, nonatomic, assign) BOOL recordMode;
42
+
43
+ /**
44
+ Designated initializer.
45
+ Before this methods returns the controller enumerates over the test methods in `testClass` and loads the images
46
+ for those tests.
47
+ @param testClass The subclass of FBSnapshotTestCase that is using this controller.
48
+ @param referenceImagesDirectory The directory where the reference images are stored.
49
+ @returns An instance of FBSnapshotTestController.
50
+ */
51
+ - (id)initWithTestClass:(Class)testClass;
52
+
53
+
54
+ /**
55
+ Performs the comparison of the layer.
56
+ @param layer The Layer to snapshot.
57
+ @param referenceImagesDirectory The directory in which reference images are stored.
58
+ @param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
59
+ @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
60
+ @returns YES if the comparison (or saving of the reference image) succeeded.
61
+ */
62
+ - (BOOL)compareSnapshotOfLayer:(CALayer *)layer
63
+ selector:(SEL)selector
64
+ identifier:(NSString *)identifier
65
+ error:(NSError **)errorPtr;
66
+
67
+ /**
68
+ Performs the comparison of the view.
69
+ @param view The view to snapshot.
70
+ @param referenceImagesDirectory The directory in which reference images are stored.
71
+ @param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
72
+ @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
73
+ @returns YES if the comparison (or saving of the reference image) succeeded.
74
+ */
75
+ - (BOOL)compareSnapshotOfView:(UIView *)view
76
+ selector:(SEL)selector
77
+ identifier:(NSString *)identifier
78
+ error:(NSError **)errorPtr;
79
+
80
+ /**
81
+ Performs the comparison of a view or layer.
82
+ @param view The view or layer to snapshot.
83
+ @param referenceImagesDirectory The directory in which reference images are stored.
84
+ @param identifier An optional identifier, used is there are muliptle snapshot tests in a given -test method.
85
+ @param error An error to log in an XCTAssert() macro if the method fails (missing reference image, images differ, etc).
86
+ @returns YES if the comparison (or saving of the reference image) succeeded.
87
+ */
88
+ - (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
89
+ selector:(SEL)selector
90
+ identifier:(NSString *)identifier
91
+ error:(NSError **)errorPtr;
92
+
93
+
94
+ /**
95
+ The directory in which referfence images are stored.
96
+ */
97
+ @property (readwrite, nonatomic, copy) NSString *referenceImagesDirectory;
98
+
99
+ /**
100
+ Loads a reference image.
101
+ @param selector The test method being run.
102
+ @param identifier The optional identifier, used when multiple images are tested in a single -test method.
103
+ @param error An error, if this methods returns nil, the error will be something useful.
104
+ @returns An image.
105
+ */
106
+ - (UIImage *)referenceImageForSelector:(SEL)selector
107
+ identifier:(NSString *)identifier
108
+ error:(NSError **)error;
109
+
110
+ /**
111
+ Saves a reference image.
112
+ @param selector The test method being run.
113
+ @param identifier The optional identifier, used when multiple images are tested in a single -test method.
114
+ @param error An error, if this methods returns NO, the error will be something useful.
115
+ @returns An image.
116
+ */
117
+ - (BOOL)saveReferenceImage:(UIImage *)image
118
+ selector:(SEL)selector
119
+ identifier:(NSString *)identifier
120
+ error:(NSError **)errorPtr;
121
+
122
+ /**
123
+ Performs a pixel-by-pixel comparison of the two images.
124
+ @param referenceImage The reference (correct) image.
125
+ @param image The image to test against the reference.
126
+ @param error An error that indicates why the comparison failed if it does.
127
+ @param YES if the comparison succeeded and the images are the same.
128
+ */
129
+ - (BOOL)compareReferenceImage:(UIImage *)referenceImage
130
+ toImage:(UIImage *)image
131
+ error:(NSError **)errorPtr;
132
+
133
+ /**
134
+ Saves the reference image and the test image to `failedOutputDirectory`.
135
+ @param referenceImage The reference (correct) image.
136
+ @param testImage The image to test against the reference.
137
+ @param selector The test method being run.
138
+ @param identifier The optional identifier, used when multiple images are tested in a single -test method.
139
+ @param error An error that indicates why the comparison failed if it does.
140
+ @param YES if the save succeeded.
141
+ */
142
+ - (BOOL)saveFailedReferenceImage:(UIImage *)referenceImage
143
+ testImage:(UIImage *)testImage
144
+ selector:(SEL)selector
145
+ identifier:(NSString *)identifier
146
+ error:(NSError **)errorPtr;
147
+ @end
@@ -0,0 +1,376 @@
1
+ /*
2
+ * Copyright (c) 2013, 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 "FBSnapshotTestController.h"
12
+
13
+ #import "UIImage+Compare.h"
14
+ #import "UIImage+Diff.h"
15
+
16
+ #import <objc/runtime.h>
17
+
18
+ #import <UIKit/UIKit.h>
19
+
20
+ NSString *const FBSnapshotTestControllerErrorDomain = @"FBSnapshotTestControllerErrorDomain";
21
+
22
+ NSString *const FBReferenceImageFilePathKey = @"FBReferenceImageFilePathKey";
23
+
24
+ typedef struct RGBAPixel {
25
+ char r;
26
+ char g;
27
+ char b;
28
+ char a;
29
+ } RGBAPixel;
30
+
31
+ @interface FBSnapshotTestController ()
32
+
33
+ @property (readonly, nonatomic, retain) Class testClass;
34
+
35
+ @end
36
+
37
+ @implementation FBSnapshotTestController
38
+ {
39
+ NSFileManager *_fileManager;
40
+ }
41
+
42
+ #pragma mark -
43
+ #pragma mark Lifecycle
44
+
45
+ - (id)initWithTestClass:(Class)testClass;
46
+ {
47
+ if ((self = [super init])) {
48
+ _testClass = testClass;
49
+ _fileManager = [[NSFileManager alloc] init];
50
+ }
51
+ return self;
52
+ }
53
+
54
+ #pragma mark -
55
+ #pragma mark Properties
56
+
57
+ - (NSString *)description
58
+ {
59
+ return [NSString stringWithFormat:@"%@ %@", [super description], _referenceImagesDirectory];
60
+ }
61
+
62
+ #pragma mark -
63
+ #pragma mark Public API
64
+
65
+ - (UIImage *)referenceImageForSelector:(SEL)selector
66
+ identifier:(NSString *)identifier
67
+ error:(NSError **)errorPtr
68
+ {
69
+ NSString *filePath = [self _referenceFilePathForSelector:selector identifier:identifier];
70
+ UIImage *image = [UIImage imageWithContentsOfFile:filePath];
71
+ if (nil == image && NULL != errorPtr) {
72
+ BOOL exists = [_fileManager fileExistsAtPath:filePath];
73
+ if (!exists) {
74
+ *errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
75
+ code:FBSnapshotTestControllerErrorCodeNeedsRecord
76
+ userInfo:@{
77
+ FBReferenceImageFilePathKey: filePath,
78
+ NSLocalizedDescriptionKey: @"Unable to load reference image.",
79
+ NSLocalizedFailureReasonErrorKey: @"Reference image not found. You need to run the test in record mode",
80
+ }];
81
+ } else {
82
+ *errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
83
+ code:FBSnapshotTestControllerErrorCodeUnknown
84
+ userInfo:nil];
85
+ }
86
+ }
87
+ return image;
88
+ }
89
+
90
+ - (BOOL)saveReferenceImage:(UIImage *)image
91
+ selector:(SEL)selector
92
+ identifier:(NSString *)identifier
93
+ error:(NSError **)errorPtr
94
+ {
95
+ BOOL didWrite = NO;
96
+ if (nil != image) {
97
+ NSString *filePath = [self _referenceFilePathForSelector:selector identifier:identifier];
98
+ NSData *pngData = UIImagePNGRepresentation(image);
99
+ if (nil != pngData) {
100
+ NSError *creationError = nil;
101
+ BOOL didCreateDir = [_fileManager createDirectoryAtPath:[filePath stringByDeletingLastPathComponent]
102
+ withIntermediateDirectories:YES
103
+ attributes:nil
104
+ error:&creationError];
105
+ if (!didCreateDir) {
106
+ if (NULL != errorPtr) {
107
+ *errorPtr = creationError;
108
+ }
109
+ return NO;
110
+ }
111
+ didWrite = [pngData writeToFile:filePath options:NSDataWritingAtomic error:errorPtr];
112
+ } else {
113
+ if (nil != errorPtr) {
114
+ *errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
115
+ code:FBSnapshotTestControllerErrorCodePNGCreationFailed
116
+ userInfo:@{
117
+ FBReferenceImageFilePathKey: filePath,
118
+ }];
119
+ }
120
+ }
121
+ }
122
+ return didWrite;
123
+ }
124
+
125
+ - (BOOL)saveFailedReferenceImage:(UIImage *)referenceImage
126
+ testImage:(UIImage *)testImage
127
+ selector:(SEL)selector
128
+ identifier:(NSString *)identifier
129
+ error:(NSError **)errorPtr
130
+ {
131
+ NSData *referencePNGData = UIImagePNGRepresentation(referenceImage);
132
+ NSData *testPNGData = UIImagePNGRepresentation(testImage);
133
+
134
+ NSString *referencePath = [self _failedFilePathForSelector:selector
135
+ identifier:identifier
136
+ fileNameType:FBTestSnapshotFileNameTypeFailedReference];
137
+
138
+ NSError *creationError = nil;
139
+ BOOL didCreateDir = [_fileManager createDirectoryAtPath:[referencePath stringByDeletingLastPathComponent]
140
+ withIntermediateDirectories:YES
141
+ attributes:nil
142
+ error:&creationError];
143
+ if (!didCreateDir) {
144
+ if (NULL != errorPtr) {
145
+ *errorPtr = creationError;
146
+ }
147
+ return NO;
148
+ }
149
+
150
+ if (![referencePNGData writeToFile:referencePath options:NSDataWritingAtomic error:errorPtr]) {
151
+ return NO;
152
+ }
153
+
154
+ NSString *testPath = [self _failedFilePathForSelector:selector
155
+ identifier:identifier
156
+ fileNameType:FBTestSnapshotFileNameTypeFailedTest];
157
+
158
+ if (![testPNGData writeToFile:testPath options:NSDataWritingAtomic error:errorPtr]) {
159
+ return NO;
160
+ }
161
+
162
+ NSString *diffPath = [self _failedFilePathForSelector:selector
163
+ identifier:identifier
164
+ fileNameType:FBTestSnapshotFileNameTypeFailedTestDiff];
165
+
166
+ UIImage *diffImage = [referenceImage diffWithImage:testImage];
167
+ NSData *diffImageData = UIImagePNGRepresentation(diffImage);
168
+
169
+ if (![diffImageData writeToFile:diffPath options:NSDataWritingAtomic error:errorPtr]) {
170
+ return NO;
171
+ }
172
+
173
+ NSLog(@"If you have Kaleidoscope installed you can run this command to see an image diff:\n"
174
+ @"ksdiff \"%@\" \"%@\"", referencePath, testPath);
175
+
176
+ return YES;
177
+ }
178
+
179
+ - (BOOL)compareReferenceImage:(UIImage *)referenceImage toImage:(UIImage *)image error:(NSError **)errorPtr
180
+ {
181
+ if (CGSizeEqualToSize(referenceImage.size, image.size)) {
182
+
183
+ BOOL imagesEqual = [referenceImage compareWithImage:image];
184
+ if (NULL != errorPtr) {
185
+ *errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
186
+ code:FBSnapshotTestControllerErrorCodeImagesDifferent
187
+ userInfo:@{
188
+ NSLocalizedDescriptionKey: @"Images different",
189
+ }];
190
+ }
191
+ return imagesEqual;
192
+ }
193
+ if (NULL != errorPtr) {
194
+ *errorPtr = [NSError errorWithDomain:FBSnapshotTestControllerErrorDomain
195
+ code:FBSnapshotTestControllerErrorCodeImagesDifferentSizes
196
+ userInfo:@{
197
+ NSLocalizedDescriptionKey: @"Images different sizes",
198
+ NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"referenceImage:%@, image:%@",
199
+ NSStringFromCGSize(referenceImage.size),
200
+ NSStringFromCGSize(image.size)],
201
+ }];
202
+ }
203
+ return NO;
204
+ }
205
+
206
+ #pragma mark -
207
+ #pragma mark Private API
208
+
209
+ typedef NS_ENUM(NSUInteger, FBTestSnapshotFileNameType) {
210
+ FBTestSnapshotFileNameTypeReference,
211
+ FBTestSnapshotFileNameTypeFailedReference,
212
+ FBTestSnapshotFileNameTypeFailedTest,
213
+ FBTestSnapshotFileNameTypeFailedTestDiff,
214
+ };
215
+
216
+ - (NSString *)_fileNameForSelector:(SEL)selector
217
+ identifier:(NSString *)identifier
218
+ fileNameType:(FBTestSnapshotFileNameType)fileNameType
219
+ {
220
+ NSString *fileName = nil;
221
+ switch (fileNameType) {
222
+ case FBTestSnapshotFileNameTypeFailedReference:
223
+ fileName = @"reference_";
224
+ break;
225
+ case FBTestSnapshotFileNameTypeFailedTest:
226
+ fileName = @"failed_";
227
+ break;
228
+ case FBTestSnapshotFileNameTypeFailedTestDiff:
229
+ fileName = @"diff_";
230
+ break;
231
+ default:
232
+ fileName = @"";
233
+ break;
234
+ }
235
+ fileName = [fileName stringByAppendingString:NSStringFromSelector(selector)];
236
+ if (0 < identifier.length) {
237
+ fileName = [fileName stringByAppendingFormat:@"_%@", identifier];
238
+ }
239
+ if ([[UIScreen mainScreen] scale] >= 2.0) {
240
+ fileName = [fileName stringByAppendingString:@"@2x"];
241
+ }
242
+ fileName = [fileName stringByAppendingPathExtension:@"png"];
243
+ return fileName;
244
+ }
245
+
246
+ - (NSString *)_referenceFilePathForSelector:(SEL)selector identifier:(NSString *)identifier
247
+ {
248
+ NSString *fileName = [self _fileNameForSelector:selector
249
+ identifier:identifier
250
+ fileNameType:FBTestSnapshotFileNameTypeReference];
251
+ NSString *filePath = [_referenceImagesDirectory stringByAppendingPathComponent:NSStringFromClass(_testClass)];
252
+ filePath = [filePath stringByAppendingPathComponent:fileName];
253
+ return filePath;
254
+ }
255
+
256
+ - (NSString *)_failedFilePathForSelector:(SEL)selector
257
+ identifier:(NSString *)identifier
258
+ fileNameType:(FBTestSnapshotFileNameType)fileNameType
259
+ {
260
+ NSString *fileName = [self _fileNameForSelector:selector
261
+ identifier:identifier
262
+ fileNameType:fileNameType];
263
+ NSString *folderPath = NSTemporaryDirectory();
264
+ if (getenv("IMAGE_DIFF_DIR")) {
265
+ folderPath = @(getenv("IMAGE_DIFF_DIR"));
266
+ }
267
+ NSString *filePath = [folderPath stringByAppendingPathComponent:NSStringFromClass(_testClass)];
268
+ filePath = [filePath stringByAppendingPathComponent:fileName];
269
+ return filePath;
270
+ }
271
+
272
+ - (BOOL)compareSnapshotOfLayer:(CALayer *)layer
273
+ selector:(SEL)selector
274
+ identifier:(NSString *)identifier
275
+ error:(NSError **)errorPtr
276
+ {
277
+ return [self compareSnapshotOfViewOrLayer:layer
278
+ selector:selector
279
+ identifier:identifier
280
+ error:errorPtr];
281
+ }
282
+
283
+ - (BOOL)compareSnapshotOfView:(UIView *)view
284
+ selector:(SEL)selector
285
+ identifier:(NSString *)identifier
286
+ error:(NSError **)errorPtr
287
+ {
288
+ return [self compareSnapshotOfViewOrLayer:view
289
+ selector:selector
290
+ identifier:identifier
291
+ error:errorPtr];
292
+ }
293
+
294
+ - (BOOL)compareSnapshotOfViewOrLayer:(id)viewOrLayer
295
+ selector:(SEL)selector
296
+ identifier:(NSString *)identifier
297
+ error:(NSError **)errorPtr
298
+ {
299
+ if (self.recordMode) {
300
+ return [self _recordSnapshotOfViewOrLayer:viewOrLayer selector:selector identifier:identifier error:errorPtr];
301
+ } else {
302
+ return [self _performPixelComparisonWithViewOrLayer:viewOrLayer selector:selector identifier:identifier error:errorPtr];
303
+ }
304
+ }
305
+
306
+ #pragma mark -
307
+ #pragma mark Private API
308
+
309
+ - (BOOL)_performPixelComparisonWithViewOrLayer:(UIView *)viewOrLayer
310
+ selector:(SEL)selector
311
+ identifier:(NSString *)identifier
312
+ error:(NSError **)errorPtr
313
+ {
314
+ UIImage *referenceImage = [self referenceImageForSelector:selector identifier:identifier error:errorPtr];
315
+ if (nil != referenceImage) {
316
+ UIImage *snapshot = [self _snapshotViewOrLayer:viewOrLayer];
317
+ BOOL imagesSame = [self compareReferenceImage:referenceImage toImage:snapshot error:errorPtr];
318
+ if (!imagesSame) {
319
+ [self saveFailedReferenceImage:referenceImage
320
+ testImage:snapshot
321
+ selector:selector
322
+ identifier:identifier
323
+ error:errorPtr];
324
+ }
325
+ return imagesSame;
326
+ }
327
+ return NO;
328
+ }
329
+
330
+ - (BOOL)_recordSnapshotOfViewOrLayer:(id)viewOrLayer
331
+ selector:(SEL)selector
332
+ identifier:(NSString *)identifier
333
+ error:(NSError **)errorPtr
334
+ {
335
+ UIImage *snapshot = [self _snapshotViewOrLayer:viewOrLayer];
336
+ return [self saveReferenceImage:snapshot selector:selector identifier:identifier error:errorPtr];
337
+ }
338
+
339
+ - (UIImage *)_snapshotViewOrLayer:(id)viewOrLayer
340
+ {
341
+ CALayer *layer = nil;
342
+
343
+ if ([viewOrLayer isKindOfClass:[UIView class]]) {
344
+ UIView *view = (UIView *)viewOrLayer;
345
+ [view layoutIfNeeded];
346
+ layer = view.layer;
347
+ } else if ([viewOrLayer isKindOfClass:[CALayer class]]) {
348
+ layer = (CALayer *)viewOrLayer;
349
+ [layer layoutIfNeeded];
350
+ } else {
351
+ [NSException raise:@"Only UIView and CALayer classes can be snapshotted" format:@"%@", viewOrLayer];
352
+ }
353
+
354
+ return [self _renderLayer:layer];
355
+ }
356
+
357
+ - (UIImage *)_renderLayer:(CALayer *)layer
358
+ {
359
+ CGRect bounds = layer.bounds;
360
+
361
+ UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 0);
362
+ CGContextRef context = UIGraphicsGetCurrentContext();
363
+
364
+ CGContextSaveGState(context);
365
+ {
366
+ [layer renderInContext:context];
367
+ }
368
+ CGContextRestoreGState(context);
369
+
370
+ UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
371
+ UIGraphicsEndImageContext();
372
+
373
+ return snapshot;
374
+ }
375
+
376
+ @end
@@ -0,0 +1,29 @@
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.
@@ -0,0 +1,83 @@
1
+ FBSnapshotTestCase
2
+ ======================
3
+
4
+ [![Build Status](https://travis-ci.org/facebook/ios-snapshot-test-case.png)](https://travis-ci.org/facebook/ios-snapshot-test-case)
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
+ Creating a snapshot test
33
+ ------------------------
34
+
35
+ 1. Drop the `FBSnapshotTestCase` and `FBSnapshotTestController` source files
36
+ into your project. In the Add Files dialog, be sure to check the **tests**
37
+ target, not the main target.
38
+
39
+ <img src="http://facebook.github.io/ios-snapshot-test-case/AddFiles.png" alt="Add Files Dialog" width="364">
40
+
41
+ 2. Define `FB_REFERENCE_IMAGE_DIR` in `GCC_PREPROCESSOR_DEFINITIONS`. This
42
+ should point to the directory where you want reference images to be stored.
43
+ At Facebook, we normally use this:
44
+
45
+ `GCC_PREPROCESSOR_DEFINITIONS = $(inherited) FB_REFERENCE_IMAGE_DIR="\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\""`
46
+
47
+ 3. Subclass `FBSnapshotTestCase` instead of `XCTestCase`.
48
+ 4. From within your test, use `FBSnapshotVerifyView`.
49
+ 5. Run the test once with `self.recordMode = YES;` in the test's `-setUp`
50
+ method. (This creates the reference images on disk.)
51
+ 6. Remove the line enabling record mode and run the test.
52
+
53
+ Features
54
+ --------
55
+
56
+ - Automatically names reference images on disk according to test class and
57
+ selector.
58
+ - Prints a descriptive error message to the console on failure. (Bonus:
59
+ failure message includes a one-line command to see an image diff if
60
+ you have [Kaleidoscope](http://www.kaleidoscopeapp.com) installed.)
61
+ - Supply an optional "identifier" if you want to perform multiple snapshots
62
+ in a single test method.
63
+ - Support for `CALayer` via `FBSnapshotVerifyLayer`.
64
+
65
+ Notes
66
+ -----
67
+
68
+ Your unit test must be an "application test", not a "logic test." (That is, it
69
+ must be run within the Simulator so that it has access to UIKit.) In Xcode 5
70
+ and later new projects only offer application tests, but older projects will
71
+ have separate targets for the two types.
72
+
73
+ Authors
74
+ -------
75
+
76
+ `FBSnapshotTestCase` was written at Facebook by
77
+ [Jonathan Dann](https://facebook.com/j.p.dann) with significant contributions by
78
+ [Todd Krabach](https://facebook.com/toddkrabach).
79
+
80
+ License
81
+ -------
82
+
83
+ `FBSnapshotTestCase` is BSD-licensed. See `LICENSE`.
@@ -0,0 +1,37 @@
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)compareWithImage:(UIImage *)image;
36
+
37
+ @end