{ 16 | var cAbstractVar: CVar { 17 | abstractMethod() 18 | } 19 | 20 | var cConcreteVar: ChildConcrete { 21 | return ChildConcrete() 22 | } 23 | 24 | func cAbstractMethod(_ a: T, b: T) -> T { 25 | abstractMethod() 26 | } 27 | 28 | func cConcreteMethod() -> Int { 29 | return 12 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/Integration/Invalid/Implementation/ChildConcrete.swift: -------------------------------------------------------------------------------- 1 | class ChildConcrete: ChildAbstract { 2 | 3 | override var gpAbstractVar: GPVar { 4 | return GPVar() 5 | } 6 | 7 | override func pAbstractMethod(arg1: Int) -> PMethod { 8 | return PMethod(arg: arg1) 9 | } 10 | 11 | override func cAbstractMethod(_ a: Arg1, b: ArgB) -> CMethod { 12 | return CMethod(a: a, b: b) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/Integration/Invalid/Implementation/GrandParentAbstract.swift: -------------------------------------------------------------------------------- 1 | class GrandParentAbstract: AbstractClass { 2 | var gpAbstractVar: GPVar { 3 | abstractMethod() 4 | } 5 | 6 | let gpLet = "haha" 7 | 8 | var gpConcreteVar: Int { 9 | return 21 10 | } 11 | 12 | func gpConcreteMethod() -> String { 13 | return "blah" 14 | } 15 | 16 | func gpAbstractMethod() -> GPMethod { 17 | abstractMethod() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/Integration/Invalid/Implementation/ParentAbstractChildAbstractNested.swift: -------------------------------------------------------------------------------- 1 | class ParentAbstract: GrandParentAbstract { 2 | 3 | var pConcreteVar: PVar { 4 | return PVar() 5 | } 6 | 7 | func pConcreteMethod() -> Blah { 8 | return Blah() 9 | } 10 | 11 | func pAbstractMethod(arg1: Int) -> PMethod { 12 | abstractMethod() 13 | } 14 | 15 | class ChildAbstract: ParentAbstract { 16 | var cAbstractVar: CVar { 17 | abstractMethod() 18 | } 19 | 20 | var cConcreteVar: ChildConcrete { 21 | return ChildConcrete() 22 | } 23 | 24 | func cAbstractMethod(_ a: Arg1, b: ArgB) -> CMethod { 25 | abstractMethod() 26 | } 27 | 28 | func cConcreteMethod() -> Int { 29 | return 12 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/Integration/Valid/ChildConcrete.swift: -------------------------------------------------------------------------------- 1 | class ChildConcrete: ChildAbstract { 2 | 3 | override var gpAbstractVar: GPVar { 4 | return GPVar() 5 | } 6 | 7 | override var cAbstractVar: CVar { 8 | return CVar() 9 | } 10 | 11 | override func gpAbstractMethod() -> GPMethod { 12 | return GPMethod() 13 | } 14 | 15 | override func pAbstractMethod(arg1: Int) -> PMethod { 16 | return PMethod(arg: arg1) 17 | } 18 | 19 | override func cAbstractMethod(_ a: Arg1, b: ArgB) -> CMethod { 20 | return CMethod(a: a, b: b) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/Integration/Valid/GrandParentAbstract.swift: -------------------------------------------------------------------------------- 1 | class GrandParentAbstract: AbstractClass { 2 | var gpAbstractVar: GPVar { 3 | abstractMethod() 4 | } 5 | 6 | let gpLet = "haha" 7 | 8 | var gpConcreteVar: Int { 9 | return 21 10 | } 11 | 12 | func gpConcreteMethod() -> String { 13 | return "blah" 14 | } 15 | 16 | func gpAbstractMethod() -> GPMethod { 17 | abstractMethod() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/Integration/Valid/ParentAbstractChildAbstractNested.swift: -------------------------------------------------------------------------------- 1 | class ParentAbstract: GrandParentAbstract { 2 | 3 | var pConcreteVar: PVar { 4 | return PVar() 5 | } 6 | 7 | func pConcreteMethod() -> Blah { 8 | return Blah() 9 | } 10 | 11 | func pAbstractMethod(arg1: Int) -> PMethod { 12 | abstractMethod() 13 | } 14 | 15 | class ChildAbstract: ParentAbstract { 16 | var cAbstractVar: CVar { 17 | abstractMethod() 18 | } 19 | 20 | var cConcreteVar: ChildConcrete { 21 | return ChildConcrete() 22 | } 23 | 24 | func cAbstractMethod(_ a: Arg1, b: ArgB) -> CMethod { 25 | abstractMethod() 26 | } 27 | 28 | func cConcreteMethod() -> Int { 29 | return 12 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/MiddleAbstractClass.swift: -------------------------------------------------------------------------------- 1 | class MiddleAbstractClass: GrandParentAbstractClass { 2 | var someProperty: SomeAbstractC { 3 | return SomeAbstractC(blah: Blah(), kaa: BB()) 4 | } 5 | 6 | func someMethod() -> String { 7 | abstractMethod() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/MixedAbstractClasses.swift: -------------------------------------------------------------------------------- 1 | class RandomClassA { 2 | func randomMethod() { 3 | 4 | } 5 | } 6 | 7 | class SAbstractVarClass: AbstractClass { 8 | 9 | var pProperty: Object { 10 | abstractMethod() 11 | } 12 | } 13 | 14 | class KAbstractVarClass: AbstractClass { 15 | var someProperty: Int { 16 | abstractMethod() 17 | } 18 | 19 | var nonAbstractProperty: String { 20 | return "haha" 21 | } 22 | 23 | func someMethod() -> String { 24 | return "" 25 | } 26 | 27 | func hahaMethod() -> Haha { 28 | abstractMethod() 29 | } 30 | 31 | func paramMethod(_ a: HJJ, b: Bar) -> PPP { 32 | abstractMethod() 33 | } 34 | 35 | var someBlahProperty: Blah { 36 | abstractMethod() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/NestedAbstractClasses.swift: -------------------------------------------------------------------------------- 1 | class RandomClassA { 2 | func randomMethod() { 3 | 4 | } 5 | } 6 | 7 | class OutterAbstractClass: AbstractClass { 8 | var someProperty: Int { 9 | abstractMethod() 10 | } 11 | 12 | var nonAbstractProperty: String { 13 | class InnerAbstractClassA: AbstractClass { 14 | func innerAbstractMethodA() { 15 | abstractMethod() 16 | } 17 | } 18 | return "haha" 19 | } 20 | 21 | func someMethod() -> String { 22 | class InnerAbstractClassB: AbstractClass { 23 | var innerAbstractVarB: Int { 24 | abstractMethod() 25 | } 26 | func yoMethod() -> Yo { 27 | abstractMethod() 28 | } 29 | } 30 | return "" 31 | } 32 | 33 | func paramMethod(_ a: HJJ, b: Bar) -> PPP { 34 | abstractMethod() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/NoAbstractClass.swift: -------------------------------------------------------------------------------- 1 | class SomeConcreteClass: ParentClass { 2 | var someProperty: Int { 3 | return 1 4 | } 5 | 6 | func someMethod() -> String { 7 | return "" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/UsageSubclass.swift: -------------------------------------------------------------------------------- 1 | class AConcreteClass: SomeAbstractC { 2 | var someProperty: Int { 3 | return 1 4 | } 5 | 6 | func someMethod() -> String { 7 | return "" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/UsageType.swift: -------------------------------------------------------------------------------- 1 | class BConcreteClass { 2 | var someProperty: SomeAbstractC { 3 | return Blah() 4 | } 5 | 6 | func someMethod() -> String { 7 | return "" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/Fixtures/ViolateInstantiation.swift: -------------------------------------------------------------------------------- 1 | class ViolationClass { 2 | var someProperty: SomeAbstractC { 3 | return SomeAbstractC(blah: Blah(), kaa: BB()) 4 | } 5 | 6 | func someMethod() -> String { 7 | return "" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/SubclassUsageFilterTaskTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018. Uber Technologies 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import XCTest 18 | @testable import AbstractClassValidatorFramework 19 | 20 | class SubclassUsageFilterTaskTests: BaseFrameworkTests { 21 | 22 | func test_execute_noExclusion_noAbstractClass_verifyResult() { 23 | let url = fixtureUrl(for: "NoAbstractClass.swift") 24 | let task = SubclassUsageFilterTask(url: url, exclusionSuffixes: [], exclusionPaths: [], abstractClassDefinitions: []) 25 | 26 | let result = try! task.execute() 27 | 28 | switch result { 29 | case .shouldProcess(_, _): 30 | XCTFail() 31 | case .skip: 32 | break 33 | } 34 | } 35 | 36 | func test_execute_suffixExclusion_hasAbstractClass_verifyResult() { 37 | let url = fixtureUrl(for: "ConcreteSubclass.swift") 38 | let task = SubclassUsageFilterTask(url: url, exclusionSuffixes: ["Subclass"], exclusionPaths: [], abstractClassDefinitions: [AbstractClassDefinition(name: "ParentAbstractClass", vars: [], methods: [], inheritedTypes: [])]) 39 | 40 | let result = try! task.execute() 41 | 42 | switch result { 43 | case .shouldProcess(_, _): 44 | XCTFail() 45 | case .skip: 46 | break 47 | } 48 | } 49 | 50 | func test_execute_pathExclusion_hasAbstractClass_verifyResult() { 51 | let url = fixtureUrl(for: "ConcreteSubclass.swift") 52 | let task = SubclassUsageFilterTask(url: url, exclusionSuffixes: [], exclusionPaths: ["Fixtures/"], abstractClassDefinitions: [AbstractClassDefinition(name: "ParentAbstractClass", vars: [], methods: [], inheritedTypes: [])]) 53 | 54 | let result = try! task.execute() 55 | 56 | switch result { 57 | case .shouldProcess(_, _): 58 | XCTFail() 59 | case .skip: 60 | break 61 | } 62 | } 63 | 64 | func test_execute_noExclusion_simpleSubclass_verifyResult() { 65 | let url = fixtureUrl(for: "ConcreteSubclass.swift") 66 | let task = SubclassUsageFilterTask(url: url, exclusionSuffixes: [], exclusionPaths: [], abstractClassDefinitions: [AbstractClassDefinition(name: "ParentAbstractClass", vars: [], methods: [], inheritedTypes: [])]) 67 | 68 | let result = try! task.execute() 69 | 70 | switch result { 71 | case .shouldProcess(let processUrl, let content): 72 | XCTAssertEqual(processUrl, url) 73 | XCTAssertEqual(content, try! String(contentsOf: url)) 74 | case .skip: 75 | XCTFail() 76 | } 77 | } 78 | 79 | func test_execute_noExclusion_genericSubclass_verifyResult() { 80 | let url = fixtureUrl(for: "GenericSuperConcreteSubclass.swift") 81 | let task = SubclassUsageFilterTask(url: url, exclusionSuffixes: [], exclusionPaths: [], abstractClassDefinitions: [AbstractClassDefinition(name: "GenericBaseClass", vars: [], methods: [], inheritedTypes: [])]) 82 | 83 | let result = try! task.execute() 84 | 85 | switch result { 86 | case .shouldProcess(let processUrl, let content): 87 | XCTAssertEqual(processUrl, url) 88 | XCTAssertEqual(content, try! String(contentsOf: url)) 89 | case .skip: 90 | XCTFail() 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Validator/Tests/AbstractClassValidatorFrameworkTests/ValidatorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018. Uber Technologies 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | import SourceKittenFramework 18 | import SourceParsingFramework 19 | import XCTest 20 | @testable import AbstractClassValidatorFramework 21 | 22 | class ValidatorTests: BaseFrameworkTests { 23 | 24 | func test_validate_noExclusions_withNoViolations_verifySuccess() { 25 | let sourceRoot = fixtureUrl(for: "/Integration/Valid/") 26 | 27 | try! Validator().validate(from: [sourceRoot.path], excludingFilesEndingWith: [], excludingFilesWithPaths: [], shouldCollectParsingInfo: false, timeout: 10, concurrencyLimit: nil) 28 | } 29 | 30 | func test_validate_exclusionPath_withViolations_verifySuccess() { 31 | let sourceRoot = fixtureUrl(for: "/Integration/Invalid/") 32 | 33 | try! Validator().validate(from: [sourceRoot.path], excludingFilesEndingWith: [], excludingFilesWithPaths: ["/Integration"], shouldCollectParsingInfo: false, timeout: 10, concurrencyLimit: nil) 34 | } 35 | 36 | func test_validate_exclusionSuffix_withViolations_verifySuccess() { 37 | let sourceRoot = fixtureUrl(for: "/Integration/Invalid/") 38 | 39 | try! Validator().validate(from: [sourceRoot.path], excludingFilesEndingWith: ["Concrete", "Instantiation"], excludingFilesWithPaths: [], shouldCollectParsingInfo: false, timeout: 10, concurrencyLimit: nil) 40 | } 41 | 42 | func test_validate_noExclusions_withExpressionCallViolations_verifyError() { 43 | let sourceRoot = fixtureUrl(for: "/Integration/Invalid/ExpressionCall/") 44 | 45 | do { 46 | try Validator().validate(from: [sourceRoot.path], excludingFilesEndingWith: [], excludingFilesWithPaths: [], shouldCollectParsingInfo: false, timeout: 10, concurrencyLimit: nil) 47 | XCTFail() 48 | } catch GenericError.withMessage(let message) { 49 | XCTAssertTrue(message.contains("ChildAbstract")) 50 | XCTAssertTrue(message.contains("/Fixtures/Integration/Invalid/ExpressionCall/AbstractInstantiation.swift")) 51 | } catch { 52 | XCTFail() 53 | } 54 | } 55 | 56 | func test_validate_noExclusions_withImplementationViolations_verifyError() { 57 | let sourceRoot = fixtureUrl(for: "/Integration/Invalid/Implementation/") 58 | 59 | do { 60 | try Validator().validate(from: [sourceRoot.path], excludingFilesEndingWith: [], excludingFilesWithPaths: [], shouldCollectParsingInfo: false, timeout: 10, concurrencyLimit: nil) 61 | XCTFail() 62 | } catch GenericError.withMessage(let message) { 63 | XCTAssertTrue(message.contains("ChildConcrete")) 64 | XCTAssertTrue(message.contains("cAbstractVar")) 65 | } catch { 66 | XCTFail() 67 | } 68 | } 69 | 70 | func test_validate_noExclusions_withGenericSuperclassImplementationViolations_verifyError() { 71 | let sourceRoot = fixtureUrl(for: "/Integration/Invalid/GenericSuperclass/") 72 | 73 | do { 74 | try Validator().validate(from: [sourceRoot.path], excludingFilesEndingWith: [], excludingFilesWithPaths: [], shouldCollectParsingInfo: false, timeout: 10, concurrencyLimit: nil) 75 | XCTFail() 76 | } catch GenericError.withMessage(let message) { 77 | XCTAssertTrue(message.contains("ChildConcrete")) 78 | XCTAssertTrue(message.contains("cAbstractVar")) 79 | } catch { 80 | XCTFail() 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Validator/bin/abstractclassvalidator: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/swift-abstract-class/0a4a83d9b0b91ad8228e50de39122e44775c722a/Validator/bin/abstractclassvalidator -------------------------------------------------------------------------------- /Validator/xcode.xcconfig: -------------------------------------------------------------------------------- 1 | OTHER_SWIFT_FLAGS[config=Debug] = -DDEBUG 2 | -------------------------------------------------------------------------------- /foundation.xcconfig: -------------------------------------------------------------------------------- 1 | IPHONEOS_DEPLOYMENT_TARGET = 8.0 2 | --------------------------------------------------------------------------------