diff --git a/ComponentKit.xcodeproj/project.pbxproj b/ComponentKit.xcodeproj/project.pbxproj index 6798e76e5..dd947437f 100644 --- a/ComponentKit.xcodeproj/project.pbxproj +++ b/ComponentKit.xcodeproj/project.pbxproj @@ -728,6 +728,13 @@ D0B47D9E1CBDA9AC00BB33CE /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0B47D871CBDA24900BB33CE /* UIKit.framework */; }; D0B47D9F1CBDA9B600BB33CE /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0B47D8B1CBDA25E00BB33CE /* CoreGraphics.framework */; }; D0B47DA01CBDA9C200BB33CE /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0B47D8B1CBDA25E00BB33CE /* CoreGraphics.framework */; }; + D63F9F8120AAF31A003F3887 /* CKIndexSetDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = D63F9F7620AAF31A003F3887 /* CKIndexSetDescription.h */; settings = {ATTRIBUTES = (Private, ); }; }; + D63F9F8320AAF487003F3887 /* CKIndexSetDescription.mm in Sources */ = {isa = PBXBuildFile; fileRef = D63F9F8220AAF487003F3887 /* CKIndexSetDescription.mm */; }; + D6A2652120AC333F00B7B499 /* CKIndexSetDescription.mm in Sources */ = {isa = PBXBuildFile; fileRef = D63F9F8220AAF487003F3887 /* CKIndexSetDescription.mm */; }; + D6A2652F20AC5B2100B7B499 /* NSIndexSetExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = D6B0AE0020AAFB1000A31FDF /* NSIndexSetExtensions.mm */; }; + D6B0ADF420AAF88C00A31FDF /* CKIndexSetDescriptionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = D6B0ADF320AAF88C00A31FDF /* CKIndexSetDescriptionTests.mm */; }; + D6B0AE0120AAFB1000A31FDF /* NSIndexSetExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D6B0ADFF20AAFB1000A31FDF /* NSIndexSetExtensions.h */; }; + D6B0AE0220AAFB1000A31FDF /* NSIndexSetExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = D6B0AE0020AAFB1000A31FDF /* NSIndexSetExtensions.mm */; }; EB14A3411D8267DF0004BECF /* CKAutoSizedImageComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = EB14A33F1D8267DF0004BECF /* CKAutoSizedImageComponent.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB14A3421D8267DF0004BECF /* CKAutoSizedImageComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = EB14A33F1D8267DF0004BECF /* CKAutoSizedImageComponent.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB14A3431D8267DF0004BECF /* CKAutoSizedImageComponent.mm in Sources */ = {isa = PBXBuildFile; fileRef = EB14A3401D8267DF0004BECF /* CKAutoSizedImageComponent.mm */; }; @@ -1286,6 +1293,11 @@ D0B47D8B1CBDA25E00BB33CE /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; D0B47D971CBDA97400BB33CE /* CKComponentSnapshotTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKComponentSnapshotTestCase.h; sourceTree = ""; }; D0B47D981CBDA97400BB33CE /* CKComponentSnapshotTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = CKComponentSnapshotTestCase.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + D63F9F7620AAF31A003F3887 /* CKIndexSetDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKIndexSetDescription.h; sourceTree = ""; }; + D63F9F8220AAF487003F3887 /* CKIndexSetDescription.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CKIndexSetDescription.mm; sourceTree = ""; }; + D6B0ADF320AAF88C00A31FDF /* CKIndexSetDescriptionTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CKIndexSetDescriptionTests.mm; sourceTree = ""; }; + D6B0ADFF20AAFB1000A31FDF /* NSIndexSetExtensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSIndexSetExtensions.h; sourceTree = ""; }; + D6B0AE0020AAFB1000A31FDF /* NSIndexSetExtensions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NSIndexSetExtensions.mm; sourceTree = ""; }; D6B7E9BF1FCF4C6500FAD4E0 /* CKComponentScopeFrameInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKComponentScopeFrameInternal.h; sourceTree = ""; }; EB14A33F1D8267DF0004BECF /* CKAutoSizedImageComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKAutoSizedImageComponent.h; sourceTree = ""; }; EB14A3401D8267DF0004BECF /* CKAutoSizedImageComponent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CKAutoSizedImageComponent.mm; sourceTree = ""; }; @@ -1466,6 +1478,8 @@ A273801E1AFD144100E6F222 /* CKTestActionComponent.mm */, 035FD04A1D83218100D28351 /* CKTestRunLoopRunning.h */, 035FD04B1D83218100D28351 /* CKTestRunLoopRunning.mm */, + D6B0ADFF20AAFB1000A31FDF /* NSIndexSetExtensions.h */, + D6B0AE0020AAFB1000A31FDF /* NSIndexSetExtensions.mm */, ); path = ComponentKitTestHelpers; sourceTree = ""; @@ -1524,6 +1538,7 @@ B342DC601AC23EA900ACAC53 /* CKComponentViewReuseTests.mm */, B342DC611AC23EA900ACAC53 /* CKDimensionTests.mm */, 7F80A4E61F63128B00242503 /* CKFlexboxComponentTests.mm */, + D6B0ADF320AAF88C00A31FDF /* CKIndexSetDescriptionTests.mm */, B342DC621AC23EA900ACAC53 /* CKOptimisticViewMutationsTests.mm */, A22FE3041AF2CF0C00EC30B8 /* CKStateExposingComponent.h */, A22FE3051AF2CF0C00EC30B8 /* CKStateExposingComponent.mm */, @@ -1839,6 +1854,8 @@ D0B47B361CBD926700BB33CE /* CKComponentDebugController.mm */, D0B47B371CBD926700BB33CE /* CKComponentHierarchyDebugHelper.h */, D0B47B381CBD926700BB33CE /* CKComponentHierarchyDebugHelper.mm */, + D63F9F7620AAF31A003F3887 /* CKIndexSetDescription.h */, + D63F9F8220AAF487003F3887 /* CKIndexSetDescription.mm */, D0B47B391CBD926700BB33CE /* ComponentKit+QuickLook.mm */, ); path = Debug; @@ -2291,6 +2308,7 @@ buildActionMask = 2147483647; files = ( 7F98F58C1F67F2F600436978 /* CKLifecycleTestComponent.h in Headers */, + D6B0AE0120AAFB1000A31FDF /* NSIndexSetExtensions.h in Headers */, A27380341AFD172500E6F222 /* CKTestActionComponent.h in Headers */, 7FA099141F66F36800B81EED /* CKComponentLifecycleTestHelper.h in Headers */, ); @@ -2322,6 +2340,7 @@ D0B47D161CBD948E00BB33CE /* CKComponentAnnouncerBase.h in Headers */, D0B47CF61CBD948E00BB33CE /* CKComponentLayout.h in Headers */, D0B47D3F1CBD948E00BB33CE /* CKDataSourceAppliedChanges.h in Headers */, + D63F9F8120AAF31A003F3887 /* CKIndexSetDescription.h in Headers */, D0B47D3C1CBD948E00BB33CE /* CKStatefulViewComponentController.h in Headers */, D0B47CEF1CBD948E00BB33CE /* CKComponent.h in Headers */, D0B47CF31CBD948E00BB33CE /* CKComponentController.h in Headers */, @@ -2846,6 +2865,7 @@ 7F27E2C11F69CC0F00573E14 /* CKLifecycleTestComponent.mm in Sources */, 03A98A6B1D2B2BFD00C5BAC2 /* CKTestActionComponent.mm in Sources */, 7F27E2CF1F69E3FC00573E14 /* CKComponentLifecycleTestHelper.mm in Sources */, + D6A2652F20AC5B2100B7B499 /* NSIndexSetExtensions.mm in Sources */, 2D8270F71E3F72F1008C1A26 /* CKTestRunLoopRunning.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2954,6 +2974,7 @@ 03B8B4BF1D2A346F00EDFF59 /* CKTextKitAttributes.mm in Sources */, 03B8B4C01D2A346F00EDFF59 /* CKTextKitContext.mm in Sources */, 03B8B4C11D2A346F00EDFF59 /* CKTextKitEntityAttribute.m in Sources */, + D6A2652120AC333F00B7B499 /* CKIndexSetDescription.mm in Sources */, 03B8B4C21D2A346F00EDFF59 /* CKTextKitRenderer+Positioning.mm in Sources */, 03B8B4C31D2A346F00EDFF59 /* CKTextKitRenderer+TextChecking.mm in Sources */, 03B8B4C41D2A346F00EDFF59 /* CKTextKitRenderer.mm in Sources */, @@ -3030,6 +3051,7 @@ 7F98F58D1F67F2F600436978 /* CKLifecycleTestComponent.mm in Sources */, A273801F1AFD144100E6F222 /* CKTestActionComponent.mm in Sources */, 2D8270F61E3F72DE008C1A26 /* CKTestRunLoopRunning.mm in Sources */, + D6B0AE0220AAFB1000A31FDF /* NSIndexSetExtensions.mm in Sources */, 7FA099151F66F36800B81EED /* CKComponentLifecycleTestHelper.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3060,6 +3082,7 @@ A25C02D11AF0767700F4C864 /* CKDataSourceChangesetModificationTests.mm in Sources */, 23FEC5AA203B31230068E09D /* CKTreeNodeTests.mm in Sources */, A27436FA1AE9589700832359 /* CKDataSourceStateTestHelpers.mm in Sources */, + D6B0ADF420AAF88C00A31FDF /* CKIndexSetDescriptionTests.mm in Sources */, 51EDD905207E79C400892C35 /* CKBuildAndLayoutComponentTests.mm in Sources */, 39B090BF1B71645600A5470B /* CKComponentDataSourceAttachControllerTests.mm in Sources */, B342DC741AC23EA900ACAC53 /* CKComponentHostingViewTestModel.mm in Sources */, @@ -3161,6 +3184,7 @@ D0B47C971CBD943400BB33CE /* ComponentLayoutContext.mm in Sources */, D0B47C981CBD943400BB33CE /* ComponentViewManager.mm in Sources */, D0B47C991CBD943400BB33CE /* ComponentViewReuseUtilities.mm in Sources */, + D63F9F8320AAF487003F3887 /* CKIndexSetDescription.mm in Sources */, D0B47C9A1CBD943400BB33CE /* CKComponentScope.mm in Sources */, D0B47C9B1CBD943400BB33CE /* CKComponentScopeFrame.mm in Sources */, D0B47C9C1CBD943400BB33CE /* CKComponentScopeHandle.mm in Sources */, diff --git a/ComponentKit/Debug/CKIndexSetDescription.h b/ComponentKit/Debug/CKIndexSetDescription.h new file mode 100644 index 000000000..30a6e16e6 --- /dev/null +++ b/ComponentKit/Debug/CKIndexSetDescription.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +namespace CK { + auto indexSetDescription(NSIndexSet *const is, NSString *const title = @"", const int indent = 0) -> NSString *; +} diff --git a/ComponentKit/Debug/CKIndexSetDescription.mm b/ComponentKit/Debug/CKIndexSetDescription.mm new file mode 100644 index 000000000..356395913 --- /dev/null +++ b/ComponentKit/Debug/CKIndexSetDescription.mm @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "CKIndexSetDescription.h" + +auto CK::indexSetDescription(NSIndexSet *const is, NSString *const title, const int indent) -> NSString * +{ + auto rangeStrings = static_cast *>([NSMutableArray array]); + [is enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull) { + const auto rangeStr = range.length > 1 ? + [NSString stringWithFormat:@"%lu–%lu", (unsigned long)range.location, (unsigned long)NSMaxRange(range) - 1] : + [NSString stringWithFormat:@"%lu", (unsigned long)range.location]; + [rangeStrings addObject:rangeStr]; + }]; + const auto description = [rangeStrings componentsJoinedByString:@", "]; + const auto titleIndentStr = [@"" stringByPaddingToLength:indent withString:@" " startingAtIndex:0]; + return title.length > 0 ? [NSString stringWithFormat:@"%@%@: %@", titleIndentStr, title, description] : description; +} diff --git a/ComponentKit/TransactionalDataSources/Common/Internal/CKDataSourceChangesetModification.mm b/ComponentKit/TransactionalDataSources/Common/Internal/CKDataSourceChangesetModification.mm index c7f505df0..4ff29b3f3 100644 --- a/ComponentKit/TransactionalDataSources/Common/Internal/CKDataSourceChangesetModification.mm +++ b/ComponentKit/TransactionalDataSources/Common/Internal/CKDataSourceChangesetModification.mm @@ -28,6 +28,7 @@ #import "CKComponentScopeRoot.h" #import "CKComponentScopeRootFactory.h" #import "CKDataSourceModificationHelper.h" +#import "CKIndexSetDescription.h" @implementation CKDataSourceChangesetModification { @@ -177,8 +178,8 @@ - (CKDataSourceChange *)changeFromState:(CKDataSourceState *)oldState const auto sectionItems = (NSArray *)[newSections objectAtIndex:sectionIt.first]; const auto invalidIndexes = CK::invalidIndexesForInsertionInArray(sectionItems, indexes); if (invalidIndexes.count > 0) { - CKCFatal(@"Invalid indexes: %@ for range: %@ in section: %lu. Changeset: %@, user info: %@", - invalidIndexes, + CKCFatal(@"%@ for range: %@ in section: %lu. Changeset: %@, user info: %@", + CK::indexSetDescription(invalidIndexes, @"Invalid indexes", 0), NSStringFromRange({0, sectionItems.count}), (unsigned long)sectionIt.first, _changeset, diff --git a/ComponentKitTestHelpers/NSIndexSetExtensions.h b/ComponentKitTestHelpers/NSIndexSetExtensions.h new file mode 100644 index 000000000..357a3edf1 --- /dev/null +++ b/ComponentKitTestHelpers/NSIndexSetExtensions.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#import + +namespace CK { + auto makeIndexSet(const std::vector v) -> NSIndexSet *; +} diff --git a/ComponentKitTestHelpers/NSIndexSetExtensions.mm b/ComponentKitTestHelpers/NSIndexSetExtensions.mm new file mode 100644 index 000000000..f57f28c57 --- /dev/null +++ b/ComponentKitTestHelpers/NSIndexSetExtensions.mm @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "NSIndexSetExtensions.h" + +auto CK::makeIndexSet(const std::vector v) -> NSIndexSet * +{ + auto r = [NSMutableIndexSet new]; + for (const auto &i : v) { + [r addIndex:i]; + } + return r; +} diff --git a/ComponentKitTests/CKIndexSetDescriptionTests.mm b/ComponentKitTests/CKIndexSetDescriptionTests.mm new file mode 100644 index 000000000..aee042424 --- /dev/null +++ b/ComponentKitTests/CKIndexSetDescriptionTests.mm @@ -0,0 +1,56 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#import + +#import +#import + +@interface CKIndexSetDescriptionTests : XCTestCase +@end + +@implementation CKIndexSetDescriptionTests + +- (void)test_WhenIndexSetIsEmpty_ReturnsEmptyString +{ + XCTAssertEqualObjects(CK::indexSetDescription([NSIndexSet new]), @""); +} + +- (void)test_WhenIndexSetHasOneIndex_ReturnsTheIndexAsString +{ + XCTAssertEqualObjects(CK::indexSetDescription(CK::makeIndexSet({1})), @"1"); +} + +- (void)test_WhenIndexSetHasDisjointIndexes_ReturnsIndexesSeparatedByComma +{ + XCTAssertEqualObjects(CK::indexSetDescription(CK::makeIndexSet({1, 3})), @"1, 3"); +} + +- (void)test_WhenIndexSetHasAdjacentIndexes_CombinesThemIntoOneRange +{ + XCTAssertEqualObjects(CK::indexSetDescription(CK::makeIndexSet({1, 2, 3})), @"1–3"); +} + +@end + +@interface CKIndexSetDescriptionTests_WithTitleAndIndent : XCTestCase +@end + +@implementation CKIndexSetDescriptionTests_WithTitleAndIndent + +- (void)test_WhenIndentIsNonZero_AddsIndentBeforeTitle +{ + const auto is = CK::makeIndexSet({1, 2, 4}); + const auto expectedDescription = @" Removed Sections: 1–2, 4"; + + XCTAssertEqualObjects(CK::indexSetDescription(is, @"Removed Sections", 2), expectedDescription); +} + +- (void)test_WhenIndentIsZero_AddsOnlyTitle +{ + const auto is = CK::makeIndexSet({1, 2, 4}); + const auto expectedDescription = @"Removed Sections: 1–2, 4"; + + XCTAssertEqualObjects(CK::indexSetDescription(is, @"Removed Sections"), expectedDescription); +} + +@end diff --git a/ComponentKitTests/TransactionalDataSource/CKDataSourceChangesetModificationTests.mm b/ComponentKitTests/TransactionalDataSource/CKDataSourceChangesetModificationTests.mm index ceb9131a9..70da3ec82 100644 --- a/ComponentKitTests/TransactionalDataSource/CKDataSourceChangesetModificationTests.mm +++ b/ComponentKitTests/TransactionalDataSource/CKDataSourceChangesetModificationTests.mm @@ -21,6 +21,7 @@ #import #import #import +#import #import "CKDataSourceStateTestHelpers.h" @@ -284,18 +285,9 @@ - (void)test_WhenFirstInsertionLocationIsGreaterThanCount_IsNotValid - (void)test_WhenOtherInsertionLocationIsGreaterThanCount_IsNotValid { const auto array = @[@"one"]; - const auto indexes = makeIndexSet({1, 3}); + const auto indexes = CK::makeIndexSet({1, 3}); - XCTAssertEqualObjects(CK::invalidIndexesForInsertionInArray(array, indexes), makeIndexSet({3})); -} - -static auto makeIndexSet(const std::vector v) -> NSIndexSet * -{ - auto r = [NSMutableIndexSet new]; - for (const auto &i : v) { - [r addIndex:i]; - } - return r; + XCTAssertEqualObjects(CK::invalidIndexesForInsertionInArray(array, indexes), CK::makeIndexSet({3})); } @end