From 236e4d0a88ba4246b08fa0f10c97f75a0b9a1296 Mon Sep 17 00:00:00 2001 From: "emre.kartal" Date: Sat, 28 Oct 2023 17:35:10 +0200 Subject: [PATCH] added dependency injection and functional testing --- Sources/allin/allin.xcodeproj/project.pbxproj | 20 ++++--- Sources/allin/allin/ContentView.swift | 2 +- .../allin/Models/DependencyInjection.swift | 52 +++++++++++++++++++ Sources/allin/allin/Models/Singleton.swift | 19 ------- Sources/allin/allin/Screens/LoginScreen.swift | 4 +- .../allin/allin/Screens/RegisterScreen.swift | 2 +- .../allin/allin/Services/AuthService.swift | 2 +- .../allin/allin/Services/IAuthService.swift | 13 +++++ Sources/allin/allin/allinApp.swift | 5 ++ Sources/allin/allinTests/allinTests.swift | 39 ++++++++++++++ 10 files changed, 128 insertions(+), 30 deletions(-) create mode 100644 Sources/allin/allin/Models/DependencyInjection.swift delete mode 100644 Sources/allin/allin/Models/Singleton.swift create mode 100644 Sources/allin/allin/Services/IAuthService.swift diff --git a/Sources/allin/allin.xcodeproj/project.pbxproj b/Sources/allin/allin.xcodeproj/project.pbxproj index b8c045a..608d1ab 100644 --- a/Sources/allin/allin.xcodeproj/project.pbxproj +++ b/Sources/allin/allin.xcodeproj/project.pbxproj @@ -28,6 +28,8 @@ EC4163512AE126B3001E620D /* DropDownMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC4163502AE126B3001E620D /* DropDownMenuView.swift */; }; EC46D7DD2ABCCC270030AC04 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC46D7DC2ABCCC270030AC04 /* MenuView.swift */; }; EC46D7DF2ABCE0A20030AC04 /* ParameterMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC46D7DE2ABCE0A20030AC04 /* ParameterMenuView.swift */; }; + EC508A9F2AED3C2A000FA2FB /* DependencyInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC508A9E2AED3C2A000FA2FB /* DependencyInjection.swift */; }; + EC508AA12AED3D89000FA2FB /* IAuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC508AA02AED3D89000FA2FB /* IAuthService.swift */; }; EC50BF962ABF4D3300197685 /* SplashScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC50BF952ABF4D3300197685 /* SplashScreen.swift */; }; EC50BF982ABF541B00197685 /* WelcomeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC50BF972ABF541B00197685 /* WelcomeScreen.swift */; }; EC55565D2AD6E5B900E5CA3F /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC55565C2AD6E5B900E5CA3F /* AuthService.swift */; }; @@ -40,7 +42,6 @@ ECA7010B2AC4003400532444 /* RankingRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7010A2AC4003400532444 /* RankingRowView.swift */; }; ECA7010D2AC4948600532444 /* FriendsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7010C2AC4948600532444 /* FriendsScreen.swift */; }; ECA7010F2AC4949D00532444 /* FriendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECA7010E2AC4949D00532444 /* FriendView.swift */; }; - ECCD6DD92AD7228B00F947C4 /* Singleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECCD6DD82AD7228B00F947C4 /* Singleton.swift */; }; ECCD6DDB2AD7233F00F947C4 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECCD6DDA2AD7233F00F947C4 /* User.swift */; }; ECDF624A2AC1CAFD00BA8213 /* RegisterScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECDF62492AC1CAFD00BA8213 /* RegisterScreen.swift */; }; ECFC54442AC0C39E00195760 /* LoginScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFC54432AC0C39E00195760 /* LoginScreen.swift */; }; @@ -89,6 +90,8 @@ EC4163502AE126B3001E620D /* DropDownMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DropDownMenuView.swift; path = allin/Views/DropDownMenuView.swift; sourceTree = SOURCE_ROOT; }; EC46D7DC2ABCCC270030AC04 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MenuView.swift; path = allin/Views/MenuView.swift; sourceTree = SOURCE_ROOT; }; EC46D7DE2ABCE0A20030AC04 /* ParameterMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ParameterMenuView.swift; path = allin/Views/ParameterMenuView.swift; sourceTree = SOURCE_ROOT; }; + EC508A9E2AED3C2A000FA2FB /* DependencyInjection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DependencyInjection.swift; path = allin/Models/DependencyInjection.swift; sourceTree = SOURCE_ROOT; }; + EC508AA02AED3D89000FA2FB /* IAuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = IAuthService.swift; path = allin/Services/IAuthService.swift; sourceTree = SOURCE_ROOT; }; EC50BF952ABF4D3300197685 /* SplashScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SplashScreen.swift; path = allin/Screens/SplashScreen.swift; sourceTree = SOURCE_ROOT; }; EC50BF972ABF541B00197685 /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WelcomeScreen.swift; path = allin/Screens/WelcomeScreen.swift; sourceTree = SOURCE_ROOT; }; EC55565C2AD6E5B900E5CA3F /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AuthService.swift; path = allin/Services/AuthService.swift; sourceTree = SOURCE_ROOT; }; @@ -101,7 +104,6 @@ ECA7010A2AC4003400532444 /* RankingRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RankingRowView.swift; path = allin/Views/RankingRowView.swift; sourceTree = SOURCE_ROOT; }; ECA7010C2AC4948600532444 /* FriendsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FriendsScreen.swift; path = allin/Screens/FriendsScreen.swift; sourceTree = SOURCE_ROOT; }; ECA7010E2AC4949D00532444 /* FriendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FriendView.swift; path = allin/Views/FriendView.swift; sourceTree = SOURCE_ROOT; }; - ECCD6DD82AD7228B00F947C4 /* Singleton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Singleton.swift; path = allin/Models/Singleton.swift; sourceTree = SOURCE_ROOT; }; ECCD6DDA2AD7233F00F947C4 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = User.swift; path = allin/Models/User.swift; sourceTree = SOURCE_ROOT; }; ECDF62492AC1CAFD00BA8213 /* RegisterScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RegisterScreen.swift; path = allin/Screens/RegisterScreen.swift; sourceTree = SOURCE_ROOT; }; ECFC54432AC0C39E00195760 /* LoginScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LoginScreen.swift; path = allin/Screens/LoginScreen.swift; sourceTree = SOURCE_ROOT; }; @@ -229,6 +231,7 @@ isa = PBXGroup; children = ( EC55565C2AD6E5B900E5CA3F /* AuthService.swift */, + EC508AA02AED3D89000FA2FB /* IAuthService.swift */, ); path = Services; sourceTree = ""; @@ -261,8 +264,8 @@ ECCD6DD72AD7227500F947C4 /* Models */ = { isa = PBXGroup; children = ( - ECCD6DD82AD7228B00F947C4 /* Singleton.swift */, ECCD6DDA2AD7233F00F947C4 /* User.swift */, + EC508A9E2AED3C2A000FA2FB /* DependencyInjection.swift */, ); path = Models; sourceTree = ""; @@ -346,6 +349,7 @@ }; D98C4D6F2AB9D019007A6B4D = { CreatedOnToolsVersion = 14.2; + LastSwiftMigration = 1430; TestTargetID = D98C4D5F2AB9D017007A6B4D; }; D98C4D792AB9D019007A6B4D = { @@ -406,6 +410,7 @@ buildActionMask = 2147483647; files = ( ECA7010B2AC4003400532444 /* RankingRowView.swift in Sources */, + EC508AA12AED3D89000FA2FB /* IAuthService.swift in Sources */, EC31955E2ACD3B8E00D0A4DC /* ConfidentialityView.swift in Sources */, ECA701092AC3FE3300532444 /* RankingScreen.swift in Sources */, ECFC54442AC0C39E00195760 /* LoginScreen.swift in Sources */, @@ -420,7 +425,6 @@ EC55565D2AD6E5B900E5CA3F /* AuthService.swift in Sources */, D98C4D662AB9D017007A6B4D /* ContentView.swift in Sources */, EC4163512AE126B3001E620D /* DropDownMenuView.swift in Sources */, - ECCD6DD92AD7228B00F947C4 /* Singleton.swift in Sources */, D92EC57C2ABADA2800CCD30E /* CoinCounterView.swift in Sources */, EC3737E42AC2F5FB00E6BDB5 /* ChoiceCapsule.swift in Sources */, EC3737E62AC41DB000E6BDB5 /* WinModal.swift in Sources */, @@ -437,6 +441,7 @@ EC2C1EEF2AC098D30091D57C /* UsersPreview.swift in Sources */, EC87FCDB2ABBA6AC00363986 /* TrendingBetCard.swift in Sources */, EC000A7B2AC7450200A8BE26 /* CreationBetScreen.swift in Sources */, + EC508A9F2AED3C2A000FA2FB /* DependencyInjection.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -595,7 +600,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AllIn/Preview Content\""; - DEVELOPMENT_TEAM = 35KQ5BDC64; + DEVELOPMENT_TEAM = P39ZK4GA2T; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AllIn/Info.plist; @@ -625,7 +630,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AllIn/Preview Content\""; - DEVELOPMENT_TEAM = 35KQ5BDC64; + DEVELOPMENT_TEAM = P39ZK4GA2T; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AllIn/Info.plist; @@ -652,6 +657,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; @@ -660,6 +666,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.alldev.AllInTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AllIn.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/AllIn"; @@ -671,6 +678,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; diff --git a/Sources/allin/allin/ContentView.swift b/Sources/allin/allin/ContentView.swift index 30cfc89..f5b2673 100644 --- a/Sources/allin/allin/ContentView.swift +++ b/Sources/allin/allin/ContentView.swift @@ -11,7 +11,7 @@ struct ContentView: View { var body: some View { NavigationView { - Home(page: "CreationBet") + Welcome() } } } diff --git a/Sources/allin/allin/Models/DependencyInjection.swift b/Sources/allin/allin/Models/DependencyInjection.swift new file mode 100644 index 0000000..9795347 --- /dev/null +++ b/Sources/allin/allin/Models/DependencyInjection.swift @@ -0,0 +1,52 @@ +// +// DependencyInjection.swift +// AllIn +// +// Created by étudiant on 28/10/2023. +// + +import Foundation + +class DependencyInjection { + static var shared = DependencyInjection() + private var singletons = [String: Any]() + + @discardableResult + func addSingleton(_ type: T.Type, _ instance: T) -> DependencyInjection { + let key = String(describing: T.self) + singletons[key] = instance + return self + } + + func resolve(_ type: T.Type) -> T? { + let key = String(describing: T.self) + return singletons[key] as? T + } +} + +@propertyWrapper +struct Inject { + private var value: T? + + init() { + self.value = DependencyInjection.shared.resolve(T.self) + } + + var wrappedValue: T { + get { + if let value = value { + return value + } else { + if let resolvedValue = DependencyInjection.shared.resolve(T.self) { + return resolvedValue + } else { + fatalError("Dependency not registered in DependencyInjection.") + } + } + + } + set { + value = newValue + } + } +} diff --git a/Sources/allin/allin/Models/Singleton.swift b/Sources/allin/allin/Models/Singleton.swift deleted file mode 100644 index 30b7674..0000000 --- a/Sources/allin/allin/Models/Singleton.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// Singleton.swift -// AllIn -// -// Created by étudiant on 11/10/2023. -// - -import Foundation - -class Singleton { - - static let singleton = Singleton() - - var user: User? - - var auth: AuthService = AuthService() - - private init() { } -} diff --git a/Sources/allin/allin/Screens/LoginScreen.swift b/Sources/allin/allin/Screens/LoginScreen.swift index 0e5dcf8..2da887a 100644 --- a/Sources/allin/allin/Screens/LoginScreen.swift +++ b/Sources/allin/allin/Screens/LoginScreen.swift @@ -9,6 +9,7 @@ import SwiftUI struct Login: View { + @Inject private var authService: IAuthService @State private var isPasswordVisible = true @State private var username: String = "" @State private var password: String = "" @@ -111,9 +112,8 @@ struct Login: View { } func login(email: String, password: String) { - let api = AuthService() - api.login(email: email, password: password) { statusCode in + authService.login(email: email, password: password) { statusCode in DispatchQueue.main.async { if statusCode == 200 { isLoginSuccessful = true diff --git a/Sources/allin/allin/Screens/RegisterScreen.swift b/Sources/allin/allin/Screens/RegisterScreen.swift index af6e149..83d8a59 100644 --- a/Sources/allin/allin/Screens/RegisterScreen.swift +++ b/Sources/allin/allin/Screens/RegisterScreen.swift @@ -21,7 +21,7 @@ struct Register: View { @State private var errorMailMessage: String = "" @State private var errorUsernameMessage: String = "" @State private var errorPasswordMessage: String = "" - + var body: some View { GeometryReader { geometry in ScrollView(showsIndicators: false) { diff --git a/Sources/allin/allin/Services/AuthService.swift b/Sources/allin/allin/Services/AuthService.swift index d02691d..f57fe8c 100644 --- a/Sources/allin/allin/Services/AuthService.swift +++ b/Sources/allin/allin/Services/AuthService.swift @@ -7,7 +7,7 @@ import Foundation -class AuthService { +class AuthService: IAuthService { let baseURL : String = "https://codefirst.iut.uca.fr/containers/AllDev-api/" diff --git a/Sources/allin/allin/Services/IAuthService.swift b/Sources/allin/allin/Services/IAuthService.swift new file mode 100644 index 0000000..e43ea8d --- /dev/null +++ b/Sources/allin/allin/Services/IAuthService.swift @@ -0,0 +1,13 @@ +// +// IAuthService.swift +// AllIn +// +// Created by étudiant on 28/10/2023. +// + +import Foundation + +protocol IAuthService { + func login(email : String, password : String, completion : @escaping (Int)-> ()) + func register(email : String, password : String, username : String, completion : @escaping (Int)-> ()) +} diff --git a/Sources/allin/allin/allinApp.swift b/Sources/allin/allin/allinApp.swift index 0b5242b..b1b51c0 100644 --- a/Sources/allin/allin/allinApp.swift +++ b/Sources/allin/allin/allinApp.swift @@ -9,6 +9,11 @@ import SwiftUI @main struct AllInApp: App { + let DI = DependencyInjection.shared + init() { + DI.addSingleton(IAuthService.self, AuthService()) + } + var body: some Scene { WindowGroup { ContentView() diff --git a/Sources/allin/allinTests/allinTests.swift b/Sources/allin/allinTests/allinTests.swift index 4fa4a29..f089b4d 100644 --- a/Sources/allin/allinTests/allinTests.swift +++ b/Sources/allin/allinTests/allinTests.swift @@ -32,5 +32,44 @@ final class AllInTests: XCTestCase { // Put the code you want to measure the time of here. } } + + func testInstance() { + DependencyInjection.shared.addSingleton(UserTest.self, UserTest(age: 10)) + let view1 = View1() + let view2 = View2() + XCTAssertEqual(view1.getAge(), view2.getAge()) + + view1.setAge() + XCTAssertEqual(view1.getAge(), view2.getAge()) + view2.setAge() + XCTAssertEqual(view1.getAge(), view2.getAge()) + } + + class UserTest { + public var age:Int + init(age:Int) { + self.age = age + } + } + + class View1 { + @Inject private var user:UserTest + func getAge() -> Int { + return user.age + } + func setAge() { + user.age = 20 + } + } + + class View2 { + @Inject private var user:UserTest + func getAge() -> Int { + return user.age + } + func setAge() { + user.age = 40 + } + } }