diff --git a/IGListKit.xcodeproj/project.pbxproj b/IGListKit.xcodeproj/project.pbxproj index 38e54311..8d4bcae7 100644 --- a/IGListKit.xcodeproj/project.pbxproj +++ b/IGListKit.xcodeproj/project.pbxproj @@ -29,7 +29,6 @@ 16B71CEE22B0A08400FE96ED /* IGTestInvalidateLayoutDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 16B71CE822B0A08300FE96ED /* IGTestInvalidateLayoutDataSource.m */; }; 16B71CEF22B0A08400FE96ED /* IGTestInvalidateLayoutObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 16B71CEA22B0A08300FE96ED /* IGTestInvalidateLayoutObject.m */; }; 16B71CF022B0A08400FE96ED /* IGTestInvalidateLayoutObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 16B71CEA22B0A08300FE96ED /* IGTestInvalidateLayoutObject.m */; }; - 262373C2015556E71A70FA30 /* Pods_IGListKit_tvOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E980179F5E885E417EB20D55 /* Pods_IGListKit_tvOSTests.framework */; }; 26271C8A1DAE94E40073E116 /* IGTestSingleNibItemDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 26271C891DAE94E40073E116 /* IGTestSingleNibItemDataSource.m */; }; 26271C8C1DAE96740073E116 /* IGListSingleNibItemControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 26271C8B1DAE96740073E116 /* IGListSingleNibItemControllerTests.m */; }; 290DF3771E9323E6009FE456 /* IGListDebuggerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 290DF3761E9323E6009FE456 /* IGListDebuggerTests.m */; }; @@ -416,7 +415,6 @@ BA4A65252760278F00FA5750 /* ListValueSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4A65222760278F00FA5750 /* ListValueSectionController.swift */; }; BA4A65262760278F00FA5750 /* ListIdentifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4A65232760278F00FA5750 /* ListIdentifiable.swift */; }; BA4A65272760278F00FA5750 /* ListIdentifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4A65232760278F00FA5750 /* ListIdentifiable.swift */; }; - DD468D380BBF350ACE7EA28B /* Pods_IGListKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AB7195278D0BBB5DA88D36F /* Pods_IGListKitTests.framework */; }; E03DEA83255C9AAC00ACCAFC /* IGListTransitionData.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B22E692502AAB10055DC2F /* IGListTransitionData.h */; settings = {ATTRIBUTES = (Public, ); }; }; E03DEA8F255C9AB200ACCAFC /* IGListTransitionData.m in Sources */ = {isa = PBXBuildFile; fileRef = 57B22E662502AAB10055DC2F /* IGListTransitionData.m */; }; E56B7B3420A9D7100071010C /* IGListCollectionScrollingTraitsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E56B7B3320A9D7100071010C /* IGListCollectionScrollingTraitsTests.m */; }; @@ -425,6 +423,18 @@ F1855A4C29BC565600558D18 /* IGListDiffDescriptionStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1855A4B29BC565600558D18 /* IGListDiffDescriptionStringTests.m */; }; F1855A4D29BC565600558D18 /* IGListDiffDescriptionStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1855A4B29BC565600558D18 /* IGListDiffDescriptionStringTests.m */; }; F1855A4E29BC565600558D18 /* IGListDiffDescriptionStringTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1855A4B29BC565600558D18 /* IGListDiffDescriptionStringTests.m */; }; + F1E6302329EA43080060B4D6 /* IGListSectionControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1E6302229EA43080060B4D6 /* IGListSectionControllerTests.m */; }; + F1E6302429EA43080060B4D6 /* IGListSectionControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1E6302229EA43080060B4D6 /* IGListSectionControllerTests.m */; }; + F1ED68B329E9B3B9003744F8 /* IGListInteractiveMovingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1ED68AE29E9B3B9003744F8 /* IGListInteractiveMovingTests.m */; }; + F1ED68B529E9B3B9003744F8 /* IGListDebugDescriptionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1ED68AF29E9B3B9003744F8 /* IGListDebugDescriptionTests.m */; }; + F1ED68B729E9B3B9003744F8 /* IGListTransactionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1ED68B029E9B3B9003744F8 /* IGListTransactionTests.m */; }; + F1ED68B929E9B3B9003744F8 /* IGListSingleSectionControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1ED68B129E9B3B9003744F8 /* IGListSingleSectionControllerTests.m */; }; + F1ED68BA29E9B404003744F8 /* IGListInteractiveMovingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1ED68AE29E9B3B9003744F8 /* IGListInteractiveMovingTests.m */; }; + F1ED68BB29E9B40A003744F8 /* IGListGenericSectionControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 29DA5CA21EA7C72400113926 /* IGListGenericSectionControllerTests.m */; }; + F1ED68BC29E9B411003744F8 /* IGListDebuggerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 290DF3761E9323E6009FE456 /* IGListDebuggerTests.m */; }; + F1ED68BD29E9B415003744F8 /* IGListDebugDescriptionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1ED68AF29E9B3B9003744F8 /* IGListDebugDescriptionTests.m */; }; + F1ED68BE29E9B41A003744F8 /* IGListContentInsetTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E8D312DF1FC472A60009FA2F /* IGListContentInsetTests.m */; }; + F1ED68BF29E9B443003744F8 /* IGListTransactionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F1ED68B029E9B3B9003744F8 /* IGListTransactionTests.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -497,7 +507,6 @@ 16B71CE822B0A08300FE96ED /* IGTestInvalidateLayoutDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGTestInvalidateLayoutDataSource.m; sourceTree = ""; }; 16B71CE922B0A08300FE96ED /* IGTestInvalidateLayoutObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IGTestInvalidateLayoutObject.h; sourceTree = ""; }; 16B71CEA22B0A08300FE96ED /* IGTestInvalidateLayoutObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGTestInvalidateLayoutObject.m; sourceTree = ""; }; - 1AB7195278D0BBB5DA88D36F /* Pods_IGListKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_IGListKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 26271C881DAE94E40073E116 /* IGTestSingleNibItemDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IGTestSingleNibItemDataSource.h; sourceTree = ""; }; 26271C891DAE94E40073E116 /* IGTestSingleNibItemDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGTestSingleNibItemDataSource.m; sourceTree = ""; }; 26271C8B1DAE96740073E116 /* IGListSingleNibItemControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListSingleNibItemControllerTests.m; sourceTree = ""; }; @@ -731,8 +740,12 @@ DD3152AC1DE227FA00AC9D2C /* IGListKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IGListKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E56B7B3320A9D7100071010C /* IGListCollectionScrollingTraitsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListCollectionScrollingTraitsTests.m; sourceTree = ""; }; E8D312DF1FC472A60009FA2F /* IGListContentInsetTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IGListContentInsetTests.m; sourceTree = ""; }; - E980179F5E885E417EB20D55 /* Pods_IGListKit_tvOSTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_IGListKit_tvOSTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F1855A4B29BC565600558D18 /* IGListDiffDescriptionStringTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListDiffDescriptionStringTests.m; sourceTree = ""; }; + F1E6302229EA43080060B4D6 /* IGListSectionControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListSectionControllerTests.m; sourceTree = ""; }; + F1ED68AE29E9B3B9003744F8 /* IGListInteractiveMovingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListInteractiveMovingTests.m; sourceTree = ""; }; + F1ED68AF29E9B3B9003744F8 /* IGListDebugDescriptionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListDebugDescriptionTests.m; sourceTree = ""; }; + F1ED68B029E9B3B9003744F8 /* IGListTransactionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListTransactionTests.m; sourceTree = ""; }; + F1ED68B129E9B3B9003744F8 /* IGListSingleSectionControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IGListSingleSectionControllerTests.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -784,7 +797,6 @@ buildActionMask = 2147483647; files = ( 885FE1DD1DC51A0D009CE2B4 /* IGListKit.framework in Frameworks */, - 262373C2015556E71A70FA30 /* Pods_IGListKit_tvOSTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -801,7 +813,6 @@ buildActionMask = 2147483647; files = ( 887D0B401D870D7F009E01F7 /* IGListKit.framework in Frameworks */, - DD468D380BBF350ACE7EA28B /* Pods_IGListKitTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -845,15 +856,6 @@ path = Assets; sourceTree = ""; }; - 41882EBBC340173A8053E3AF /* Frameworks */ = { - isa = PBXGroup; - children = ( - E980179F5E885E417EB20D55 /* Pods_IGListKit_tvOSTests.framework */, - 1AB7195278D0BBB5DA88D36F /* Pods_IGListKitTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 7A02CEC6236150C400B49FAE /* IGListKit */ = { isa = PBXGroup; children = ( @@ -1102,7 +1104,6 @@ 887D0B2C1D870D7E009E01F7 = { isa = PBXGroup; children = ( - 41882EBBC340173A8053E3AF /* Frameworks */, 887D0B371D870D7E009E01F7 /* Products */, 0B3B927E1E08D7F5008390ED /* Source */, 887D0B551D870E1E009E01F7 /* Tests */, @@ -1140,8 +1141,10 @@ 88144EE51D870EDC007C7F66 /* IGListBatchUpdateDataTests.m */, 298DD9CD1E3ADD1400F76F50 /* IGListBindingSectionControllerTests.m */, E56B7B3320A9D7100071010C /* IGListCollectionScrollingTraitsTests.m */, + F1ED68B129E9B3B9003744F8 /* IGListSingleSectionControllerTests.m */, 298DDA231E3B15EE00F76F50 /* IGListCollectionViewLayoutTests.m */, E8D312DF1FC472A60009FA2F /* IGListContentInsetTests.m */, + F1ED68AF29E9B3B9003744F8 /* IGListDebugDescriptionTests.m */, 290DF3761E9323E6009FE456 /* IGListDebuggerTests.m */, F1855A4B29BC565600558D18 /* IGListDiffDescriptionStringTests.m */, 294AC6311DDE4C19002FCE5D /* IGListDiffResultTests.m */, @@ -1149,7 +1152,9 @@ 88144EE81D870EDC007C7F66 /* IGListDiffTests.m */, 88144EE91D870EDC007C7F66 /* IGListDisplayHandlerTests.m */, 29DA5CA21EA7C72400113926 /* IGListGenericSectionControllerTests.m */, + F1ED68AE29E9B3B9003744F8 /* IGListInteractiveMovingTests.m */, 88144EEB1D870EDC007C7F66 /* IGListKitTests-Bridging-Header.h */, + F1E6302229EA43080060B4D6 /* IGListSectionControllerTests.m */, 829D7BA81DD1816400549816 /* IGListSectionMapTests.m */, 26271C8B1DAE96740073E116 /* IGListSingleNibItemControllerTests.m */, 88144EED1D870EDC007C7F66 /* IGListSingleSectionControllerTests.m */, @@ -1157,6 +1162,7 @@ 29DA5CA91EA7D39B00113926 /* IGListTestCase.h */, 29DA5CA61EA7D37000113926 /* IGListTestCase.m */, 29DA5CAA1EA7D3FF00113926 /* IGListTestHelpers.h */, + F1ED68B029E9B3B9003744F8 /* IGListTransactionTests.m */, 88144EEF1D870EDC007C7F66 /* IGListWorkingRangeHandlerTests.m */, 2997D4961DF5FC0B005A5DD2 /* IGReloadDataUpdaterTests.m */, 887D0B571D870E1E009E01F7 /* Info.plist */, @@ -1519,11 +1525,9 @@ isa = PBXNativeTarget; buildConfigurationList = 885FE1EA1DC51A0D009CE2B4 /* Build configuration list for PBXNativeTarget "IGListKit-tvOSTests" */; buildPhases = ( - 9B12CED6C1A4A7B9137C8C52 /* [CP] Check Pods Manifest.lock */, 885FE1D81DC51A0D009CE2B4 /* Sources */, 885FE1D91DC51A0D009CE2B4 /* Frameworks */, 885FE1DA1DC51A0D009CE2B4 /* Resources */, - 1C5FA70E034CFACCF4FD0854 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -1557,11 +1561,9 @@ isa = PBXNativeTarget; buildConfigurationList = 887D0B4D1D870D7F009E01F7 /* Build configuration list for PBXNativeTarget "IGListKitTests" */; buildPhases = ( - 9B9AB53579E3C2BBEEBC3548 /* [CP] Check Pods Manifest.lock */, 887D0B3B1D870D7F009E01F7 /* Sources */, 887D0B3C1D870D7F009E01F7 /* Frameworks */, 887D0B3D1D870D7F009E01F7 /* Resources */, - 21587AA7E74BD876C049E30D /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -1569,8 +1571,6 @@ 887D0B421D870D7F009E01F7 /* PBXTargetDependency */, ); name = IGListKitTests; - packageProductDependencies = ( - ); productName = IGListKitTests; productReference = 887D0B3F1D870D7F009E01F7 /* IGListKitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -1681,8 +1681,6 @@ en, ); mainGroup = 887D0B2C1D870D7E009E01F7; - packageReferences = ( - ); productRefGroup = 887D0B371D870D7E009E01F7 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -1747,78 +1745,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1C5FA70E034CFACCF4FD0854 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-IGListKit-tvOSTests/Pods-IGListKit-tvOSTests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/OCMock-tvOS/OCMock.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-IGListKit-tvOSTests/Pods-IGListKit-tvOSTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 21587AA7E74BD876C049E30D /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-IGListKitTests/Pods-IGListKitTests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/OCMock-iOS/OCMock.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-IGListKitTests/Pods-IGListKitTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 9B12CED6C1A4A7B9137C8C52 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-IGListKit-tvOSTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - 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"; - showEnvVarsInLog = 0; - }; - 9B9AB53579E3C2BBEEBC3548 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-IGListKitTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - 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"; - showEnvVarsInLog = 0; - }; F105D9AE29B7193000B7F361 /* SwiftLint */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -1977,6 +1903,7 @@ 29C474901DDF460500AE68CE /* IGListSectionMapTests.m in Sources */, 29C579321DE0DA8A003A149B /* IGTestStoryboardSupplementarySource.m in Sources */, 298DDA131E3AE3F100F76F50 /* IGTestDiffingDataSource.m in Sources */, + F1ED68B329E9B3B9003744F8 /* IGListInteractiveMovingTests.m in Sources */, 29C5792F1DE0DA8A003A149B /* IGListTestAdapterStoryboardDataSource.m in Sources */, 885FE23B1DC51B86009CE2B4 /* IGListTestUICollectionViewDataSource.m in Sources */, 885FE23D1DC51B86009CE2B4 /* IGTestDelegateController.m in Sources */, @@ -1991,24 +1918,30 @@ 298DDA001E3AE28000F76F50 /* IGTestDiffingObject.m in Sources */, 29C579331DE0DA8A003A149B /* IGTestStoryboardSupplementaryView.m in Sources */, 16B71CF022B0A08400FE96ED /* IGTestInvalidateLayoutObject.m in Sources */, + F1ED68BB29E9B40A003744F8 /* IGListGenericSectionControllerTests.m in Sources */, 16B71CEC22B0A08400FE96ED /* IGTestInvalidateLayoutSectionController.m in Sources */, 2995409F1F588C9500F647CF /* IGTestBindingWithoutDeselectionDelegate.m in Sources */, 885FE2401DC51B86009CE2B4 /* IGTestSingleItemDataSource.m in Sources */, 885FE2451DC51B86009CE2B4 /* IGTestStoryboardCell.m in Sources */, + F1E6302429EA43080060B4D6 /* IGListSectionControllerTests.m in Sources */, 16B71CEE22B0A08400FE96ED /* IGTestInvalidateLayoutDataSource.m in Sources */, 298DD9CF1E3ADD1400F76F50 /* IGListBindingSectionControllerTests.m in Sources */, 885FE22F1DC51B76009CE2B4 /* IGListDiffSwiftTests.swift in Sources */, 885FE23F1DC51B86009CE2B4 /* IGTestObject.m in Sources */, + F1ED68B929E9B3B9003744F8 /* IGListSingleSectionControllerTests.m in Sources */, F1855A4D29BC565600558D18 /* IGListDiffDescriptionStringTests.m in Sources */, 828540511DE40D2D00118B94 /* IGListTestAdapterHorizontalDataSource.m in Sources */, 885FE2371DC51B76009CE2B4 /* IGListWorkingRangeHandlerTests.m in Sources */, 8285404D1DE40C6E00118B94 /* IGListTestHorizontalSection.m in Sources */, 298DDA061E3AE2B000F76F50 /* IGTestNumberBindableCell.m in Sources */, 885FE2381DC51B86009CE2B4 /* IGListTestAdapterDataSource.m in Sources */, + F1ED68B529E9B3B9003744F8 /* IGListDebugDescriptionTests.m in Sources */, 885FE2341DC51B76009CE2B4 /* IGListSingleNibItemControllerTests.m in Sources */, 0B40C5F31E01CB8200378109 /* IGReloadDataUpdaterTests.m in Sources */, 885FE2391DC51B86009CE2B4 /* IGListTestOffsettingLayout.m in Sources */, 29C4748F1DDF460500AE68CE /* IGListDiffResultTests.m in Sources */, + F1ED68B729E9B3B9003744F8 /* IGListTransactionTests.m in Sources */, + F1ED68BE29E9B41A003744F8 /* IGListContentInsetTests.m in Sources */, 885FE2421DC51B86009CE2B4 /* IGTestSingleStoryboardItemDataSource.m in Sources */, 885FE2301DC51B76009CE2B4 /* IGListDiffTests.m in Sources */, 885FE22E1DC51B76009CE2B4 /* IGListBatchUpdateDataTests.m in Sources */, @@ -2027,6 +1960,7 @@ 6A9EB3621F841E5D0070C572 /* IGTestSingleWithoutDeselectionDelegate.m in Sources */, 885FE2461DC51B86009CE2B4 /* IGTestSupplementarySource.m in Sources */, 885FE2431DC51B86009CE2B4 /* IGTestStoryboardViewController.m in Sources */, + F1ED68BC29E9B411003744F8 /* IGListDebuggerTests.m in Sources */, 885FE23A1DC51B86009CE2B4 /* IGListTestSection.m in Sources */, 29C579301DE0DA8A003A149B /* IGListTestStoryboardSection.m in Sources */, 885FE23E1DC51B86009CE2B4 /* IGTestDelegateDataSource.m in Sources */, @@ -2086,6 +2020,7 @@ 298DDA141E3AE3F300F76F50 /* IGTestDiffingDataSource.m in Sources */, 8240C7F51DC2D99300B3AAE7 /* IGTestStoryboardSupplementarySource.m in Sources */, 88144F1B1D870EDC007C7F66 /* IGTestSingleItemDataSource.m in Sources */, + F1E6302329EA43080060B4D6 /* IGListSectionControllerTests.m in Sources */, 88144F171D870EDC007C7F66 /* IGTestCell.m in Sources */, 298DDA241E3B15EE00F76F50 /* IGListCollectionViewLayoutTests.m in Sources */, 821BC4C01DB8C9D500172ED0 /* IGListSingleStoryboardItemControllerTests.m in Sources */, @@ -2095,7 +2030,9 @@ 298DDA011E3AE28000F76F50 /* IGTestDiffingObject.m in Sources */, 88144F131D870EDC007C7F66 /* IGListTestAdapterDataSource.m in Sources */, 88144F071D870EDC007C7F66 /* IGListAdapterE2ETests.m in Sources */, + F1ED68BA29E9B404003744F8 /* IGListInteractiveMovingTests.m in Sources */, 88144F1A1D870EDC007C7F66 /* IGTestObject.m in Sources */, + F1ED68BF29E9B443003744F8 /* IGListTransactionTests.m in Sources */, 298DD9CE1E3ADD1400F76F50 /* IGListBindingSectionControllerTests.m in Sources */, 88144F0B1D870EDC007C7F66 /* IGListDiffSwiftTests.swift in Sources */, 88144F191D870EDC007C7F66 /* IGTestDelegateDataSource.m in Sources */, @@ -2110,6 +2047,7 @@ 2997D4971DF5FC0B005A5DD2 /* IGReloadDataUpdaterTests.m in Sources */, 13DF01771FA1000E0092A320 /* IGTestReorderableSection.m in Sources */, 829D7BAA1DD1819000549816 /* IGListSectionMapTests.m in Sources */, + F1ED68BD29E9B415003744F8 /* IGListDebugDescriptionTests.m in Sources */, E56B7B3420A9D7100071010C /* IGListCollectionScrollingTraitsTests.m in Sources */, 16B71CEB22B0A08400FE96ED /* IGTestInvalidateLayoutSectionController.m in Sources */, 29C5792E1DE0DA89003A149B /* IGTestNibSupplementaryView.m in Sources */, @@ -2602,6 +2540,11 @@ buildSettings = { CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + "NS_BLOCK_ASSERTIONS=1", + ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_SHADOW = YES; INFOPLIST_FILE = Tests/Info.plist; @@ -2946,6 +2889,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + "NS_BLOCK_ASSERTIONS=1", + ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_SHADOW = YES; INFOPLIST_FILE = Tests/Info.plist; @@ -2996,6 +2944,11 @@ CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + "NS_BLOCK_ASSERTIONS=1", + ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; GCC_WARN_SHADOW = YES; INFOPLIST_FILE = Tests/Info.plist; diff --git a/Tests/IGListDebugDescriptionTests.m b/Tests/IGListDebugDescriptionTests.m new file mode 100644 index 00000000..9811b21c --- /dev/null +++ b/Tests/IGListDebugDescriptionTests.m @@ -0,0 +1,112 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +#import + +#import "IGListAdapter+DebugDescription.h" +#import "IGListAdapterUpdater+DebugDescription.h" +#import "IGListAdapterUpdaterInternal.h" +#import "IGListAdapterInternal.h" +#import "IGListBatchUpdateData+DebugDescription.h" +#import "IGListMoveIndexInternal.h" +#import "IGListMoveIndexPathINternal.h" +#import "IGListTestAdapterDataSource.h" +#import "IGListTestCase.h" +#import "IGListUpdateTransactable.h" +#import "IGTestDelegateDataSource.h" +#import "IGTestObject.h" + +@interface IGListAdapterUpdater (DebugDescriptionTests) +- (void)setTransaction:(id)transaction; +@end + +@interface IGListBindingSectionController (DebugDescriptionTests) +- (void)setViewModels:(NSArray> *)viewModels; +@end + + +@interface IGListDebugDescriptionTests : IGListTestCase + +@end + +@implementation IGListDebugDescriptionTests + +- (void)setUp { + self.dataSource = [IGListTestAdapterDataSource new]; + [super setUp]; +} + +- (void)test_withListAdapter_thatDebugDescriptionIsValid { + self.dataSource.objects = @[@1, @2, @3]; + + IGListAdapter *adapter = [[IGListAdapter alloc] initWithUpdater:[IGListAdapterUpdater new] viewController:nil]; + adapter.collectionView = self.collectionView; + adapter.dataSource = self.dataSource; + + [adapter.registeredCellIdentifiers addObject:@"IGCellIdentifier"]; + [adapter.registeredNibNames addObject:@"IGCellNibName"]; + [adapter.registeredSupplementaryViewIdentifiers addObject:@"IGSupplementaryViewIdentifier"]; + [adapter.registeredSupplementaryViewNibNames addObject:@"IGSupplementaryNibName"]; + + IGListBindingSectionController *bindingSectionController = [[IGListBindingSectionController alloc] init]; + bindingSectionController.viewModels = @[[[IGTestObject alloc] initWithKey:@"Key" value:@(1)]]; + + adapter.previousSectionMap = [[IGListSectionMap alloc] initWithMapTable:[NSMapTable strongToStrongObjectsMapTable]]; + [adapter.previousSectionMap updateWithObjects:@[@1] sectionControllers:@[bindingSectionController]]; + + XCTAssertTrue(adapter.debugDescriptionLines.count > 0); + XCTAssertTrue(adapter.debugDescription.length > 0); +} + +- (void)test_withListAdapterUpdater_thatDebugDescriptionIsValid { + id transactionMock = [OCMockObject mockForProtocol:@protocol(IGListUpdateTransactable)]; + + IGListAdapterUpdater *updater = [IGListAdapterUpdater new]; + [updater setTransaction:transactionMock]; + + [[[transactionMock expect] andReturnValue:@(IGListBatchUpdateStateIdle)] state]; + XCTAssertTrue(updater.debugDescriptionLines.count > 0); + + [[[transactionMock expect] andReturnValue:@(IGListBatchUpdateStateQueuedBatchUpdate)] state]; + XCTAssertTrue(updater.debugDescriptionLines.count > 0); + + [[[transactionMock expect] andReturnValue:@(IGListBatchUpdateStateExecutingBatchUpdateBlock)] state]; + XCTAssertTrue(updater.debugDescriptionLines.count > 0); + + [[[transactionMock expect] andReturnValue:@(IGListBatchUpdateStateExecutedBatchUpdateBlock)] state]; + XCTAssertTrue(updater.debugDescriptionLines.count > 0); +} + +- (void)test_withBatchUpdateData_thatDebugDescriptionIsValid { + NSMutableIndexSet *insertSections = [NSMutableIndexSet indexSet]; + [insertSections addIndex:0]; + [insertSections addIndex:1]; + + NSIndexSet *deleteSections = [NSIndexSet indexSetWithIndex:5]; + IGListMoveIndex *moveSections = [[IGListMoveIndex alloc] initWithFrom:3 to:4]; + NSIndexPath *insertIndexPaths = [NSIndexPath indexPathForItem:0 inSection:0]; + NSIndexPath *deleteIndexPaths = [NSIndexPath indexPathForItem:0 inSection:0]; + IGListMoveIndexPath *moveIndexPaths = [[IGListMoveIndexPath alloc] initWithFrom:[NSIndexPath indexPathForItem:0 inSection:6] + to:[NSIndexPath indexPathForItem:1 inSection:6]]; + + IGListBatchUpdateData *data = [[IGListBatchUpdateData alloc] initWithInsertSections:insertSections + deleteSections:deleteSections + moveSections:[NSSet setWithObject:moveSections] + insertIndexPaths:@[insertIndexPaths] + deleteIndexPaths:@[deleteIndexPaths] + updateIndexPaths:@[] + moveIndexPaths:@[moveIndexPaths]]; + + XCTAssertTrue(data.debugDescriptionLines.count > 0); +} + +@end + diff --git a/Tests/IGListInteractiveMovingTests.m b/Tests/IGListInteractiveMovingTests.m new file mode 100644 index 00000000..eb7c763b --- /dev/null +++ b/Tests/IGListInteractiveMovingTests.m @@ -0,0 +1,130 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +#import "IGTestObject.h" +#import "IGListTestCase.h" +#import "IGTestDelegateDataSource.h" +#import "UICollectionViewLayout+InteractiveReordering.h" + +@interface UICollectionViewLayout (Tests) + +- (void)ig_invalidateAccessoryElementsWithSupplementaryIndexPaths:(NSDictionary *> *)supplementaryIndexPaths + decorationIndexPaths:(NSDictionary *> *)decorationIndexPaths + inContext:(UICollectionViewLayoutInvalidationContext *)context; + +@end + +@interface IGListInteractiveMovingTests : IGListTestCase + +@end + +@implementation IGListInteractiveMovingTests + +- (void)setUp { + self.workingRangeSize = 2; + self.dataSource = [IGTestDelegateDataSource new]; + [super setUp]; +} + +- (void)test_withDetachedLayout_whenQueryingForInteractiveMovingItem_thatOriginalIndexPathIsReturned { + UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new]; + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:1 inSection:1]; + NSIndexPath *targetIndexPath = [layout targetIndexPathForInteractivelyMovingItem:indexPath + withPosition:CGPointMake(100, 100)]; + XCTAssertEqual(indexPath.item, targetIndexPath.item); + XCTAssertEqual(indexPath.section, targetIndexPath.section); +} + +- (void)test_withDetachedLayout_thatCleanupInvalidationContextExitsEarly { + UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new]; + NSIndexPath *sourceIndexPath = [NSIndexPath indexPathForItem:1 inSection:1]; + NSIndexPath *targetIndexPath = [NSIndexPath indexPathForItem:1 inSection:1]; + UICollectionViewLayoutInvalidationContext *context = [layout invalidationContextForInteractivelyMovingItems:@[targetIndexPath] + withTargetPosition:CGPointMake(0, 0) + previousIndexPaths:@[sourceIndexPath] + previousPosition:CGPointZero]; + XCTAssertTrue(context.invalidatedItemIndexPaths.count > 0); +} + +- (void)test_whenCollectionViewIsSet_thatTargetIndexPathIsValid { + [self setupWithObjects:@[genTestObject(@1, @2)]]; + UICollectionViewLayout *layout = self.collectionView.collectionViewLayout; + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:1 inSection:1]; + NSIndexPath *targetIndexPath = [layout targetIndexPathForInteractivelyMovingItem:indexPath + withPosition:CGPointMake(100, 100)]; + XCTAssertEqual(indexPath.item, targetIndexPath.item); + XCTAssertEqual(indexPath.section, targetIndexPath.section); +} + +- (void)test_whenCollectionViewIsSet_thatInvalidationContextForInteractivelyMovingItemsPasses { + [self setupWithObjects:@[genTestObject(@1, @2), genTestObject(@4, @5)]]; + UICollectionViewLayout *layout = self.collectionView.collectionViewLayout; + NSIndexPath *sourceIndexPath = [NSIndexPath indexPathForItem:1 inSection:1]; + NSIndexPath *targetIndexPath = [NSIndexPath indexPathForItem:1 inSection:1]; + UICollectionViewLayoutInvalidationContext *context = [layout invalidationContextForInteractivelyMovingItems:@[targetIndexPath] + withTargetPosition:CGPointMake(0, 0) + previousIndexPaths:@[sourceIndexPath] + previousPosition:CGPointZero]; + XCTAssertTrue(context.invalidatedItemIndexPaths.count > 0); +} + +- (void)test_whenCollectionViewIsSet_andIndexPathIsInsideBounds_thatValidationContextForEndingInteractiveMovementOfItemsToFinalIndexPathsPasses { + [self setupWithObjects:@[genTestObject(@1, @2), genTestObject(@4, @5), genTestObject(@6, @7)]]; + UICollectionViewLayout *layout = self.collectionView.collectionViewLayout; + NSIndexPath *sourceIndexPath = [NSIndexPath indexPathForItem:1 inSection:0]; + NSIndexPath *targetIndexPath = [NSIndexPath indexPathForItem:1 inSection:0]; + UICollectionViewLayoutInvalidationContext *context = [layout invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths:@[sourceIndexPath] + previousIndexPaths:@[targetIndexPath] + movementCancelled:NO]; + XCTAssertTrue(context.invalidatedItemIndexPaths.count > 0); +} + +- (void)test_whenCollectionViewIsSet_andIndexPathIsOutOfBounds_thatValidationContextForEndingInteractiveMovementOfItemsToFinalIndexPathsPasses { + [self setupWithObjects:@[genTestObject(@1, @2), genTestObject(@4, @5), genTestObject(@6, @7)]]; + UICollectionViewLayout *layout = self.collectionView.collectionViewLayout; + NSIndexPath *sourceIndexPath = [NSIndexPath indexPathForItem:8 inSection:2]; + NSIndexPath *targetIndexPath = [NSIndexPath indexPathForItem:8 inSection:2]; + UICollectionViewLayoutInvalidationContext *context = [layout invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths:@[sourceIndexPath] + previousIndexPaths:@[targetIndexPath] + movementCancelled:NO]; + XCTAssertTrue(context.invalidatedItemIndexPaths.count == 0); +} + +- (void)test_whenCollectionViewIsSetWithBaseLayout_andIndexPathIsOutOfBounds_thatValidationContextForEndingInteractiveMovementOfItemsToFinalIndexPathsPasses { + [self setupWithObjects:@[genTestObject(@1, @2), genTestObject(@4, @5), genTestObject(@6, @7)]]; + UICollectionViewLayout *layout = [UICollectionViewLayout new]; + [layout ig_hijackLayoutInteractiveReorderingMethodForAdapter:self.adapter]; + self.collectionView.collectionViewLayout = layout; + NSIndexPath *sourceIndexPath = [NSIndexPath indexPathForItem:8 inSection:2]; + NSIndexPath *targetIndexPath = [NSIndexPath indexPathForItem:8 inSection:2]; + UICollectionViewLayoutInvalidationContext *context = [layout invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths:@[sourceIndexPath] + previousIndexPaths:@[targetIndexPath] + movementCancelled:NO]; + XCTAssertTrue(context.invalidatedItemIndexPaths.count == 0); +} + +- (void)test_withInvalidationContext_thatSupplementaryAndDecorationIndexPathsAreInvalidated { + UICollectionViewLayout *layout = [UICollectionViewLayout new]; + + NSDictionary *supplementaryDictionary = @{@"supplementary": @[[NSIndexPath indexPathForItem:1 inSection:1]]}; + NSDictionary *decorationDictionary = @{@"decoration": @[[NSIndexPath indexPathForItem:2 inSection:2]]}; + + id contextMock = [OCMockObject mockForClass:[UICollectionViewLayoutInvalidationContext class]]; + [[contextMock expect] invalidateSupplementaryElementsOfKind:@"supplementary" atIndexPaths:supplementaryDictionary[@"supplementary"]]; + [[contextMock expect] invalidateDecorationElementsOfKind:@"decoration" atIndexPaths:decorationDictionary[@"decoration"]]; + + [layout ig_invalidateAccessoryElementsWithSupplementaryIndexPaths:supplementaryDictionary + decorationIndexPaths:decorationDictionary + inContext:contextMock]; + [contextMock verify]; +} + +@end diff --git a/Tests/IGListSectionControllerTests.m b/Tests/IGListSectionControllerTests.m new file mode 100644 index 00000000..288c83af --- /dev/null +++ b/Tests/IGListSectionControllerTests.m @@ -0,0 +1,42 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import + +@interface IGListSectionControllerTests : XCTestCase + +@end + +@implementation IGListSectionControllerTests + +- (void)test_withBaseSectionContoller_thatDefaultValuesAreCorrect { + NSObject *object = [NSObject new]; + IGListSectionController *sectionController = [[IGListSectionController alloc] init]; + XCTAssertNotNil(sectionController); + + XCTAssertEqual([sectionController numberOfItems], 1); + XCTAssertTrue(CGSizeEqualToSize([sectionController sizeForItemAtIndex:0], CGSizeZero)); + XCTAssertTrue([sectionController shouldSelectItemAtIndex:0]); + XCTAssertTrue([sectionController shouldDeselectItemAtIndex:0]); + XCTAssertFalse([sectionController canMoveItemAtIndex:0]); + + [sectionController didUpdateToObject:object]; + + [sectionController didSelectItemAtIndex:0]; + [sectionController didDeselectItemAtIndex:0]; + [sectionController didHighlightItemAtIndex:0]; + [sectionController didUnhighlightItemAtIndex:0]; + + @try { + [sectionController cellForItemAtIndex:0]; + [sectionController moveObjectFromIndex:0 toIndex:1]; + } @catch (NSException *exception) {} +} + +@end diff --git a/Tests/IGListTransactionTests.m b/Tests/IGListTransactionTests.m new file mode 100644 index 00000000..25346051 --- /dev/null +++ b/Tests/IGListTransactionTests.m @@ -0,0 +1,170 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import "IGListAdapterUpdater.h" +#import "IGListBatchUpdateTransaction.h" +#import "IGListDataSourceChangeTransaction.h" +#import "IGListReloadTransaction.h" +#import "IGListTestUICollectionViewDataSource.h" +#import "IGListTransitionData.h" + +@interface IGListBatchUpdateTransaction (Tests) + +- (NSInteger)mode; +- (void)setSectionData:(IGListTransitionData *)sectionData; + +@end + +@interface IGListTransactionTests : XCTestCase { + IGListUpdateTransactationConfig _config; +} + +@property (nonatomic, strong) UIWindow *window; +@property (nonatomic, strong) UICollectionView *collectionView; +@property (nonatomic, strong) IGListTestUICollectionViewDataSource *dataSource; +@property (nonatomic, strong) IGListTransitionDataApplyBlock applySectionDataBlock; + +@end + +@implementation IGListTransactionTests + +- (IGListCollectionViewBlock)collectionViewBlock { + return ^UICollectionView *{ return self.collectionView; }; +} + +- (IGListTransitionDataBlock)dataBlockFromObjects:(NSArray *)fromObjects toObjects:(NSArray *)toObjects { + return ^IGListTransitionData *{ + return [[IGListTransitionData alloc] initFromObjects:fromObjects toObjects:toObjects toSectionControllers:@[]]; + }; +} + +- (IGListBatchUpdateTransaction *)makeBatchUpdateTransaction { + return [[IGListBatchUpdateTransaction alloc] initWithCollectionViewBlock:[self collectionViewBlock] + updater:[IGListAdapterUpdater new] + delegate:nil + config:_config + animated:NO + sectionDataBlock:[self dataBlockFromObjects:@[] toObjects:@[@0]] + applySectionDataBlock:self.applySectionDataBlock + itemUpdateBlocks:@[] + completionBlocks:@[]]; +} + +- (IGListDataSourceChangeTransaction *)makeDataSourceChangeTransaction { + return [[IGListDataSourceChangeTransaction alloc] initWithChangeBlock:^{} + itemUpdateBlocks:@[] + completionBlocks:@[]]; +} + +- (IGListReloadTransaction *)makeReloadTransaction { + return [[IGListReloadTransaction alloc] initWithCollectionViewBlock:[self collectionViewBlock] + updater:[IGListAdapterUpdater new] + delegate:nil + reloadBlock:^{} + itemUpdateBlocks:@[] + completionBlocks:@[]]; +} + +- (void)setUp { + [super setUp]; + + self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:self.window.frame collectionViewLayout:layout]; + [self.window addSubview:self.collectionView]; + + self.dataSource = [[IGListTestUICollectionViewDataSource alloc] initWithCollectionView:self.collectionView]; + __weak __typeof__(self) weakSelf = self; + self.applySectionDataBlock = ^(IGListTransitionData *data) { + weakSelf.dataSource.sections = data.toObjects; + }; + + memset(&_config, 0, sizeof(IGListUpdateTransactationConfig)); +} + +- (void)tearDown { + [super tearDown]; + self.collectionView = nil; + self.dataSource = nil; + self.window = nil; + memset(&_config, 0, sizeof(IGListUpdateTransactationConfig)); +} + +- (void)test_withBatchUpdateTransaction_thatNilCollectionViewBailsCorrectly { + self.collectionView = nil; + IGListBatchUpdateTransaction *batchUpdateTransaction = [self makeBatchUpdateTransaction]; + [batchUpdateTransaction begin]; + XCTAssertEqual(batchUpdateTransaction.state, IGListBatchUpdateStateIdle); +} + +- (void)test_withBatchUpdateTransaction_thatCancellingTransactionMultipleTimesPerformsCorrectly { + _config.allowsBackgroundDiffing = YES; + IGListBatchUpdateTransaction *batchUpdateTransaction = [self makeBatchUpdateTransaction]; + [batchUpdateTransaction begin]; + [batchUpdateTransaction cancel]; + [batchUpdateTransaction cancel]; + XCTAssertEqual(batchUpdateTransaction.mode, 2); +} + +- (void)test_withBatchUpdateTransaction_thatMismatchedCollectionViewStateIsCaught { + self.dataSource.sections = @[[IGSectionObject sectionWithObjects:@[]]]; + IGListBatchUpdateTransaction *batchUpdateTransaction = [self makeBatchUpdateTransaction]; + + @try { + [batchUpdateTransaction begin]; + } @catch (NSException *exception) {} +} + +- (void)test_withBatchUpdateTransaction_thatCancellingTransactionBetweenRunLoopsIsCaptured { + _config.allowsBackgroundDiffing = YES; + IGListBatchUpdateTransaction *batchUpdateTransaction = [self makeBatchUpdateTransaction]; + [batchUpdateTransaction begin]; + [batchUpdateTransaction cancel]; + + XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)]; + dispatch_async(dispatch_get_main_queue(), ^{ + XCTAssertEqual(batchUpdateTransaction.mode, 2); // Check mode is cancelled + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:30 handler:nil]; +} + +- (void)test_withDataSourceChangeTransaction_thatAllStubbedMethodsNoOpCorrectly { + IGListDataSourceChangeTransaction *transaction = [self makeDataSourceChangeTransaction]; + + XCTAssertFalse([transaction cancel]); + + NSIndexPath *from = [NSIndexPath indexPathForItem:0 inSection:0]; + NSIndexPath *to = [NSIndexPath indexPathForItem:0 inSection:1]; + + [transaction insertItemsAtIndexPaths:@[]]; + [transaction deleteItemsAtIndexPaths:@[]]; + [transaction moveItemFromIndexPath:from toIndexPath:to]; + [transaction reloadItemFromIndexPath:from toIndexPath:to]; + [transaction reloadSections:[NSIndexSet indexSet]]; +} + +- (void)test_withReloadTransaction_thatAllStubbedMethodsNoOpCorrectly { + IGListReloadTransaction *transaction = [self makeReloadTransaction]; + + XCTAssertFalse([transaction cancel]); + + NSIndexPath *from = [NSIndexPath indexPathForItem:0 inSection:0]; + NSIndexPath *to = [NSIndexPath indexPathForItem:0 inSection:1]; + + [transaction insertItemsAtIndexPaths:@[]]; + [transaction deleteItemsAtIndexPaths:@[]]; + [transaction moveItemFromIndexPath:from toIndexPath:to]; + [transaction reloadItemFromIndexPath:from toIndexPath:to]; + [transaction reloadSections:[NSIndexSet indexSet]]; +} + +@end