import Foundation import TestHelpers import Testing @testable import SwiftLintBuiltInRules @testable import SwiftLintFramework // swiftlint:disable file_length private extension Configuration { func contains(rule _: T.Type) -> Bool { rules.contains { $0 is T } } } @Suite(.rulesRegistered) struct MultipleConfigurationsTests { // swiftlint:disable:this type_body_length // MARK: - Rules Merging @Test(.workingDirectory(Constants.Dir.level0)) func merge() { let config0Merge2 = Constants.Config._0.merged(withChild: Constants.Config._2) #expect(!Constants.Config._0.contains(rule: ForceCastRule.self)) #expect(Constants.Config._2.contains(rule: ForceCastRule.self)) #expect(!config0Merge2.contains(rule: ForceCastRule.self)) #expect(Constants.Config._0.contains(rule: TodoRule.self)) #expect(Constants.Config._2.contains(rule: TodoRule.self)) #expect(config0Merge2.contains(rule: TodoRule.self)) #expect(!Constants.Config._3.contains(rule: TodoRule.self)) #expect(!config0Merge2.merged(withChild: Constants.Config._3).contains(rule: TodoRule.self)) } // MARK: - Merging Aspects @Test func warningThresholdMerging() { func configuration(forWarningThreshold warningThreshold: Int?) -> Configuration { Configuration( warningThreshold: warningThreshold, reporter: XcodeReporter.identifier ) } #expect(configuration(forWarningThreshold: 3) .merged(withChild: configuration(forWarningThreshold: 2)).warningThreshold == 2) #expect(configuration(forWarningThreshold: nil) .merged(withChild: configuration(forWarningThreshold: 2)).warningThreshold == 2) #expect(configuration(forWarningThreshold: 3) .merged(withChild: configuration(forWarningThreshold: nil)).warningThreshold == 3) #expect(configuration(forWarningThreshold: nil) .merged(withChild: configuration(forWarningThreshold: nil)).warningThreshold == nil) } @Test func onlyRulesMerging() { let baseConfiguration = Configuration( rulesMode: .defaultConfiguration( disabled: [], optIn: [ ForceTryRule.identifier, ForceCastRule.identifier, ] ) ) let onlyConfiguration = Configuration(rulesMode: .onlyConfiguration([TodoRule.identifier])) #expect(baseConfiguration.contains(rule: TodoRule.self)) #expect(onlyConfiguration.rules.count == 1) #expect(onlyConfiguration.rules.first is TodoRule) let mergedConfiguration1 = baseConfiguration.merged(withChild: onlyConfiguration) #expect(mergedConfiguration1.rules.count == 1) #expect(mergedConfiguration1.rules.first is TodoRule) // Also test the other way around let mergedConfiguration2 = onlyConfiguration.merged(withChild: baseConfiguration) #expect(mergedConfiguration2.rules.count == 3) // 2 opt-ins + 1 from the only rules #expect(mergedConfiguration2.contains(rule: TodoRule.self)) #expect(mergedConfiguration2.contains(rule: ForceCastRule.self)) #expect(mergedConfiguration2.contains(rule: ForceTryRule.self)) } @Test func onlyRuleMerging() { let ruleIdentifier = TodoRule.identifier let onlyRuleConfiguration = Configuration.onlyRuleConfiguration(ruleIdentifier) let emptyDefaultConfiguration = Configuration.emptyDefaultConfiguration() let mergedConfiguration1 = onlyRuleConfiguration.merged(withChild: emptyDefaultConfiguration) #expect(mergedConfiguration1.rules.count == 1) #expect(mergedConfiguration1.rules.first is TodoRule) let disabledDefaultConfiguration = Configuration.disabledDefaultConfiguration(ruleIdentifier) let mergedConfiguration2 = onlyRuleConfiguration.merged(withChild: disabledDefaultConfiguration) #expect(mergedConfiguration2.rules.isEmpty) let enabledOnlyConfiguration = Configuration.enabledOnlyConfiguration(ForceTryRule.identifier) let mergedConfiguration3 = onlyRuleConfiguration.merged(withChild: enabledOnlyConfiguration) #expect(mergedConfiguration3.rules.count == 1) #expect(mergedConfiguration3.rules.first is TodoRule) } @Test func customRulesMerging() { let mergedConfiguration = Constants.Config._0CustomRules.merged( withChild: Constants.Config._2CustomRules, rootDirectory: URL.cwd ) guard let mergedCustomRules = mergedConfiguration.rules.customRules else { Issue.record("Custom rules are expected to be present") return } #expect( mergedCustomRules.configuration.customRuleConfigurations.contains { $0.identifier == "no_abc" } ) #expect( mergedCustomRules.configuration.customRuleConfigurations.contains { $0.identifier == "no_abcd" } ) } @Test func mergingAllowsDisablingParentsCustomRules() { let mergedConfiguration = Constants.Config._0CustomRules.merged( withChild: Constants.Config._2CustomRulesDisabled, rootDirectory: URL.cwd ) guard let mergedCustomRules = mergedConfiguration.rules.customRules else { Issue.record("Custom rules are expected to be present") return } #expect(!mergedCustomRules.configuration.customRuleConfigurations.contains { $0.identifier == "no_abc" }) #expect(mergedCustomRules.configuration.customRuleConfigurations.contains { $0.identifier == "no_abcd" }) } @Test func customRulesMergingWithOnlyRulesCase1() { // The base configuration is in only rules mode // The child configuration is in the default rules mode // => all custom rules should be considered let mergedConfiguration = Constants.Config._0CustomRulesOnly.merged( withChild: Constants.Config._2CustomRules, rootDirectory: URL.cwd ) guard let mergedCustomRules = mergedConfiguration.rules.customRules else { Issue.record("Custom rules are expected to be present") return } #expect( mergedCustomRules.configuration.customRuleConfigurations.contains { $0.identifier == "no_abc" } ) #expect( mergedCustomRules.configuration.customRuleConfigurations.contains { $0.identifier == "no_abcd" } ) } @Test func customRulesMergingWithOnlyRulesCase2() { // The base configuration is in only rules mode // The child configuration is in the only rules mode // => only the custom rules from the child configuration should be considered // (because custom rules from base configuration would require explicit mention as one of the `only_rules`) let mergedConfiguration = Constants.Config._0CustomRulesOnly.merged( withChild: Constants.Config._2CustomRulesOnly, rootDirectory: URL.cwd ) guard let mergedCustomRules = mergedConfiguration.rules.customRules else { Issue.record("Custom rules are expected to be present") return } #expect(!mergedCustomRules.configuration.customRuleConfigurations.contains { $0.identifier == "no_abc" }) #expect(mergedCustomRules.configuration.customRuleConfigurations.contains { $0.identifier == "no_abcd" }) } @Test func customRulesReconfiguration() { // Custom Rule severity gets reconfigured to "error" let mergedConfiguration = Constants.Config._0CustomRulesOnly.merged( withChild: Constants.Config._2CustomRulesReconfig, rootDirectory: URL.cwd ) guard let mergedCustomRules = mergedConfiguration.rules.customRules else { Issue.record("Custom rules are expected to be present") return } #expect( mergedCustomRules.configuration.customRuleConfigurations.filter { $0.identifier == "no_abc" }.count == 1 ) guard let customRule = (mergedCustomRules.configuration.customRuleConfigurations.first { $0.identifier == "no_abc" }) else { Issue.record("Custom rule is expected to be present") return } #expect(customRule.severityConfiguration.severity == .error) } // MARK: - Nested Configurations @Test(.workingDirectory(Constants.Dir.level0)) func level0() { #expect( Constants.Config._0.configuration(for: SwiftLintFile(path: Constants.Swift._0)!) == Constants.Config._0 ) } @Test(.workingDirectory(Constants.Dir.level0)) func level1() { #expect( Constants.Config._0.configuration(for: SwiftLintFile(path: Constants.Swift._1)!) == Constants.Config._0 ) } @Test func level2() { let config = Constants.Config._0.configuration(for: SwiftLintFile(path: Constants.Swift._2)!) var config2 = Constants.Config._2 config2.fileGraph = Configuration.FileGraph(rootDirectory: Constants.Dir.level2) #expect(config == Constants.Config._0.merged(withChild: config2, rootDirectory: config.rootDirectory)) } @Test func level3() { let config = Constants.Config._0.configuration(for: SwiftLintFile(path: Constants.Swift._3)!) var config3 = Constants.Config._3 config3.fileGraph = Configuration.FileGraph(rootDirectory: Constants.Dir.level3) #expect(config == Constants.Config._0.merged(withChild: config3, rootDirectory: config.rootDirectory)) } @Test func nestedConfigurationForOnePathPassedIn() { // If a path to one or more configuration files is specified, nested configurations should be ignored let config = Configuration(configurationFiles: [Constants.Yml._0]) #expect(config.configuration(for: SwiftLintFile(path: Constants.Swift._3)!) == config) } @Test func parentConfigIsIgnoredAsNestedConfiguration() { // If a configuration has already been used to build the main config, // it should not again be regarded as a nested config #expect( Constants.Config.nested.configuration(for: SwiftLintFile(path: Constants.Swift.nestedSub)!) == Constants.Config.nested ) } // MARK: - Child & Parent Configs @Test( .disabled(if: isRunningWithBazel), arguments: [Constants.Dir.childConfigTest1, Constants.Dir.childConfigTest2], ) func validChildConfig(_ path: URL) { CurrentWorkingDirectory.$url.withValue(path) { assertEqualExceptForFileGraph( Configuration(configurationFiles: ["main.yml".url()]), Configuration(configurationFiles: ["expected.yml".url()]) ) } } @Test(arguments: [Constants.Dir.parentConfigTest1, Constants.Dir.parentConfigTest2]) func validParentConfig(_ path: URL) { CurrentWorkingDirectory.$url.withValue(path) { assertEqualExceptForFileGraph( Configuration(configurationFiles: ["main.yml".url()]), Configuration(configurationFiles: ["expected.yml".url()]) ) } } @Test( .disabled(if: isRunningWithBazel), arguments: [Constants.Dir.childConfigTest1, Constants.Dir.childConfigTest2], ) func commandLineChildConfigs(_ path: URL) { CurrentWorkingDirectory.$url.withValue(path) { assertEqualExceptForFileGraph( Configuration( configurationFiles: [ "main.yml".url(), "child1.yml".url(), "child2.yml".url(), ] ), Configuration(configurationFiles: ["expected.yml".url()]) ) } } @Test( arguments: [ Constants.Dir.childConfigCycle1, Constants.Dir.childConfigCycle2, Constants.Dir.childConfigCycle3, Constants.Dir.parentConfigCycle1, Constants.Dir.parentConfigCycle2, Constants.Dir.parentConfigCycle3, ], ) func configCycleDetection(_ path: URL) { CurrentWorkingDirectory.$url.withValue(path) { // If the cycle is properly detected, the config should equal the default config. #expect(Configuration(configurationFiles: []) == Configuration()) } } @Test(.workingDirectory(Constants.Dir.childConfigCycle4)) func commandLineConfigsCycleDetection() { // If the cycle is properly detected, the config should equal the default config. assertEqualExceptForFileGraph( Configuration( configurationFiles: ["main.yml".url(), "child.yml".url()], useDefaultConfigOnFailure: true ), Configuration() ) } @Test func parentChildOptInAndDisable() { struct TestCase: Equatable { let optedInInParent: Bool let disabledInParent: Bool let optedInInChild: Bool let disabledInChild: Bool let isEnabled: Bool var message: String { "optedInInParent = \(optedInInParent) " + "disabledInParent = \(disabledInParent) " + "optedInInChild = \(optedInInChild) " + "disabledInChild = \(disabledInChild)" } } let testCases: [TestCase] = [ // swiftlint:disable line_length TestCase(optedInInParent: false, disabledInParent: false, optedInInChild: false, disabledInChild: false, isEnabled: false), TestCase(optedInInParent: true, disabledInParent: false, optedInInChild: false, disabledInChild: false, isEnabled: true), TestCase(optedInInParent: false, disabledInParent: true, optedInInChild: false, disabledInChild: false, isEnabled: false), TestCase(optedInInParent: true, disabledInParent: true, optedInInChild: false, disabledInChild: false, isEnabled: false), TestCase(optedInInParent: false, disabledInParent: false, optedInInChild: true, disabledInChild: false, isEnabled: true), TestCase(optedInInParent: true, disabledInParent: false, optedInInChild: true, disabledInChild: false, isEnabled: true), TestCase(optedInInParent: false, disabledInParent: true, optedInInChild: true, disabledInChild: false, isEnabled: true), TestCase(optedInInParent: true, disabledInParent: true, optedInInChild: true, disabledInChild: false, isEnabled: true), TestCase(optedInInParent: false, disabledInParent: false, optedInInChild: false, disabledInChild: true, isEnabled: false), TestCase(optedInInParent: true, disabledInParent: false, optedInInChild: false, disabledInChild: true, isEnabled: false), TestCase(optedInInParent: false, disabledInParent: true, optedInInChild: false, disabledInChild: true, isEnabled: false), TestCase(optedInInParent: true, disabledInParent: true, optedInInChild: false, disabledInChild: true, isEnabled: false), TestCase(optedInInParent: false, disabledInParent: false, optedInInChild: true, disabledInChild: true, isEnabled: false), TestCase(optedInInParent: true, disabledInParent: false, optedInInChild: true, disabledInChild: true, isEnabled: false), TestCase(optedInInParent: false, disabledInParent: true, optedInInChild: true, disabledInChild: true, isEnabled: false), TestCase(optedInInParent: true, disabledInParent: true, optedInInChild: true, disabledInChild: true, isEnabled: false), // swiftlint:enable line_length ] #expect(testCases.unique.count == 4 * 4) let ruleType = ImplicitReturnRule.self #expect((ruleType as Any) is any OptInRule.Type) let ruleIdentifier = ruleType.identifier for testCase in testCases { let parentConfiguration = Configuration(rulesMode: .defaultConfiguration( disabled: testCase.disabledInParent ? [ruleIdentifier] : [], optIn: testCase.optedInInParent ? [ruleIdentifier] : [] )) let childConfiguration = Configuration(rulesMode: .defaultConfiguration( disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: testCase.optedInInChild ? [ruleIdentifier] : [] )) let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration) let isEnabled = mergedConfiguration.contains(rule: ruleType) #expect(isEnabled == testCase.isEnabled, Comment(rawValue: testCase.message)) } } @Test func parentChildDisableForDefaultRule() { struct TestCase: Equatable { let disabledInParent: Bool let disabledInChild: Bool let isEnabled: Bool var message: String { "disabledInParent = \(disabledInParent) disabledInChild = \(disabledInChild)" } } let testCases: [TestCase] = [ TestCase(disabledInParent: false, disabledInChild: false, isEnabled: true), TestCase(disabledInParent: true, disabledInChild: false, isEnabled: false), TestCase(disabledInParent: false, disabledInChild: true, isEnabled: false), TestCase(disabledInParent: true, disabledInChild: true, isEnabled: false), ] #expect(testCases.unique.count == 2 * 2) let ruleType = BlanketDisableCommandRule.self #expect(!(ruleType is any OptInRule.Type)) let ruleIdentifier = ruleType.identifier for testCase in testCases { let parentConfiguration = Configuration( rulesMode: .defaultConfiguration(disabled: testCase.disabledInParent ? [ruleIdentifier] : [], optIn: []) ) let childConfiguration = Configuration( rulesMode: .defaultConfiguration(disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: []) ) let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration) let isEnabled = mergedConfiguration.contains(rule: ruleType) #expect(isEnabled == testCase.isEnabled, Comment(rawValue: testCase.message)) } } @Test func parentOnlyRulesAndChildOptInAndDisabled() { struct TestCase: Equatable { let optedInInChild: Bool let disabledInChild: Bool let isEnabled: Bool var message: String { "optedInInChild = \(optedInInChild) disabledInChild = \(disabledInChild)" } } let testCases: [TestCase] = [ TestCase(optedInInChild: false, disabledInChild: false, isEnabled: true), TestCase(optedInInChild: true, disabledInChild: false, isEnabled: true), TestCase(optedInInChild: false, disabledInChild: true, isEnabled: false), TestCase(optedInInChild: true, disabledInChild: true, isEnabled: false), ] #expect(testCases.unique.count == 2 * 2) let ruleType = ImplicitReturnRule.self #expect((ruleType as Any) is any OptInRule.Type) let ruleIdentifier = ruleType.identifier let parentConfiguration = Configuration(rulesMode: .onlyConfiguration([ruleIdentifier])) for testCase in testCases { let childConfiguration = Configuration(rulesMode: .defaultConfiguration( disabled: testCase.disabledInChild ? [ruleIdentifier] : [], optIn: testCase.optedInInChild ? [ruleIdentifier] : [] )) let mergedConfiguration = parentConfiguration.merged(withChild: childConfiguration) let isEnabled = mergedConfiguration.contains(rule: ruleType) #expect(isEnabled == testCase.isEnabled, Comment(rawValue: testCase.message)) } } // MARK: Warnings about configurations for disabled rules @Test func defaultConfigurationDisabledRuleWarnings() { let optInRuleType = ImplicitReturnRule.self #expect((optInRuleType as Any) is any OptInRule.Type) testDefaultConfigurationDisabledRuleWarnings(for: optInRuleType) let defaultRuleType = BlockBasedKVORule.self #expect(!((defaultRuleType as Any) is any OptInRule.Type)) testDefaultConfigurationDisabledRuleWarnings(for: defaultRuleType) } private func testDefaultConfigurationDisabledRuleWarnings(for ruleType: any Rule.Type) { let ruleIdentifier = ruleType.identifier let parentConfigurations = [ nil, Configuration.emptyDefaultConfiguration(), Configuration.optInDefaultConfiguration(ruleIdentifier), Configuration.optInDisabledDefaultConfiguration(ruleIdentifier), Configuration.disabledDefaultConfiguration(ruleIdentifier), Configuration.emptyOnlyConfiguration(), Configuration.enabledOnlyConfiguration(ruleIdentifier), Configuration.allEnabledConfiguration(), ] let configurations = [ Configuration(rulesMode: .defaultConfiguration(disabled: [], optIn: [])), Configuration(rulesMode: .defaultConfiguration(disabled: [], optIn: [ruleIdentifier])), Configuration(rulesMode: .defaultConfiguration(disabled: [ruleIdentifier], optIn: [ruleIdentifier])), Configuration(rulesMode: .defaultConfiguration(disabled: [ruleIdentifier], optIn: [])), ] for parentConfiguration in parentConfigurations { for configuration in configurations { testParentConfiguration(parentConfiguration, configuration: configuration, ruleType: ruleType) } } } private func testParentConfiguration( _ parentConfiguration: Configuration?, configuration: Configuration, ruleType: any Rule.Type ) { guard case let .defaultConfiguration(disabledRules, optInRules) = configuration.rulesMode else { Issue.record("Configuration rulesMode was not the default") return } let mergedConfiguration = parentConfiguration?.merged(withChild: configuration) ?? configuration let isEnabled = mergedConfiguration.contains(rule: ruleType) let issue = Configuration.validateConfiguredRuleIsEnabled( parentConfiguration: parentConfiguration, disabledRules: disabledRules, optInRules: optInRules, ruleType: ruleType ) #expect(isEnabled == (issue == nil)) guard let issue else { return } let ruleIdentifier = ruleType.identifier guard disabledRules.isEmpty, optInRules.isEmpty else { #expect(issue == Issue.ruleDisabledInDisabledRules(ruleID: ruleIdentifier)) return } if parentConfiguration == nil || parentConfiguration == Configuration.emptyDefaultConfiguration() { #expect(issue == Issue.ruleNotEnabledInOptInRules(ruleID: ruleIdentifier)) } else if parentConfiguration == Configuration.emptyOnlyConfiguration() { if ruleType is any OptInRule.Type { #expect(issue == Issue.ruleNotEnabledInOptInRules(ruleID: ruleIdentifier)) } else { #expect(issue == Issue.ruleNotEnabledInParentOnlyRules(ruleID: ruleIdentifier)) } } else if parentConfiguration == Configuration.optInDisabledDefaultConfiguration(ruleIdentifier) || parentConfiguration == Configuration.disabledDefaultConfiguration(ruleIdentifier) { #expect(issue == Issue.ruleDisabledInParentConfiguration(ruleID: ruleIdentifier)) } } @Test func onlyConfigurationDisabledRulesWarnings() { let optInRuleType = ImplicitReturnRule.self #expect((optInRuleType as Any) is any OptInRule.Type) testOnlyConfigurationDisabledRulesWarnings(ruleType: optInRuleType) let defaultRuleType = BlockBasedKVORule.self #expect(!((defaultRuleType as Any) is any OptInRule.Type)) testOnlyConfigurationDisabledRulesWarnings(ruleType: defaultRuleType) } private func testOnlyConfigurationDisabledRulesWarnings(ruleType: any Rule.Type) { let issue = Configuration.validateConfiguredRuleIsEnabled(onlyRules: [], ruleType: ruleType) #expect(issue == Issue.ruleNotPresentInOnlyRules(ruleID: ruleType.identifier)) #expect( Configuration.validateConfiguredRuleIsEnabled(onlyRules: [ruleType.identifier], ruleType: ruleType) == nil ) } // MARK: - Remote Configs @Test(.temporaryDirectory(withFixture: Constants.Dir.remoteConfigChild)) func validRemoteChildConfig() { let mockedNetworkResults = [ "https://www.mock.com": """ included: - Test/Test1/Test/Test - Test/Test2/Test/Test """, ] let remoteConfig = Configuration.FileGraph.FilePath.$mockedNetworkResults.withValue(mockedNetworkResults) { Configuration(configurationFiles: ["main.yml".url()]) } assertEqualExceptForFileGraph( remoteConfig, Configuration(configurationFiles: ["expected.yml".url()]) ) } @Test(.temporaryDirectory(withFixture: Constants.Dir.remoteConfigParent)) func validRemoteParentConfig() { let mockedNetworkResults = [ "https://www.mock.com": """ included: - Test/Test1 - Test/Test2 excluded: - Test/Test1/Test - Test/Test2/Test line_length: 80 """, ] let remoteConfig = Configuration.FileGraph.FilePath.$mockedNetworkResults.withValue(mockedNetworkResults) { Configuration(configurationFiles: ["main.yml".url()]) } assertEqualExceptForFileGraph( remoteConfig, Configuration(configurationFiles: ["expected.yml".url()]) ) } @Test(.temporaryDirectory(withFixture: Constants.Dir.remoteConfigLocalRef)) func remoteConfigNotAllowedToReferenceLocalConfig() { let mockedNetworkResults = [ "https://www.mock.com": """ line_length: 60 child_config: child.yml """, ] let remoteConfig = Configuration.FileGraph.FilePath.$mockedNetworkResults.withValue(mockedNetworkResults) { Configuration(configurationFiles: []) // Not specifying a file means the .swiftlint.yml will be used. } // If the remote file is not allowed to reference a local file, the config should equal the default config. #expect(remoteConfig == Configuration()) } @Test(.temporaryDirectory(withFixture: Constants.Dir.remoteConfigCycle)) func remoteConfigCycleDetection() { let mockedNetworkResults = [ "https://www.mock.com": """ child_config: https://www.mock.com """, ] let remoteConfig = Configuration.FileGraph.FilePath.$mockedNetworkResults.withValue(mockedNetworkResults) { Configuration(configurationFiles: []) // Not specifying a file means the .swiftlint.yml will be used. } // If the cycle is properly detected, the config should equal the default config. #expect(remoteConfig == Configuration()) } // MARK: - Helpers /// This helper function checks whether two configurations are equal except for their file graph. /// This is needed to test a child/parent merged config against an expected config. func assertEqualExceptForFileGraph(_ configuration1: Configuration, _ configuration2: Configuration) { #expect( configuration1.rulesWrapper.disabledRuleIdentifiers == configuration2.rulesWrapper.disabledRuleIdentifiers ) #expect( configuration1.rules.map { type(of: $0).identifier } == configuration2.rules.map { type(of: $0).identifier } ) #expect( Set(configuration1.rulesWrapper.allRulesWrapped.map { $0.rule.createConfigurationDescription().oneLiner() }) == Set(configuration2.rulesWrapper.allRulesWrapped.map { $0.rule.createConfigurationDescription().oneLiner() }) ) #expect(configuration1.includedPaths.map(\.path).sorted() == configuration2.includedPaths.map(\.path).sorted()) #expect(configuration1.excludedPaths.map(\.path).sorted() == configuration2.excludedPaths.map(\.path).sorted()) } } private extension Configuration { static func emptyDefaultConfiguration() -> Self { Configuration(rulesMode: .defaultConfiguration(disabled: [], optIn: [])) } static func optInDefaultConfiguration(_ ruleIdentifier: String) -> Self { Configuration(rulesMode: .defaultConfiguration(disabled: [], optIn: [ruleIdentifier])) } static func optInDisabledDefaultConfiguration(_ ruleIdentifier: String) -> Self { Configuration(rulesMode: .defaultConfiguration(disabled: [ruleIdentifier], optIn: [ruleIdentifier])) } static func disabledDefaultConfiguration(_ ruleIdentifier: String) -> Self { Configuration(rulesMode: .defaultConfiguration(disabled: [ruleIdentifier], optIn: [])) } static func emptyOnlyConfiguration() -> Self { Configuration(rulesMode: .onlyConfiguration([])) } static func enabledOnlyConfiguration(_ ruleIdentifier: String) -> Self { Configuration(rulesMode: .onlyConfiguration([ruleIdentifier])) } static func allEnabledConfiguration() -> Self { Configuration(rulesMode: .allCommandLine)} static func onlyRuleConfiguration(_ ruleIdentifier: String) -> Self { Configuration(rulesMode: .onlyCommandLine([ruleIdentifier])) } }