diff --git a/Model/GBMethodsProvider.m b/Model/GBMethodsProvider.m index d8ba5dc1..5fa3ef79 100644 --- a/Model/GBMethodsProvider.m +++ b/Model/GBMethodsProvider.m @@ -158,19 +158,30 @@ - (void)mergeDataFromMethodsProvider:(GBMethodsProvider *)source { // If a method with the same selector is found while merging from source, we should check if the type also matches. If so, we can merge the data from the source's method. However if the type doesn't match, we should ignore the method alltogether (ussually this is due to custom property implementation). We should probably deal with this scenario more inteligently, but it seems it works... if (!source || source == self) return; GBLogDebug(@"%@: Merging methods from %@...", _parent, source->_parent); + + // First merge all existing methods regardless of section and prepare the list of all new methods. + NSMutableArray *newMethods = [NSMutableArray array]; + [source.methods enumerateObjectsUsingBlock:^(GBMethodData *sourceMethod, NSUInteger idx, BOOL *stop) { + GBMethodData *existingMethod = [self methodBySelector:sourceMethod.methodSelector]; + if (!existingMethod) { + [newMethods addObject:sourceMethod]; + return; + } + [existingMethod mergeDataFromObject:sourceMethod]; + }]; + if ([newMethods count] == 0) return; + + // Second merge all sections; only use sections for methods that were not registered yet! Note that we need to remember current section so that we restore it later on. GBMethodSectionData *previousSection = _registeringSection; [source.sections enumerateObjectsUsingBlock:^(GBMethodSectionData *sourceSection, NSUInteger idx, BOOL *stop) { - GBMethodSectionData *existingSection = [_sectionsByNames objectForKey:sourceSection.sectionName]; - if (!existingSection) existingSection = [self registerSectionWithName:sourceSection.sectionName]; - _registeringSection = existingSection; - - [sourceSection.methods enumerateObjectsUsingBlock:^(GBMethodData *sourceMethod, NSUInteger idx, BOOL *stop) { - GBMethodData *existingMethod = [_methodsBySelectors objectForKey:sourceMethod.methodSelector]; - if (existingMethod) { - if (existingMethod.methodType == sourceMethod.methodType) [existingMethod mergeDataFromObject:sourceMethod]; + [newMethods enumerateObjectsUsingBlock:^(GBMethodData *sourceMethod, NSUInteger idx, BOOL *stop) { + if ([sourceSection.methods containsObject:sourceMethod]) { + GBMethodSectionData *existingSection = [_sectionsByNames objectForKey:sourceSection.sectionName]; + if (!existingSection) existingSection = [self registerSectionWithName:sourceSection.sectionName]; + _registeringSection = existingSection; + [self registerMethod:sourceMethod]; return; } - [self registerMethod:sourceMethod]; }]; }]; _registeringSection = previousSection; diff --git a/Testing/GBMethodsProviderTesting.m b/Testing/GBMethodsProviderTesting.m index 55b41d79..0e176e26 100644 --- a/Testing/GBMethodsProviderTesting.m +++ b/Testing/GBMethodsProviderTesting.m @@ -439,6 +439,43 @@ - (void)testMergeDataFromObjectsProvider_shouldPreserveCurrentSectionForNewMetho assertThat([[section.methods objectAtIndex:0] methodSelector], is(@"m2:")); } +- (void)testMergeDataFromObjectsProvider_shouldUseOriginalSectionForExistingMethodsEvenIfFoundInDifferentSection { + // setup + GBMethodsProvider *original = [[GBMethodsProvider alloc] initWithParentObject:self]; + [original registerSectionWithName:@"Section1"]; + [original registerMethod:[GBTestObjectsRegistry instanceMethodWithNames:@"m1", nil]]; + GBMethodsProvider *source = [[GBMethodsProvider alloc] initWithParentObject:self]; + [source registerSectionWithName:@"Section2"]; + [source registerMethod:[GBTestObjectsRegistry instanceMethodWithNames:@"m1", nil]]; + // execute + [original mergeDataFromMethodsProvider:source]; + // verify + NSArray *sections = [original sections]; + assertThatInteger([sections count], equalToInteger(1)); + GBMethodSectionData *section = [sections objectAtIndex:0]; + assertThat([section sectionName], is(@"Section1")); + assertThatInteger([section.methods count], equalToInteger(1)); + assertThat([[section.methods objectAtIndex:0] methodSelector], is(@"m1:")); +} + +- (void)testMergeDataFromObjectsProvider_shouldUseOriginalSectionForExistingMethodsFromDefaultSection { + // setup + GBMethodsProvider *original = [[GBMethodsProvider alloc] initWithParentObject:self]; + [original registerSectionWithName:@"Section1"]; + [original registerMethod:[GBTestObjectsRegistry instanceMethodWithNames:@"m1", nil]]; + GBMethodsProvider *source = [[GBMethodsProvider alloc] initWithParentObject:self]; + [source registerMethod:[GBTestObjectsRegistry instanceMethodWithNames:@"m1", nil]]; + // execute + [original mergeDataFromMethodsProvider:source]; + // verify + NSArray *sections = [original sections]; + assertThatInteger([sections count], equalToInteger(1)); + GBMethodSectionData *section = [sections objectAtIndex:0]; + assertThat([section sectionName], is(@"Section1")); + assertThatInteger([section.methods count], equalToInteger(1)); + assertThat([[section.methods objectAtIndex:0] methodSelector], is(@"m1:")); +} + #pragma mark Unregistering handling - (void)testUnregisterMethod_shouldRemoveMethodFromMethods {