/* * Copyright (c) Meta Platforms, Inc. and affiliates. * 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. */ #import "ResourceTestCase.h" static void generateCombinations( NSDictionary *> *matchesByResource, NSArray *keys, NSMutableDictionary *result, NSUInteger index, NSMutableSet *> *combinations) { if (index == keys.count) { if (result.count == keys.count) { [combinations addObject:[result copy]]; } return; } NSString *key = keys[index]; NSArray *matches = matchesByResource[key] ?: @[]; if (!matches.count) { generateCombinations( matchesByResource, keys, result, index + 1, combinations); return; } for (NSString *match in matches) { result[key] = match; generateCombinations( matchesByResource, keys, result, index + 1, combinations); [result removeObjectForKey:key]; } } @implementation ResourceTestCase + (NSArray *)bundles { return @[ [NSBundle mainBundle], [NSBundle bundleForClass:self] ]; } + (NSArray *)directories { return @[]; } + (NSDictionary *)predicates { return @{}; } + (NSDictionary *)dynamicTestsForResources: (NSDictionary *)resources { return @{}; } + (NSDictionary *)dynamicTests { NSMutableDictionary *tests = [NSMutableDictionary new]; NSMutableSet *> *combinations = [NSMutableSet new]; NSDictionary *predicates = [self predicates]; NSArray *sortedKeys = [predicates.allKeys sortedArrayUsingSelector:@selector(compare:)]; if (predicates.count == 0) return @{}; for (NSBundle *bundle in self.bundles) { for (NSString *directory in self.directories) { NSArray *resourceURLs = [bundle URLsForResourcesWithExtension:nil subdirectory:directory]; if (!resourceURLs.count) { continue; }; NSMutableDictionary *> *matchesByResource = [NSMutableDictionary new]; for (NSURL *url in resourceURLs) { NSString *file = url.lastPathComponent; NSString *fullPath = url.path; for (NSString *key in sortedKeys) { if (predicates[key](file)) { matchesByResource[key] = matchesByResource[key] ?: [NSMutableArray new]; [matchesByResource[key] addObject:fullPath]; } } } NSMutableDictionary *result = [NSMutableDictionary new]; generateCombinations( matchesByResource, sortedKeys, result, 0, combinations); } } for (NSDictionary *resources in combinations) { NSMutableString *resourceString = [NSMutableString new]; NSCharacterSet *punctuationSet = [NSCharacterSet punctuationCharacterSet]; for (NSString *key in sortedKeys) { NSString *lastComponent = [resources[key] lastPathComponent]; NSString *cleanedComponent = [[lastComponent componentsSeparatedByCharactersInSet:punctuationSet] componentsJoinedByString:@"_"]; [resourceString appendFormat:@"_%@", cleanedComponent]; } NSDictionary *resourceTests = [self dynamicTestsForResources:resources]; [resourceTests enumerateKeysAndObjectsUsingBlock:^( NSString *testName, void (^testBlock)(XCTestCase *), BOOL *stop) { tests[[testName stringByAppendingString:resourceString]] = testBlock; }]; } return tests; } @end