├── .bundle └── config ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .jazzy.yml ├── .swiftlint-test.yml ├── .swiftlint.yml ├── .travis.yml ├── AUTHORS ├── CHANGELOG.md ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── OmiseGO.podspec ├── OmiseGO.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── OmiseGO.xcscheme │ └── Tests.xcscheme ├── OmiseGO.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Podfile ├── Podfile.lock ├── README.md ├── Rakefile ├── Source ├── Admin │ ├── API │ │ ├── APIAdminEndpoint.swift │ │ ├── AdminConfiguration.swift │ │ ├── AdminCredential.swift │ │ └── HTTPAdminAPI.swift │ ├── Models │ │ ├── Account+Admin.swift │ │ ├── AccountGetParams.swift │ │ ├── Transaction+Admin.swift │ │ ├── TransactionConsumption+Admin.swift │ │ ├── TransactionConsumptionParams+Admin.swift │ │ ├── TransactionCreateParams+Admin.swift │ │ ├── TransactionRequest+Admin.swift │ │ ├── TransactionRequestParams+Admin.swift │ │ ├── Wallet+Admin.swift │ │ ├── WalletGetParams.swift │ │ ├── WalletListForAccountParams.swift │ │ └── WalletListForUserParams.swift │ └── Websocket │ │ └── SocketClient+Admin.swift ├── Client │ ├── API │ │ ├── APIClientEndpoint.swift │ │ ├── ClientConfiguration.swift │ │ ├── ClientCredential.swift │ │ └── HTTPClientAPI.swift │ ├── Models │ │ ├── Setting+Client.swift │ │ ├── SignupParams.swift │ │ ├── Transaction+Client.swift │ │ ├── TransactionConsumption+Client.swift │ │ ├── TransactionListParams.swift │ │ ├── TransactionRequest+Client.swift │ │ ├── User+Client.swift │ │ ├── UserResetPasswordParams.swift │ │ ├── UserUpdatePasswordParams.swift │ │ └── Wallet+Client.swift │ ├── QRCode │ │ ├── QRClientVerifier.swift │ │ └── QRScannerViewController+Client.swift │ └── Websocket │ │ └── SocketClient+Client.swift ├── Core │ ├── API │ │ ├── APIEndpoint.swift │ │ ├── APIError.swift │ │ ├── Configuration.swift │ │ ├── Credential.swift │ │ ├── CredentialEncoder.swift │ │ ├── HTTPAPI.swift │ │ ├── HTTPTask.swift │ │ ├── Request.swift │ │ └── RequestBuilder.swift │ ├── Helpers │ │ ├── Codable.swift │ │ ├── OMGNumberFormatter.swift │ │ └── Tool.swift │ ├── Models │ │ ├── Account.swift │ │ ├── AuthenticationToken.swift │ │ ├── Avatar.swift │ │ ├── Balance.swift │ │ ├── CollectionParams │ │ │ ├── FilterParams.swift │ │ │ ├── PaginatedListParams.swift │ │ │ ├── PaginationParams.swift │ │ │ └── SortParams.swift │ │ ├── EmptyResponse.swift │ │ ├── ExchangePair.swift │ │ ├── JSONListResponse.swift │ │ ├── JSONResponse.swift │ │ ├── LoginParams.swift │ │ ├── OMGError.swift │ │ ├── Pagination.swift │ │ ├── Reponse.swift │ │ ├── Setting.swift │ │ ├── Token.swift │ │ ├── Transaction.swift │ │ ├── TransactionConsumption.swift │ │ ├── TransactionConsumptionParams.swift │ │ ├── TransactionExchange.swift │ │ ├── TransactionParams.swift │ │ ├── TransactionRequest.swift │ │ ├── TransactionRequestParams.swift │ │ ├── TransactionSource.swift │ │ ├── User.swift │ │ └── Wallet.swift │ ├── Operations │ │ ├── Listable.swift │ │ ├── Listenable.swift │ │ ├── QREncodable.swift │ │ └── Retrievable.swift │ ├── QRCode │ │ ├── QRGenerator.swift │ │ ├── QRReader.swift │ │ ├── QRScannerLoadingView.swift │ │ ├── QRScannerOverlayView.swift │ │ ├── QRScannerView.swift │ │ ├── QRScannerViewController.swift │ │ ├── QRScannerViewModel.swift │ │ └── QRVerifier.swift │ └── Websocket │ │ ├── SocketChannel.swift │ │ ├── SocketClient.swift │ │ ├── SocketDelegate.swift │ │ ├── SocketDispatcher.swift │ │ ├── SocketEvent.swift │ │ ├── SocketMessage.swift │ │ ├── SocketObject.swift │ │ └── SocketPayload.swift ├── Info.plist └── OmiseGO.h ├── Tests ├── Admin │ ├── APITests │ │ ├── APIAdminEndpointTest.swift │ │ └── AdminCredentialTests.swift │ ├── CondingTests │ │ └── AdminEncodeTests.swift │ └── FixtureTests │ │ ├── AccountAdminFixtureTests.swift │ │ ├── FixtureAdminAPI.swift │ │ ├── FixtureAdminTestCase.swift │ │ ├── LoginAdminFixtureTests.swift │ │ ├── LogoutAdminFixtureTests.swift │ │ ├── RequestAdminFixtureTests.swift │ │ ├── TransactionAdminFixtureTests.swift │ │ ├── TransactionConsumptionAdminFixtureTests.swift │ │ ├── TransactionRequestAdminFixtureTests.swift │ │ ├── WalletAdminFixtureTests.swift │ │ └── admin_fixtures │ │ └── api │ │ ├── account.all.json │ │ ├── account.get.json │ │ ├── account.get_wallets.json │ │ ├── admin.login.json │ │ ├── me.logout.json │ │ ├── transaction.all.json │ │ ├── transaction.create.json │ │ ├── transaction_consumption.approve.json │ │ ├── transaction_consumption.cancel.json │ │ ├── transaction_consumption.reject.json │ │ ├── transaction_request.consume.json │ │ ├── transaction_request.create.json │ │ ├── transaction_request.get.json │ │ ├── user.get_wallets.json │ │ └── wallet.get.json ├── Client │ ├── APITests │ │ ├── APIClientEndpointTest.swift │ │ └── ClientCredentialTests.swift │ ├── FixtureTests │ │ ├── FixtureClientAPI.swift │ │ ├── FixtureClientTestCase.swift │ │ ├── LoginFixtureTests.swift │ │ ├── LogoutFixtureTests.swift │ │ ├── RequestFixtureTest.swift │ │ ├── SettingFixtureTests.swift │ │ ├── SignupFixtureTests.swift │ │ ├── TransactionConsumptionFixtureTests.swift │ │ ├── TransactionFixtureTests.swift │ │ ├── TransactionRequestFixtureTests.swift │ │ ├── UserFixtureTests.swift │ │ ├── WalletFixtureTests.swift │ │ └── client_fixtures │ │ │ └── api │ │ │ ├── me.approve_transaction_consumption.json │ │ │ ├── me.cancel_transaction_consumption.json │ │ │ ├── me.consume_transaction_request.json │ │ │ ├── me.create_transaction.json │ │ │ ├── me.create_transaction_request.json │ │ │ ├── me.get.json │ │ │ ├── me.get_settings.json │ │ │ ├── me.get_transaction_request.json │ │ │ ├── me.get_transactions.json │ │ │ ├── me.get_wallets.json │ │ │ ├── me.logout.json │ │ │ ├── me.reject_transaction_consumption.json │ │ │ ├── user.login.json │ │ │ ├── user.reset_password.json │ │ │ ├── user.signup.json │ │ │ └── user.update_password.json │ └── LiveTests │ │ ├── AuthenticationLiveTests.swift │ │ ├── LiveClientTestCase.swift │ │ ├── ResponseLiveTest.swift │ │ ├── SettingLiveTests.swift │ │ ├── TransactionLiveTests.swift │ │ ├── TransactionRequestLiveTests.swift │ │ ├── UserLiveTests.swift │ │ └── WalletLiveTests.swift ├── Core │ ├── APITests │ │ ├── APIErrorTests.swift │ │ ├── CredentialEncoderTests.swift │ │ ├── HTTPClientTests.swift │ │ ├── RequestBuilderTests.swift │ │ └── RequestTest.swift │ ├── CodingTests │ │ ├── DecodeTests.swift │ │ └── EncodeTests.swift │ ├── FixtureTests │ │ ├── DecodingFixtureTests.swift │ │ ├── FixtureClient.swift │ │ ├── FixtureTestCase.swift │ │ ├── ListableTests.swift │ │ ├── ResponseFixtureTest.swift │ │ └── core_fixtures │ │ │ ├── api │ │ │ ├── dummy.decoding_error.json │ │ │ ├── dummy.failure.json │ │ │ ├── dummy.listable.failure.json │ │ │ ├── dummy.paginated_listable.failure.json │ │ │ └── dummy.success.json │ │ │ └── objects │ │ │ ├── account.json │ │ │ ├── api_error.json │ │ │ ├── authentication_token.json │ │ │ ├── avatar.json │ │ │ ├── balance.json │ │ │ ├── bigint_int32.json │ │ │ ├── bigint_int64.json │ │ │ ├── bigint_invalid.json │ │ │ ├── bigint_over_int64.json │ │ │ ├── dates.json │ │ │ ├── dates_invalid.json │ │ │ ├── exchange_pair.json │ │ │ ├── json_list_response.json │ │ │ ├── json_response.json │ │ │ ├── metadata.json │ │ │ ├── metadata_null.json │ │ │ ├── pagination.json │ │ │ ├── setting.json │ │ │ ├── socket_response.json │ │ │ ├── socket_response_failure.json │ │ │ ├── socket_response_reply.json │ │ │ ├── socket_response_unknown_object.json │ │ │ ├── token.json │ │ │ ├── transaction.json │ │ │ ├── transaction_consumption.json │ │ │ ├── transaction_exchange.json │ │ │ ├── transaction_request.json │ │ │ ├── transaction_source.json │ │ │ ├── user.json │ │ │ └── wallet.json │ ├── Helpers │ │ ├── Extension.swift │ │ └── StubGenerator.swift │ ├── LiveTests │ │ └── LiveTestCase.swift │ ├── ModelTests │ │ ├── AccountTest.swift │ │ ├── AuthenticationTokenTests.swift │ │ ├── BalanceTests.swift │ │ ├── ExchangePairTest.swift │ │ ├── OMGErrorTests.swift │ │ ├── TokenTests.swift │ │ ├── TransactionConsumptionParamsTest.swift │ │ ├── TransactionConsumptionTest.swift │ │ ├── TransactionRequestParamsTest.swift │ │ ├── TransactionRequestTest.swift │ │ ├── TransactionTest.swift │ │ ├── UserTests.swift │ │ └── WalletTests.swift │ ├── OMGNumberFormatterTests.swift │ ├── QRCodeTests │ │ ├── QRGeneratorTests.swift │ │ ├── QRReaderTests.swift │ │ ├── QRScannerViewControllerTests.swift │ │ ├── QRScannerViewModelTests.swift │ │ └── QRScannerViewTests.swift │ ├── SocketsTests │ │ ├── FixtureSocketClient.swift │ │ ├── SocketChannelTests.swift │ │ ├── SocketClientTests.swift │ │ ├── SocketDispatcherTests.swift │ │ └── SocketMessageTests.swift │ ├── TestMocks │ │ ├── QRScannerViewController+Test.swift │ │ ├── TestAPIEndpoint.swift │ │ ├── TestBigUInt.swift │ │ ├── TestConfiguration.swift │ │ ├── TestCredential.swift │ │ ├── TestDate.swift │ │ ├── TestListable.swift │ │ ├── TestMetadata.swift │ │ ├── TestObject.swift │ │ ├── TestQRHelper.swift │ │ ├── TestQRReader.swift │ │ ├── TestSocketEventDelegate.swift │ │ ├── TestSortable.swift │ │ └── TestWebSocketDelegate.swift │ └── ToolsTests.swift ├── Info.plist └── secret.plist └── documentation ├── admin.md ├── client.md └── pagination.md /.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_PATH: "vendor/bundle" 3 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute to the OmiseGO's projects 2 | 3 | Welcome to one of OmiseGO's open source projects! We welcome contributions in all kinds and shapes: code, documentation, bug reports, feedbacks... But before opening your first issue or PR, please read through this document. 4 | 5 | #### **Did you find a bug?** 6 | 7 | * __Do not create issues for security vulnerabilities__. We are currently setting up a bounty program for those. In the meantime, you can get in touch with us via [email](mailto:thibault@omisego.co). 8 | * For other bugs, first, ensure that the bug you found has not been reported yet. To do so, you can [search under issues](https://github.com/omisego/ios-sdk/issues). 9 | * Open a new issue if you didn't find an existing one. Follow the issue template and be as specific as possible. 10 | 11 | #### **Did you write a patch that fixes a bug?** 12 | 13 | * Open a Pull Request. 14 | * Describe the problem and solution. Add link to issue if any. 15 | 16 | #### **Do you intend to add a new feature or change an existing one?** 17 | 18 | * Do not open an issue right away. First, get in touch with us through [Gitter](https://gitter.im/omisego/ios-sdk). Once you get the green light to work on something, create an issue to describe the whole idea. 19 | 20 | #### **Do you have questions about the source code?** 21 | 22 | * You can ask any question about the source code in the [Gitter](https://gitter.im/omisego/ios-sdk) or on [stack overflow](https://stackoverflow.com/). 23 | 24 | Thanks! 25 | 26 | The OmiseGO Team 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Subject of the issue 2 | 3 | Describe your issue here. 4 | 5 | # Your environment 6 | 7 | Tell us where this issue occurred. 8 | 9 | # Steps to reproduce 10 | 11 | Tell us how to reproduce this issue. 12 | 13 | # Expected behavior 14 | 15 | Tell us what should happen. 16 | 17 | # Actual behavior 18 | 19 | Tell us what happens instead. 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Issue/Task Number: 2 | 3 | # Overview 4 | 5 | Describe what your Pull Request is about in a few sentences. This is a global description that should tell people what your PR is all about. Don't go too much into details here. 6 | 7 | # Changes 8 | 9 | - Change 1 10 | - Change 2 11 | - ... 12 | 13 | # Implementation Details 14 | 15 | Describe your changes and implementation choices. More details make PRs easier to review. 16 | 17 | # Usage 18 | 19 | Describe how to test your new feature/bug fix. Step by step so we can quickly give it a try. 20 | 21 | # Impact 22 | 23 | How can this change be deployed? Any special requirement? 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | vendor/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | # Package.pins 41 | # Package.resolved 42 | .build/ 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots 69 | fastlane/test_output 70 | 71 | ## User settings 72 | xcuserdata/ 73 | 74 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 75 | *.xcscmblueprint 76 | *.xccheckout 77 | 78 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 79 | build/ 80 | DerivedData/ 81 | *.moved-aside 82 | *.pbxuser 83 | !default.pbxuser 84 | *.mode1v3 85 | !default.mode1v3 86 | *.mode2v3 87 | !default.mode2v3 88 | *.perspectivev3 89 | !default.perspectivev3 90 | 91 | ## Jazzy generated doc 92 | docs/ 93 | -------------------------------------------------------------------------------- /.jazzy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | author: OmiseGO 3 | author_url: https://omisego.network/ 4 | copyright: Copyright (c) 2017-present, Omise Go Pte. Ltd. All rights reserved. 5 | clean: true 6 | github_url: https://github.com/omisego/ios-sdk 7 | hide_documentation_coverage: true 8 | module: OmiseGO 9 | output: docs 10 | podspec: OmiseGO.podspec 11 | readme: README.md 12 | skip_undocumented: true 13 | theme: fullwidth 14 | source_directory: Source 15 | use_safe_filenames: true 16 | -------------------------------------------------------------------------------- /.swiftlint-test.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Tests 3 | line_length: 160 4 | disabled_rules: 5 | - identifier_name 6 | - force_try 7 | - force_cast 8 | - cyclomatic_complexity 9 | - function_body_length 10 | - type_body_length 11 | - weak_delegate 12 | - file_length 13 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Source 3 | line_length: 140 4 | disabled_rules: 5 | - identifier_name 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: swift 2 | osx_image: xcode10 3 | cache: 4 | - bundler 5 | - cocoapods 6 | env: 7 | matrix: 8 | - TEST_TYPE=iOS 9 | - TEST_TYPE=Lint 10 | - TEST_TYPE=CocoaPods 11 | install: 12 | - | 13 | if [ "$TEST_TYPE" = Lint ]; then 14 | brew install swiftlint || brew upgrade swiftlint 15 | elif [ "$TEST_TYPE" = CocoaPods ] || [ "$TEST_TYPE" = iOS ]; then 16 | bundle install --path vendor/bundle 17 | bundle exec pod repo update --silent 18 | fi 19 | if [ "$TEST_TYPE" = iOS ]; then 20 | bundle exec pod install 21 | fi 22 | script: 23 | - | 24 | if [ "$TEST_TYPE" = iOS ]; then 25 | set -o pipefail 26 | xcodebuild -workspace OmiseGO.xcworkspace -scheme "OmiseGO" -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone X" test | xcpretty -c 27 | elif [ "$TEST_TYPE" = Lint ]; then 28 | swiftlint lint --config .swiftlint.yml 29 | elif [ "$TEST_TYPE" = CocoaPods ]; then 30 | bundle exec pod lib lint --verbose 31 | fi 32 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Omise Go Pte. Ltd. 2 | Ryo Fukuda yuzushioh@gmail.com 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'jazzy', "0.9.5" 5 | gem 'cocoapods', "~> 1.5.3" 6 | gem 'xcpretty' 7 | gem 'github_changelog_generator' 8 | -------------------------------------------------------------------------------- /OmiseGO.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'OmiseGO' 3 | s.version = '1.1.2' 4 | s.license = 'Apache' 5 | s.summary = 'The OmiseGO iOS SDK allows developers to easily interact with a node of the OmiseGO eWallet.' 6 | s.homepage = 'https://github.com/omisego/ios-sdk' 7 | s.social_media_url = 'https://twitter.com/omise_go' 8 | s.authors = { 'OmiseGO team' => 'omg@omise.co' } 9 | s.source = { :git => 'https://github.com/omisego/ios-sdk.git', :tag => s.version } 10 | 11 | s.platform = :ios, '10.0' 12 | s.swift_version = '4.2' 13 | 14 | s.subspec 'Core' do |ss| 15 | ss.source_files = "Source/Core/**/*.swift" 16 | ss.dependency 'Starscream', '~> 3.0' 17 | ss.dependency 'BigInt', '~> 3.1' 18 | end 19 | 20 | s.subspec 'Client' do |ss| 21 | ss.source_files = "Source/Client/**/*.swift" 22 | ss.dependency 'OmiseGO/Core' 23 | end 24 | 25 | s.subspec 'Admin' do |ss| 26 | ss.source_files = "Source/Admin/**/*.swift" 27 | ss.dependency 'OmiseGO/Core' 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /OmiseGO.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OmiseGO.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /OmiseGO.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /OmiseGO.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '10.0' 3 | 4 | def shared_pods 5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 6 | use_frameworks! 7 | # websocket library 8 | pod 'Starscream', '~> 3.0' 9 | pod 'BigInt', '~> 3.1' 10 | end 11 | 12 | target 'OmiseGO' do 13 | shared_pods 14 | end 15 | 16 | target 'Tests' do 17 | shared_pods 18 | end 19 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - BigInt (3.1.0): 3 | - SipHash (~> 1.2) 4 | - SipHash (1.2.2) 5 | - Starscream (3.0.6) 6 | 7 | DEPENDENCIES: 8 | - BigInt (~> 3.1) 9 | - Starscream (~> 3.0) 10 | 11 | SPEC REPOS: 12 | https://github.com/cocoapods/specs.git: 13 | - BigInt 14 | - SipHash 15 | - Starscream 16 | 17 | SPEC CHECKSUMS: 18 | BigInt: 76b5dfdfa3e2e478d4ffdf161aeede5502e2742f 19 | SipHash: fad90a4683e420c52ef28063063dbbce248ea6d4 20 | Starscream: ef3ece99d765eeccb67de105bfa143f929026cf5 21 | 22 | PODFILE CHECKSUM: de86b509d6be5a0f236452ea05b50b8633136c66 23 | 24 | COCOAPODS: 1.5.3 25 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | JAZZY_CONFIG = '.jazzy.yml' 2 | 3 | desc 'Generate API Reference' 4 | task :docs do 5 | `jazzy --config #{JAZZY_CONFIG}` 6 | end 7 | 8 | task :changelog do 9 | `github_changelog_generator omisego/ios-sdk` 10 | end 11 | 12 | task :prepare_release do 13 | Rake::Task["docs"].invoke 14 | Rake::Task["changelog"].invoke 15 | end 16 | -------------------------------------------------------------------------------- /Source/Admin/API/AdminConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AdminConfiguration.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 8/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a configuration object used to setup an HTTPAPI 10 | public struct AdminConfiguration: Configuration { 11 | /// The current SDK version 12 | let apiVersion: String = "1" 13 | 14 | /// The base URL of the wallet server: 15 | /// When initializing the HTTPAPI, this needs to be an http(s) url 16 | /// When initializing the SocketClient, this needs to be a ws(s) url 17 | let baseURL: String 18 | var credentials: Credential 19 | let debugLog: Bool 20 | 21 | /// Creates the configuration required to initialize the OmiseGO SDK 22 | /// 23 | /// - Parameters: 24 | /// - baseURL: The base URL of the wallet server 25 | /// When initializing the HTTPAPI, this needs to be an http(s) url 26 | /// When initializing the SocketClient, this needs to be a ws(s) url 27 | /// - apiKey: The API key (typically generated on the admin panel) 28 | /// - authenticationToken: The authentication token of the current user 29 | /// - debugLog: Enable or not SDK console logs 30 | public init(baseURL: String, credentials: AdminCredential = AdminCredential(), debugLog: Bool = false) { 31 | self.baseURL = baseURL + "/api/admin" 32 | self.credentials = credentials 33 | self.debugLog = debugLog 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Source/Admin/API/AdminCredential.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AdminCredential.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 7/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | public struct AdminCredential: Credential { 10 | public var userId: String? 11 | public var authenticationToken: String? 12 | 13 | /// Initialize an AdminCredential object with the given userId and authentication token 14 | /// 15 | /// - Parameters: 16 | /// - userId: The userId of the admin to use for the authenticated calls. Can be nil if doing request that don't need authentication. 17 | /// - authenticationToken: The authentication token of the admin. Can be nil if doing request that don't need authentication. 18 | public init(userId: String, authenticationToken: String) { 19 | self.userId = userId 20 | self.authenticationToken = authenticationToken 21 | } 22 | 23 | public init() {} 24 | 25 | func isAuthenticated() -> Bool { return self.authenticationToken != nil && self.userId != nil } 26 | 27 | func authentication() throws -> String? { 28 | guard let authenticationToken = self.authenticationToken, let userId = self.userId else { 29 | return nil 30 | } 31 | return try CredentialEncoder.encode(value1: userId, value2: authenticationToken, scheme: "OMGAdmin") 32 | } 33 | 34 | mutating func update(withAuthenticationToken authenticationToken: AuthenticationToken) { 35 | self.userId = authenticationToken.user.id 36 | self.authenticationToken = authenticationToken.token 37 | } 38 | 39 | public mutating func invalidate() { 40 | self.userId = nil 41 | self.authenticationToken = nil 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/Admin/Models/Account+Admin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Account+Admin.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 18/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension Account: Filterable { 10 | public enum FilterableFields: String, RawEnumerable { 11 | case id 12 | case name 13 | case description 14 | case createdAt = "created_at" 15 | case updatedAt = "updated_at" 16 | case metadata 17 | } 18 | } 19 | 20 | extension Account: Sortable { 21 | public enum SortableFields: String, RawEnumerable { 22 | case id 23 | case name 24 | case description 25 | case createdAt = "created_at" 26 | case updatedAt = "updated_at" 27 | } 28 | } 29 | 30 | extension Account: PaginatedListable { 31 | @discardableResult 32 | /// Get a paginated list of accounts 33 | /// 34 | /// - Parameters: 35 | /// - client: An API client. 36 | /// This client need to be initialized with a AdminConfiguration struct before being used. 37 | /// - params: The pagination params object to use to scope the results 38 | /// - callback: The closure called when the request is completed 39 | /// - Returns: An optional cancellable request. 40 | public static func list(using client: HTTPAdminAPI, 41 | params: PaginatedListParams, 42 | callback: @escaping Account.PaginatedListRequestCallback) -> Account.PaginatedListRequest? { 43 | return self.list(using: client, endpoint: APIAdminEndpoint.getAccounts(params: params), callback: callback) 44 | } 45 | } 46 | 47 | extension Account: Retrievable { 48 | @discardableResult 49 | /// Get an account from its id 50 | /// 51 | /// - Parameters: 52 | /// - client: An API client. 53 | /// This client need to be initialized with a AdminConfiguration struct before being used. 54 | /// - params: The AccountGetParams params object containing the id of the account to retrieve 55 | /// - callback: The closure called when the request is completed 56 | /// - Returns: An optional cancellable request. 57 | public static func get(using client: HTTPAdminAPI, 58 | params: AccountGetParams, 59 | callback: @escaping Account.RetrieveRequestCallback) -> Account.RetrieveRequest? { 60 | return self.retrieve(using: client, endpoint: APIAdminEndpoint.getAccount(params: params), callback: callback) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Source/Admin/Models/AccountGetParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AccountGetParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 26/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a structure used to retrieve an account from its id 10 | public struct AccountGetParams: APIParameters { 11 | /// The id of the account to retrieve 12 | public let id: String 13 | 14 | /// Initialize the params used to retrive a account from its id 15 | /// 16 | /// - Parameters: 17 | /// - id: The id of the account to retrieve 18 | public init(id: String) { 19 | self.id = id 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/Admin/Models/Transaction+Admin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Transaction+Admin.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 19/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension Transaction { 10 | @discardableResult 11 | /// Create a new transaction 12 | /// 13 | /// - Parameters: 14 | /// - client: An API client. 15 | /// This client need to be initialized with a ClientConfiguration struct before being used. 16 | /// - params: The TransactionSendParams object to customize the transaction 17 | /// - callback: The closure called when the request is completed 18 | /// - Returns: An optional cancellable request. 19 | public static func create(using client: HTTPAdminAPI, 20 | params: TransactionCreateParams, 21 | callback: @escaping Transaction.RetrieveRequestCallback) -> Transaction.RetrieveRequest? { 22 | return self.retrieve(using: client, endpoint: APIAdminEndpoint.createTransaction(params: params), callback: callback) 23 | } 24 | 25 | @discardableResult 26 | /// Get a paginated list of transactions 27 | /// 28 | /// - Parameters: 29 | /// - client: An API client. 30 | /// This client need to be initialized with a ClientConfiguration struct before being used. 31 | /// - params: The PaginatedListParams object to use to scope the results 32 | /// - callback: The closure called when the request is completed 33 | /// - Returns: An optional cancellable request. 34 | public static func list(using client: HTTPAdminAPI, 35 | params: PaginatedListParams, 36 | callback: @escaping Transaction.PaginatedListRequestCallback) -> Transaction.PaginatedListRequest? { 37 | return self.list(using: client, endpoint: APIAdminEndpoint.getTransactions(params: params), callback: callback) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/Admin/Models/TransactionCreateParams+Admin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionCreateParams+Admin.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 19/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import BigInt 10 | 11 | extension TransactionCreateParams { 12 | public init(fromAddress: String?, 13 | toAddress: String?, 14 | amount: BigInt?, 15 | fromAmount: BigInt?, 16 | toAmount: BigInt?, 17 | fromTokenId: String?, 18 | toTokenId: String?, 19 | tokenId: String?, 20 | fromAccountId: String?, 21 | toAccountId: String?, 22 | fromProviderUserId: String?, 23 | toProviderUserId: String?, 24 | fromUserId: String?, 25 | toUserId: String?, 26 | idempotencyToken: String, 27 | exchangeAccountId: String?, 28 | exchangeAddress: String?, 29 | metadata: [String: Any], 30 | encryptedMetadata: [String: Any]) { 31 | self.fromAddress = fromAddress 32 | self.toAddress = toAddress 33 | self.amount = amount 34 | self.fromAmount = fromAmount 35 | self.toAmount = toAmount 36 | self.fromTokenId = fromTokenId 37 | self.toTokenId = toTokenId 38 | self.tokenId = tokenId 39 | self.fromAccountId = fromAccountId 40 | self.toAccountId = toAccountId 41 | self.fromProviderUserId = fromProviderUserId 42 | self.toProviderUserId = toProviderUserId 43 | self.fromUserId = fromUserId 44 | self.toUserId = toUserId 45 | self.idempotencyToken = idempotencyToken 46 | self.metadata = metadata 47 | self.encryptedMetadata = encryptedMetadata 48 | self.exchangeAddress = exchangeAddress 49 | self.exchangeAccountId = exchangeAccountId 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/Admin/Models/TransactionRequest+Admin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionRequest+Admin.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 8/10/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension TransactionRequest { 10 | @discardableResult 11 | /// Generate a transaction request from the given TransactionRequestParams object 12 | /// 13 | /// - Parameters: 14 | /// - client: An API client. 15 | /// This client need to be initialized with a AdminConfiguration struct before being used. 16 | /// - params: The TransactionRequestCreateParams object describing the transaction request to be made. 17 | /// - callback: The closure called when the request is completed 18 | /// - Returns: An optional cancellable request. 19 | public static func create(using client: HTTPAdminAPI, 20 | params: TransactionRequestCreateParams, 21 | callback: @escaping TransactionRequest.RetrieveRequestCallback) 22 | -> TransactionRequest.RetrieveRequest? { 23 | return self.retrieve(using: client, 24 | endpoint: APIAdminEndpoint.transactionRequestCreate(params: params), 25 | callback: callback) 26 | } 27 | 28 | @discardableResult 29 | /// Retreive a transaction request from its formatted id 30 | /// 31 | /// - Parameters: 32 | /// - client: An API client. 33 | /// This client need to be initialized with a AdminConfiguration struct before being used. 34 | /// - formattedId: The formatted id of the TransactionRequest to be retrived. 35 | /// - callback: The closure called when the request is completed 36 | /// - Returns: An optional cancellable request. 37 | public static func get(using client: HTTPAdminAPI, 38 | formattedId: String, 39 | callback: @escaping TransactionRequest.RetrieveRequestCallback) 40 | -> TransactionRequest.RetrieveRequest? { 41 | let params = TransactionRequestGetParams(formattedId: formattedId) 42 | return self.retrieve(using: client, 43 | endpoint: APIAdminEndpoint.transactionRequestGet(params: params), 44 | callback: callback) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Source/Admin/Models/WalletGetParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WalletGetParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 17/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a structure used to retrieve a wallet from its address 10 | public struct WalletGetParams: APIParameters { 11 | /// The address of the wallet to retrieve 12 | public let address: String 13 | 14 | /// Initialize the params used to retrive a wallet from its address 15 | /// 16 | /// - Parameters: 17 | /// - address: The address of the wallet to retrieve 18 | public init(address: String) { 19 | self.address = address 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/Admin/Models/WalletListForAccountParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WalletListForAccountParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 18/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// Represents a structure used to retrieve wallets for a specific user 12 | public struct WalletListForAccountParams { 13 | /// The pagination params 14 | public let paginatedListParams: PaginatedListParams 15 | /// The account id 16 | public let accountId: String 17 | /// Query only wallets belonging to the specified account OR also its children 18 | public let owned: Bool 19 | 20 | /// Initialize the params used to query a paginated list of wallets belonging to an account from its id 21 | /// 22 | /// - Parameters: 23 | /// - paginatedListParams: The params to use for the pagination 24 | /// - accountId: The id of the account 25 | public init(paginatedListParams: PaginatedListParams, 26 | accountId: String, 27 | owned: Bool) { 28 | self.paginatedListParams = paginatedListParams 29 | self.accountId = accountId 30 | self.owned = owned 31 | } 32 | } 33 | 34 | extension WalletListForAccountParams: APIParameters { 35 | private enum CodingKeys: String, CodingKey { 36 | case paginatedListParams 37 | case accountId = "id" 38 | case owned 39 | } 40 | 41 | public func encode(to encoder: Encoder) throws { 42 | var container = encoder.container(keyedBy: CodingKeys.self) 43 | try paginatedListParams.encode(to: encoder) 44 | try container.encode(accountId, forKey: .accountId) 45 | try container.encode(owned, forKey: .owned) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/Admin/Models/WalletListForUserParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WalletListForUserParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 17/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a structure used to retrieve wallets for a specific user 10 | public struct WalletListForUserParams { 11 | /// The pagination params 12 | public let paginatedListParams: PaginatedListParams 13 | /// The id of the user 14 | public let userId: String? 15 | /// The provider user id of the user 16 | public let providerUserId: String? 17 | 18 | /// Initialize the params used to query a paginated list of wallets belonging to a user from its userId 19 | /// 20 | /// - Parameters: 21 | /// - paginatedListParams: The params to use for the pagination 22 | /// - userId: The id of the user 23 | public init(paginatedListParams: PaginatedListParams, 24 | userId: String) { 25 | self.paginatedListParams = paginatedListParams 26 | self.userId = userId 27 | self.providerUserId = nil 28 | } 29 | 30 | /// Initialize the params used to query a paginated list of wallets belonging to a user from its providerUserId 31 | /// 32 | /// - Parameters: 33 | /// - paginatedListParams: The params to use for the pagination 34 | /// - providerUserId: The id of the user 35 | public init(paginatedListParams: PaginatedListParams, 36 | providerUserId: String) { 37 | self.paginatedListParams = paginatedListParams 38 | self.providerUserId = providerUserId 39 | self.userId = nil 40 | } 41 | } 42 | 43 | extension WalletListForUserParams: APIParameters { 44 | private enum CodingKeys: String, CodingKey { 45 | case paginatedListParams 46 | case userId = "id" 47 | case providerUserId = "provider_user_id" 48 | } 49 | 50 | public func encode(to encoder: Encoder) throws { 51 | var container = encoder.container(keyedBy: CodingKeys.self) 52 | try paginatedListParams.encode(to: encoder) 53 | try container.encodeIfPresent(userId, forKey: .userId) 54 | try container.encodeIfPresent(providerUserId, forKey: .providerUserId) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Source/Admin/Websocket/SocketClient+Admin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketClient+Admin.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 10/10/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension SocketClient { 10 | /// Initialize a websocket client using a configuration object 11 | /// 12 | /// - Parameters: 13 | /// - config: The configuration object containing the client configuration 14 | /// - delegate: The delegate that should receive connection events 15 | /// - Note: the baseURL of the Configuration needs to be a socket url (wss://your.domain.com) 16 | public convenience init(config: AdminConfiguration, delegate: SocketConnectionDelegate?) { 17 | self.init() 18 | self.config = config 19 | self.delegate = delegate 20 | self.initWebSocket() 21 | } 22 | 23 | /// Invalidate the current (if any) socket connection and prepare the client for a new one with the updated configuration. 24 | /// Note that the active connection will be droped and any topic currently subscribed will be unsubscribed. 25 | /// You will need to start listening for events again. 26 | /// 27 | /// - Parameter configuration: The updated Configuration 28 | public func updateConfiguration(_ configuration: AdminConfiguration) { 29 | self.config = configuration 30 | self.cleanup() 31 | self.initWebSocket() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/Client/API/ClientConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClientConfiguration.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 7/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a configuration object used to setup an HTTPAPI 10 | public struct ClientConfiguration: Configuration { 11 | /// The current SDK version 12 | let apiVersion: String = "1" 13 | 14 | /// The base URL of the wallet server: 15 | /// When initializing the HTTPAPI, this needs to be an http(s) url 16 | /// When initializing the SocketClient, this needs to be a ws(s) url 17 | let baseURL: String 18 | var credentials: Credential 19 | let debugLog: Bool 20 | 21 | /// Creates the configuration required to initialize the HTTPAPI in order to perform client API calls 22 | /// 23 | /// - Parameters: 24 | /// - baseURL: The base URL of the wallet server 25 | /// When initializing the HTTPAPI, this needs to be an http(s) url 26 | /// When initializing the SocketClient, this needs to be a ws(s) url 27 | /// - apiKey: The API key (typically generated on the admin panel) 28 | /// - authenticationToken: The authentication token of the current user 29 | /// - debugLog: Enable or not SDK console logs 30 | public init(baseURL: String, credentials: ClientCredential, debugLog: Bool = false) { 31 | self.baseURL = baseURL + "/api/client" 32 | self.credentials = credentials 33 | self.debugLog = debugLog 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Source/Client/API/ClientCredential.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClientCredential.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 7/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents the credentials needed for making client API calls. 10 | /// They consist on an API key and an authentication token. 11 | public struct ClientCredential: Credential { 12 | public let apiKey: String 13 | public var authenticationToken: String? 14 | 15 | /// Initialize a ClientCredential with the given API key and authentication token 16 | /// 17 | /// - Parameters: 18 | /// - apiKey: The API key to use for the authenticated calls 19 | /// - authenticationToken: The authentication token of the user. Can be nil if doing request that don't need authentication. 20 | public init(apiKey: String, authenticationToken: String? = nil) { 21 | self.apiKey = apiKey 22 | self.authenticationToken = authenticationToken 23 | } 24 | 25 | func isAuthenticated() -> Bool { 26 | return self.authenticationToken != nil 27 | } 28 | 29 | func authentication() throws -> String? { 30 | guard let authenticationToken = self.authenticationToken else { return nil } 31 | return try CredentialEncoder.encode(value1: self.apiKey, value2: authenticationToken, scheme: "OMGClient") 32 | } 33 | 34 | mutating func update(withAuthenticationToken authenticationToken: AuthenticationToken) { 35 | self.authenticationToken = authenticationToken.token 36 | } 37 | 38 | public mutating func invalidate() { 39 | self.authenticationToken = nil 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/Client/Models/Setting+Client.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Setting+Client.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 7/8/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension Setting: Retrievable { 10 | @discardableResult 11 | /// Get the global settings of the provider 12 | /// 13 | /// - Parameters: 14 | /// - client: An API client. 15 | /// This client need to be initialized with a ClientConfiguration struct before being used. 16 | /// - callback: The closure called when the request is completed 17 | /// - Returns: An optional cancellable request. 18 | public static func get(using client: HTTPClientAPI, 19 | callback: @escaping Setting.RetrieveRequestCallback) -> Setting.RetrieveRequest? { 20 | return self.retrieve(using: client, endpoint: APIClientEndpoint.getSettings, callback: callback) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Source/Client/Models/Transaction+Client.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Transaction+Client.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 7/8/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension Transaction { 10 | @discardableResult 11 | /// Create a new transaction 12 | /// 13 | /// - Parameters: 14 | /// - client: An API client. 15 | /// This client need to be initialized with a ClientConfiguration struct before being used. 16 | /// - params: The TransactionSendParams object to customize the transaction 17 | /// - callback: The closure called when the request is completed 18 | /// - Returns: An optional cancellable request. 19 | public static func create(using client: HTTPClientAPI, 20 | params: TransactionCreateParams, 21 | callback: @escaping Transaction.RetrieveRequestCallback) -> Transaction.RetrieveRequest? { 22 | return self.retrieve(using: client, endpoint: APIClientEndpoint.createTransaction(params: params), callback: callback) 23 | } 24 | 25 | @discardableResult 26 | /// Get a paginated list of transaction for the current user 27 | /// 28 | /// - Parameters: 29 | /// - client: An API client. 30 | /// This client need to be initialized with a ClientConfiguration struct before being used. 31 | /// - params: The TransactionListParams object to use to scope the results 32 | /// - callback: The closure called when the request is completed 33 | /// - Returns: An optional cancellable request. 34 | public static func list(using client: HTTPClientAPI, 35 | params: TransactionListParams, 36 | callback: @escaping Transaction.PaginatedListRequestCallback) -> Transaction.PaginatedListRequest? { 37 | return self.list(using: client, endpoint: APIClientEndpoint.getTransactions(params: params), callback: callback) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/Client/Models/TransactionListParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionListParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 23/2/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // Represents a structure used to query a list of transactions 12 | public struct TransactionListParams { 13 | /// The pagination params to use 14 | public let paginatedListParams: PaginatedListParams 15 | /// An optional wallet address owned by the current user 16 | public let address: String? 17 | 18 | /// Initialize the params used to query a paginated list of transactions 19 | /// 20 | /// - Parameters: 21 | /// - paginatedListParams: The pagination params to use 22 | /// - address: An optional wallet address belonging to the current user 23 | public init(paginatedListParams: PaginatedListParams, 24 | address: String? = nil) { 25 | self.paginatedListParams = paginatedListParams 26 | self.address = address 27 | } 28 | } 29 | 30 | extension TransactionListParams: APIParameters { 31 | private enum CodingKeys: String, CodingKey { 32 | case paginationParams 33 | case address 34 | } 35 | 36 | public func encode(to encoder: Encoder) throws { 37 | var container = encoder.container(keyedBy: CodingKeys.self) 38 | try container.encode(address, forKey: .address) 39 | try paginatedListParams.encode(to: encoder) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/Client/Models/TransactionRequest+Client.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionRequest.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 7/8/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension TransactionRequest { 10 | @discardableResult 11 | /// Generate a transaction request from the given TransactionRequestParams object 12 | /// 13 | /// - Parameters: 14 | /// - client: An API client. 15 | /// This client need to be initialized with a ClientConfiguration struct before being used. 16 | /// - params: The TransactionRequestCreateParams object describing the transaction request to be made. 17 | /// - callback: The closure called when the request is completed 18 | /// - Returns: An optional cancellable request. 19 | public static func create(using client: HTTPClientAPI, 20 | params: TransactionRequestCreateParams, 21 | callback: @escaping TransactionRequest.RetrieveRequestCallback) 22 | -> TransactionRequest.RetrieveRequest? { 23 | return self.retrieve(using: client, 24 | endpoint: APIClientEndpoint.transactionRequestCreate(params: params), 25 | callback: callback) 26 | } 27 | 28 | @discardableResult 29 | /// Retreive a transaction request from its formatted id 30 | /// 31 | /// - Parameters: 32 | /// - client: An API client. 33 | /// This client need to be initialized with a ClientConfiguration struct before being used. 34 | /// - formattedId: The formatted id of the TransactionRequest to be retrived. 35 | /// - callback: The closure called when the request is completed 36 | /// - Returns: An optional cancellable request. 37 | public static func get(using client: HTTPClientAPI, 38 | formattedId: String, 39 | callback: @escaping TransactionRequest.RetrieveRequestCallback) 40 | -> TransactionRequest.RetrieveRequest? { 41 | let params = TransactionRequestGetParams(formattedId: formattedId) 42 | return self.retrieve(using: client, 43 | endpoint: APIClientEndpoint.transactionRequestGet(params: params), 44 | callback: callback) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Source/Client/Models/UserResetPasswordParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserResetPasswordParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 14/3/19. 6 | // Copyright © 2019 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a structure used to request a password reset for the user 10 | public struct UserResetPasswordParams { 11 | /// The email of the user 12 | public let email: String 13 | /// The URL where the user will be taken when clicking the link in the email 14 | public let redirectUrl: String 15 | 16 | /// Initialize the params used to request a password reset for the user 17 | /// 18 | /// - Parameters: 19 | /// - email: The email of the user 20 | /// - redirectUrl: The URL where the user will be taken when clicking the link in the email 21 | public init(email: String, 22 | redirectUrl: String) { 23 | self.email = email 24 | self.redirectUrl = redirectUrl 25 | } 26 | } 27 | 28 | extension UserResetPasswordParams: APIParameters { 29 | private enum CodingKeys: String, CodingKey { 30 | case email 31 | case redirectUrl = "redirect_url" 32 | } 33 | 34 | public func encode(to encoder: Encoder) throws { 35 | var container = encoder.container(keyedBy: CodingKeys.self) 36 | try container.encode(email, forKey: .email) 37 | try container.encode(redirectUrl, forKey: .redirectUrl) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/Client/Models/UserUpdatePasswordParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserUpdatePasswordParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 14/3/19. 6 | // Copyright © 2019 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a structure used to update the password of a user following a reset 10 | public struct UserUpdatePasswordParams { 11 | /// The email of the user (obtained from the params in the link sent to the email of the user) 12 | public let email: String 13 | /// The unique reset password token obtained from the params in the link sent to the email of the user 14 | public let token: String? 15 | /// The updated password 16 | public let password: String 17 | /// The password confirmation that should match the updated password 18 | public let passwordConfirmation: String 19 | 20 | /// Initialize the params used to signup a user 21 | /// 22 | /// - Parameters: 23 | /// - email: The email of the user (obtained from the params in the link sent to the email of the user) 24 | /// - token: The unique reset password token obtained from the params in the link sent to the email of the user 25 | /// - password: The updated password 26 | /// - passwordConfirmation: The password confirmation that should match the updated password 27 | public init(email: String, 28 | token: String, 29 | password: String, 30 | passwordConfirmation: String) { 31 | self.email = email 32 | self.token = token 33 | self.password = password 34 | self.passwordConfirmation = passwordConfirmation 35 | } 36 | } 37 | 38 | extension UserUpdatePasswordParams: APIParameters { 39 | private enum CodingKeys: String, CodingKey { 40 | case email 41 | case token 42 | case password 43 | case passwordConfirmation = "password_confirmation" 44 | } 45 | 46 | public func encode(to encoder: Encoder) throws { 47 | var container = encoder.container(keyedBy: CodingKeys.self) 48 | try container.encode(email, forKey: .email) 49 | try container.encode(token, forKey: .token) 50 | try container.encode(password, forKey: .password) 51 | try container.encode(passwordConfirmation, forKey: .passwordConfirmation) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Source/Client/Models/Wallet+Client.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Wallet+Client.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 7/8/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension Wallet { 10 | @discardableResult 11 | /// Get all wallets of the current user 12 | /// 13 | /// - Parameters: 14 | /// - client: An API client. 15 | /// This client need to be initialized with a ClientConfiguration struct before being used. 16 | /// - callback: The closure called when the request is completed 17 | /// - Returns: An optional cancellable request. 18 | public static func getAll(using client: HTTPClientAPI, 19 | callback: @escaping Wallet.ListRequestCallback) -> Wallet.ListRequest? { 20 | return self.list(using: client, endpoint: APIClientEndpoint.getWallets, callback: callback) 21 | } 22 | 23 | @discardableResult 24 | /// Get the main wallet for the current user 25 | /// 26 | /// - Parameters: 27 | /// - client: An API client. 28 | /// This client need to be initialized with a ClientConfiguration struct before being used. 29 | /// - callback: The closure called when the request is completed 30 | /// - Returns: An optional cancellable request. 31 | public static func getMain(using client: HTTPClientAPI, 32 | callback: @escaping Wallet.RetrieveRequestCallback) -> Wallet.ListRequest? { 33 | return self.list(using: client, endpoint: APIClientEndpoint.getWallets, callback: { response in 34 | switch response { 35 | case let .success(data: wallets): 36 | if wallets.isEmpty { 37 | callback(Response.fail(error: OMGError.unexpected(message: "No wallet received."))) 38 | } else { 39 | callback(.success(data: wallets.first!)) 40 | } 41 | case let .fail(error: error): 42 | callback(.fail(error: error)) 43 | } 44 | 45 | }) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/Client/QRCode/QRClientVerifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRClientVerifier.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 7/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | public struct QRClientVerifier: QRVerifier { 10 | let client: HTTPClientAPI 11 | 12 | public init(client: HTTPClientAPI) { 13 | self.client = client 14 | } 15 | 16 | public func onData(data: String, callback: @escaping (Response) -> Void) { 17 | TransactionRequest.get(using: self.client, formattedId: data, callback: callback) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Source/Client/QRCode/QRScannerViewController+Client.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRScannerViewController+Client.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 8/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension QRScannerViewController { 10 | /// Initialize the QR code scanner. You should always use this method to initialize it. 11 | /// 12 | /// - Parameters: 13 | /// - delegate: The delegate that will receive the events from the scanner 14 | /// - verifier: A QRClientVerifier that will take care of processing the scanned data 15 | /// - cancelButtonTitle: The title of the cancel button 16 | /// - Returns: An optional cancellable request. 17 | public convenience init?(delegate: QRScannerViewControllerDelegate, verifier: QRClientVerifier, cancelButtonTitle: String) { 18 | self.init(delegate: delegate, 19 | verifier: verifier, 20 | cancelButtonTitle: cancelButtonTitle, 21 | viewModel: QRScannerViewModel(verifier: verifier)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/Client/Websocket/SocketClient+Client.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketClient+Client.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 8/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | extension SocketClient { 10 | /// Initialize a websocket client using a configuration object 11 | /// 12 | /// - Parameters: 13 | /// - config: The configuration object containing the client configuration 14 | /// - delegate: The delegate that should receive connection events 15 | /// - Note: the baseURL of the Configuration needs to be a socket url (wss://your.domain.com) 16 | public convenience init(config: ClientConfiguration, delegate: SocketConnectionDelegate?) { 17 | self.init() 18 | self.config = config 19 | self.delegate = delegate 20 | self.initWebSocket() 21 | } 22 | 23 | /// Invalidate the current (if any) socket connection and prepare the client for a new one with the updated configuration. 24 | /// Note that the active connection will be droped and any topic currently subscribed will be unsubscribed. 25 | /// You will need to start listening for events again. 26 | /// 27 | /// - Parameter configuration: The updated Configuration 28 | public func updateConfiguration(_ configuration: ClientConfiguration) { 29 | self.config = configuration 30 | self.cleanup() 31 | self.initWebSocket() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/Core/API/APIEndpoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // APIEndpoint.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 9/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Protocol with the required variable to build an enpoint 10 | protocol APIEndpoint { 11 | var path: String { get } 12 | var task: HTTPTask { get } 13 | } 14 | -------------------------------------------------------------------------------- /Source/Core/API/Configuration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Configuration.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 9/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Protocol containing the required variable for the initialization of a Client 10 | protocol Configuration { 11 | /// The current SDK version 12 | var apiVersion: String { get } 13 | /// The base URL of the wallet server: 14 | /// When initializing the HTTPAPI, this needs to be an http(s) url 15 | /// When initializing the SocketClient, this needs to be a ws(s) url 16 | var baseURL: String { get } 17 | /// The credential object containing the authentication info if needed 18 | var credentials: Credential { get set } 19 | /// A boolean indicating if the debug logs should be printed to the console 20 | var debugLog: Bool { get } 21 | } 22 | -------------------------------------------------------------------------------- /Source/Core/API/Credential.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Credential.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 6/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Contains the required functions that a configuration object would need to authenticate an API call if needed 10 | protocol Credential { 11 | func isAuthenticated() -> Bool 12 | func authentication() throws -> String? 13 | mutating func update(withAuthenticationToken authenticationToken: AuthenticationToken) 14 | mutating func invalidate() 15 | } 16 | -------------------------------------------------------------------------------- /Source/Core/API/CredentialEncoder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CredentialEncoder.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 6/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | struct CredentialEncoder { 10 | static func encode(value1: String, value2: String, scheme: String) throws -> String { 11 | let keys = "\(value1):\(value2)" 12 | let data = keys.data(using: .utf8, allowLossyConversion: false) 13 | 14 | guard let encodedKey = data?.base64EncodedString() else { 15 | throw OMGError.configuration(message: "Failed to encode authorization header") 16 | } 17 | 18 | return "\(scheme) \(encodedKey)" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/Core/API/HTTPAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPAPI.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 9/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents an HTTPAPI that should be initialized using a Configuration 10 | public class HTTPAPI { 11 | let operationQueue: OperationQueue = OperationQueue() 12 | 13 | lazy var session: URLSession = { 14 | URLSession(configuration: URLSessionConfiguration.ephemeral, 15 | delegate: nil, 16 | delegateQueue: self.operationQueue) 17 | }() 18 | 19 | var config: Configuration 20 | 21 | init(config: Configuration) { 22 | self.config = config 23 | } 24 | 25 | /// A boolean indicating if the client is authenticated and allowed to make authenticated requests 26 | public var isAuthenticated: Bool { return self.config.credentials.isAuthenticated() } 27 | 28 | @discardableResult 29 | func request(toEndpoint endpoint: APIEndpoint, 30 | callback: Request.Callback?) -> Request? { 31 | do { 32 | let request: Request = Request(client: self, 33 | endpoint: endpoint, 34 | callback: callback) 35 | return try request.start() 36 | } catch let error as OMGError { 37 | performCallback { 38 | callback?(.fail(error: error)) 39 | } 40 | } catch let error as EncodingError { 41 | switch error { 42 | case let .invalidValue(_, context): 43 | performCallback { 44 | callback?(.fail(error: OMGError.unexpected(message: context.debugDescription))) 45 | } 46 | } 47 | } catch _ { 48 | self.performCallback { 49 | callback?(.fail(error: OMGError.unexpected(message: "Could not build the request"))) 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | 56 | private func performCallback(_ callback: @escaping () -> Void) { 57 | OperationQueue.main.addOperation(callback) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Source/Core/API/HTTPTask.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPTask.swift 3 | // OmiseGO 4 | // 5 | // Created by yuzushioh on2017-2018/05/11. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Protocol for api parameters 10 | public protocol APIParameters: Encodable {} 11 | 12 | extension APIParameters { 13 | public func encodedPayload() throws -> Data { 14 | return try serialize(self) 15 | } 16 | } 17 | 18 | /// Represents an HTTP task. 19 | enum HTTPTask { 20 | /// A request with no additional data. 21 | case requestPlain 22 | /// A requests body set with encoded parameters. 23 | case requestParameters(parameters: APIParameters) 24 | 25 | /// Parameters required for task's request 26 | /// nil if tasks do not require any parameters 27 | public var parameters: APIParameters? { 28 | switch self { 29 | case let .requestParameters(parameters): 30 | return parameters 31 | case .requestPlain: 32 | return nil 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Source/Core/API/RequestBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestBuilder.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 16/3/18. 6 | // 7 | 8 | import UIKit 9 | 10 | final class RequestBuilder { 11 | private let configuration: Configuration 12 | 13 | init(configuration: Configuration) { 14 | self.configuration = configuration 15 | } 16 | 17 | func buildHTTPURLRequest(withEndpoint endpoint: APIEndpoint) throws -> URLRequest { 18 | guard let requestURL = URL(string: self.configuration.baseURL)?.appendingPathComponent(endpoint.path) else { 19 | throw OMGError.configuration(message: "Invalid base url") 20 | } 21 | 22 | var request = URLRequest(url: requestURL) 23 | request.httpMethod = "POST" 24 | request.cachePolicy = .useProtocolCachePolicy 25 | request.timeoutInterval = 6.0 26 | 27 | try addRequiredHeaders(toRequest: &request) 28 | 29 | // Add endpoint's task parameters if necessary 30 | if let parameters = endpoint.task.parameters { 31 | let payload = try parameters.encodedPayload() 32 | request.httpBody = payload 33 | request.addValue(String(payload.count), forHTTPHeaderField: "Content-Length") 34 | } 35 | 36 | return request 37 | } 38 | 39 | func buildWebsocketRequest() throws -> URLRequest { 40 | guard let url = URL(string: self.configuration.baseURL + "/socket") else { 41 | throw OMGError.configuration(message: "Invalid base url") 42 | } 43 | 44 | var request = URLRequest(url: url) 45 | request.timeoutInterval = 6.0 46 | try addRequiredHeaders(toRequest: &request) 47 | return request 48 | } 49 | 50 | func contentTypeHeader() -> String { 51 | return "application/vnd.omisego.v\(self.configuration.apiVersion)+json; charset=utf-8" 52 | } 53 | 54 | func acceptHeader() -> String { 55 | return "application/vnd.omisego.v\(self.configuration.apiVersion)+json" 56 | } 57 | 58 | private func addRequiredHeaders(toRequest request: inout URLRequest) throws { 59 | if let auth = try self.configuration.credentials.authentication() { 60 | request.addValue(auth, forHTTPHeaderField: "Authorization") 61 | } 62 | request.addValue(self.acceptHeader(), forHTTPHeaderField: "Accept") 63 | request.addValue(self.contentTypeHeader(), forHTTPHeaderField: "Content-Type") 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Source/Core/Models/AuthenticationToken.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AuthenticationToken.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 15/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | public struct AuthenticationToken { 10 | /// The unique authentication token corresponding to the provided credentials 11 | public let token: String 12 | /// The user corresponding to the token 13 | public let user: User 14 | } 15 | 16 | extension AuthenticationToken: Decodable { 17 | private enum CodingKeys: String, CodingKey { 18 | case token = "authentication_token" 19 | case user 20 | } 21 | 22 | public init(from decoder: Decoder) throws { 23 | let container = try decoder.container(keyedBy: CodingKeys.self) 24 | token = try container.decode(String.self, forKey: .token) 25 | user = try container.decode(User.self, forKey: .user) 26 | } 27 | } 28 | 29 | extension AuthenticationToken: Hashable { 30 | public var hashValue: Int { 31 | return self.token.hashValue 32 | } 33 | 34 | public static func == (lhs: AuthenticationToken, rhs: AuthenticationToken) -> Bool { 35 | return lhs.token == rhs.token 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/Core/Models/Avatar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Avatar.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 18/4/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents an avatar containing urls of different sizes 10 | public struct Avatar: Decodable { 11 | /// The url of the original image 12 | public let original: String? 13 | /// The url of the large image 14 | public let large: String? 15 | /// The url of the small image 16 | public let small: String? 17 | /// The url of the thumbnail image 18 | public let thumb: String? 19 | } 20 | -------------------------------------------------------------------------------- /Source/Core/Models/Balance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Balance.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 12/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import BigInt 10 | 11 | /// Represents a balance of a token 12 | public struct Balance: Decodable { 13 | /// The token corresponding to the balance 14 | public let token: Token 15 | /// The total amount of token available 16 | public let amount: BigInt 17 | } 18 | 19 | extension Balance { 20 | /// Helper method that returns an easily readable value of the amount 21 | /// 22 | /// - Parameter precision: The decimal precision to give to the formatter 23 | /// for example a number 0.123 with a precision of 1 will be 0.1 24 | /// - Returns: the formatted balance amount 25 | public func displayAmount(withPrecision precision: Int = 1000) -> String { 26 | return OMGNumberFormatter(precision: precision).string(from: self.amount, subunitToUnit: self.token.subUnitToUnit) 27 | } 28 | } 29 | 30 | extension Balance: Hashable { 31 | public var hashValue: Int { 32 | return self.token.hashValue 33 | } 34 | 35 | public static func == (lhs: Balance, rhs: Balance) -> Bool { 36 | return lhs.token == rhs.token 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/Core/Models/CollectionParams/PaginatedListParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PaginatedListParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 17/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol RawEnumerable: Hashable, RawRepresentable, Encodable {} 12 | 13 | public struct PaginatedListParams { 14 | let sortParams: SortParams 15 | let filterParams: FilterParams? 16 | let paginationParams: PaginationParams 17 | 18 | /// Initialize the params used to query a paginated collection 19 | /// 20 | /// - Parameters: 21 | /// - page: The page requested (0 and 1 are the same) 22 | /// - perPage: The number of result expected per page 23 | /// - filters: A FilterParams struc used to filter the results 24 | /// - sortBy: The field to sort by 25 | /// - sortDirection: The sort direction (ascending or descending) 26 | public init(page: Int, 27 | perPage: Int, 28 | filters: FilterParams? = nil, 29 | sortBy: T.SortableFields, 30 | sortDirection: SortDirection) { 31 | self.paginationParams = PaginationParams(page: page, perPage: perPage) 32 | self.filterParams = filters 33 | self.sortParams = SortParams(sortBy: sortBy, sortDirection: sortDirection) 34 | } 35 | } 36 | 37 | extension PaginatedListParams: APIParameters { 38 | public func encode(to encoder: Encoder) throws { 39 | try self.sortParams.encode(to: encoder) 40 | try self.filterParams?.encode(to: encoder) 41 | try self.paginationParams.encode(to: encoder) 42 | } 43 | } 44 | 45 | extension PaginatedListable { 46 | public static func paginatedListParams(page: Int, 47 | perPage: Int, 48 | filters: FilterParams? = nil, 49 | sortBy: SortableFields, 50 | sortDirection: SortDirection) -> PaginatedListParams { 51 | return PaginatedListParams(page: page, 52 | perPage: perPage, 53 | filters: filters, 54 | sortBy: sortBy, 55 | sortDirection: sortDirection) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Source/Core/Models/CollectionParams/PaginationParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PaginationParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 17/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a structure used to query a paginated list 10 | struct PaginationParams { 11 | /// The page requested (0 and 1 are the same) 12 | public let page: Int 13 | /// The number of result expected per page 14 | public let perPage: Int 15 | 16 | /// Initialize the params used to query a paginated collection 17 | /// 18 | /// - Parameters: 19 | /// - page: The page requested (0 and 1 are the same) 20 | /// - perPage: The number of result expected per page 21 | public init(page: Int, 22 | perPage: Int) { 23 | self.page = page 24 | self.perPage = perPage 25 | } 26 | } 27 | 28 | extension PaginationParams: APIParameters { 29 | enum CodingKeys: String, CodingKey { 30 | case page 31 | case perPage = "per_page" 32 | } 33 | 34 | public func encode(to encoder: Encoder) throws { 35 | var container = encoder.container(keyedBy: CodingKeys.self) 36 | try container.encode(page, forKey: .page) 37 | try container.encode(perPage, forKey: .perPage) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/Core/Models/CollectionParams/SortParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SortParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 17/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// The desired sort direction 10 | /// 11 | /// - ascending: Ascending 12 | /// - descending: Descending 13 | public enum SortDirection: String, Encodable { 14 | case ascending = "asc" 15 | case descending = "desc" 16 | } 17 | 18 | public protocol Sortable { 19 | associatedtype SortableFields: RawEnumerable where SortableFields.RawValue == String 20 | } 21 | 22 | /// Represents a structure used to query a sortable list 23 | struct SortParams { 24 | /// The field to sort by 25 | public let sortBy: T.SortableFields 26 | /// The sort direction (ascending or descending) 27 | public let sortDirection: SortDirection 28 | 29 | /// Initialize the params used to query a sortable collection 30 | /// 31 | /// - Parameters: 32 | /// - sortBy: The field to sort by 33 | /// - sortDirection: The sort direction (ascending or descending) 34 | public init(sortBy: T.SortableFields, 35 | sortDirection: SortDirection) { 36 | self.sortBy = sortBy 37 | self.sortDirection = sortDirection 38 | } 39 | } 40 | 41 | extension SortParams: APIParameters { 42 | enum CodingKeys: String, CodingKey { 43 | case sortBy = "sort_by" 44 | case sortDirection = "sort_dir" 45 | } 46 | 47 | public func encode(to encoder: Encoder) throws { 48 | var container = encoder.container(keyedBy: CodingKeys.self) 49 | try container.encode(self.sortBy, forKey: .sortBy) 50 | try container.encode(self.sortDirection, forKey: .sortDirection) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Source/Core/Models/EmptyResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EmptyResponse.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 9/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | // Represents an empty response from the server. 10 | public struct EmptyResponse: Decodable {} 11 | -------------------------------------------------------------------------------- /Source/Core/Models/ExchangePair.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExchangePair.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 29/6/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// An ExchangePair describes 2 tradable tokens with a specific rate 12 | public struct ExchangePair { 13 | /// The unique identifier of the exchange pair 14 | public let id: String 15 | /// The name of the pair (ex: ETH/BTC) 16 | public let name: String 17 | /// The 1st token id of the pair 18 | public let fromTokenId: String 19 | /// The 1st token of the pair 20 | public let fromToken: Token 21 | /// The 2nd token id of the pair 22 | public let toTokenId: String 23 | /// The 2nd token of the pair 24 | public let toToken: Token 25 | /// The rate between both tokens (token2/token1) 26 | public let rate: Double 27 | /// The creation date of the pair 28 | public let createdAt: Date 29 | /// The last update date of the pair 30 | public let updatedAt: Date 31 | } 32 | 33 | extension ExchangePair: Decodable { 34 | private enum CodingKeys: String, CodingKey { 35 | case id 36 | case name 37 | case fromTokenId = "from_token_id" 38 | case fromToken = "from_token" 39 | case toTokenId = "to_token_id" 40 | case toToken = "to_token" 41 | case rate 42 | case createdAt = "created_at" 43 | case updatedAt = "updated_at" 44 | } 45 | 46 | public init(from decoder: Decoder) throws { 47 | let container = try decoder.container(keyedBy: CodingKeys.self) 48 | id = try container.decode(String.self, forKey: .id) 49 | name = try container.decode(String.self, forKey: .name) 50 | fromTokenId = try container.decode(String.self, forKey: .fromTokenId) 51 | fromToken = try container.decode(Token.self, forKey: .fromToken) 52 | toTokenId = try container.decode(String.self, forKey: .toTokenId) 53 | toToken = try container.decode(Token.self, forKey: .toToken) 54 | rate = try container.decode(Double.self, forKey: .rate) 55 | createdAt = try container.decode(Date.self, forKey: .createdAt) 56 | updatedAt = try container.decode(Date.self, forKey: .updatedAt) 57 | } 58 | } 59 | 60 | extension ExchangePair: Hashable { 61 | public var hashValue: Int { 62 | return self.id.hashValue 63 | } 64 | 65 | public static func == (lhs: ExchangePair, rhs: ExchangePair) -> Bool { 66 | return lhs.id == rhs.id 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Source/Core/Models/JSONListResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSONListResponse.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 10/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a list response containing a data array of generic items. 10 | public struct JSONListResponse: Decodable { 11 | let data: [Item] 12 | } 13 | 14 | /// Represents a list response containing a data array of generic items and a pagination object. 15 | public struct JSONPaginatedListResponse: Decodable { 16 | public let data: [Item] 17 | public let pagination: Pagination 18 | } 19 | -------------------------------------------------------------------------------- /Source/Core/Models/JSONResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSONResponse.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 10/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | struct JSONResponse { 10 | let version: String 11 | let success: Bool 12 | let data: Response 13 | } 14 | 15 | extension JSONResponse: Decodable { 16 | private enum CodingKeys: String, CodingKey { 17 | case version 18 | case success 19 | case data 20 | } 21 | 22 | init(from decoder: Decoder) throws { 23 | let container = try decoder.container(keyedBy: CodingKeys.self) 24 | version = try container.decode(String.self, forKey: .version) 25 | success = try container.decode(Bool.self, forKey: .success) 26 | if self.success { 27 | let result = try container.decode(ObjectType.self, forKey: .data) 28 | data = .success(data: result) 29 | } else { 30 | let error = try container.decode(APIError.self, forKey: .data) 31 | data = .fail(error: .api(apiError: error)) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/Core/Models/LoginParams.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginParams.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 15/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a structure used to login an existing user 10 | public struct LoginParams { 11 | public let email: String 12 | public let password: String 13 | 14 | /// Initialize the params used to login a user 15 | /// 16 | /// - Parameters: 17 | /// - email: The email of the user 18 | /// - password: The password of the user 19 | public init(email: String, password: String) { 20 | self.email = email 21 | self.password = password 22 | } 23 | } 24 | 25 | extension LoginParams: APIParameters { 26 | private enum CodingKeys: String, CodingKey { 27 | case email 28 | case password 29 | } 30 | 31 | public func encode(to encoder: Encoder) throws { 32 | var container = encoder.container(keyedBy: CodingKeys.self) 33 | try container.encode(email, forKey: .email) 34 | try container.encode(password, forKey: .password) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Source/Core/Models/Pagination.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Pagination.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 23/2/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a pagination object contained in a paginated list response 10 | public struct Pagination: Decodable { 11 | /// The number of result per page 12 | public let perPage: Int 13 | /// The current page requested 14 | public let currentPage: Int 15 | /// Indicates if the page requested is the first one 16 | public let isFirstPage: Bool 17 | /// Indicates if the page requested is the last one 18 | public let isLastPage: Bool 19 | 20 | private enum CodingKeys: String, CodingKey { 21 | case perPage = "per_page" 22 | case currentPage = "current_page" 23 | case isFirstPage = "is_first_page" 24 | case isLastPage = "is_last_page" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/Core/Models/Reponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Response.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 9/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents whether an API request was successfull or encountered an error. 10 | /// 11 | /// - success: The request and post processing operations were successful resulting in the serialization 12 | /// of the provided associated Data 13 | /// - fail: The request encountered an error resulting in a failure 14 | public enum Response { 15 | case success(data: Data) 16 | case fail(error: OMGError) 17 | } 18 | -------------------------------------------------------------------------------- /Source/Core/Models/Setting.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Setting.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 12/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents the global settings of the eWallet 10 | public struct Setting: Decodable { 11 | /// An array of tokens available 12 | public let tokens: [Token] 13 | } 14 | -------------------------------------------------------------------------------- /Source/Core/Models/Token.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Token.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 12/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import BigInt 10 | 11 | /// Represents a token 12 | public struct Token { 13 | /// The id of the token 14 | public let id: String 15 | /// The symbol of the token 16 | public let symbol: String 17 | /// The full name of the token 18 | public let name: String 19 | /// The multiplier representing the value of 1 token. i.e: if I want to give or receive 20 | /// 13 tokens and the subunitToUnit is 1000 then the amount will be 13*1000 = 13000 21 | public let subUnitToUnit: BigInt 22 | /// Any additional metadata that need to be stored as a dictionary 23 | public let metadata: [String: Any] 24 | /// Any additional encrypted metadata that need to be stored as a dictionary 25 | public let encryptedMetadata: [String: Any] 26 | /// The creation date of the token 27 | public let createdAt: Date 28 | /// The last update date of the token 29 | public let updatedAt: Date 30 | } 31 | 32 | extension Token: Decodable { 33 | private enum CodingKeys: String, CodingKey { 34 | case id 35 | case symbol 36 | case name 37 | case subUnitToUnit = "subunit_to_unit" 38 | case metadata 39 | case encryptedMetadata = "encrypted_metadata" 40 | case createdAt = "created_at" 41 | case updatedAt = "updated_at" 42 | } 43 | 44 | public init(from decoder: Decoder) throws { 45 | let container = try decoder.container(keyedBy: CodingKeys.self) 46 | id = try container.decode(String.self, forKey: .id) 47 | symbol = try container.decode(String.self, forKey: .symbol) 48 | name = try container.decode(String.self, forKey: .name) 49 | subUnitToUnit = try container.decode(BigInt.self, forKey: .subUnitToUnit) 50 | metadata = try container.decode([String: Any].self, forKey: .metadata) 51 | encryptedMetadata = try container.decode([String: Any].self, forKey: .encryptedMetadata) 52 | createdAt = try container.decode(Date.self, forKey: .createdAt) 53 | updatedAt = try container.decode(Date.self, forKey: .updatedAt) 54 | } 55 | } 56 | 57 | extension Token: Hashable { 58 | public var hashValue: Int { 59 | return self.id.hashValue 60 | } 61 | 62 | public static func == (lhs: Token, rhs: Token) -> Bool { 63 | return lhs.id == rhs.id 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Source/Core/Models/TransactionExchange.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionExchange.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 27/2/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents a transaction exchange 10 | public struct TransactionExchange { 11 | /// The exchange rate used in the transaction. This can be nil if there was no exchange involved. 12 | public let rate: Double? 13 | /// The date when the exchange was processed 14 | public let calculatedAt: Date? 15 | /// The id of the exchange pair used 16 | public let exchangePairId: String? 17 | /// The exchange pair used in the exchange (if any) 18 | public let exchangePair: ExchangePair? 19 | /// The id of the account used for exchanging the funds 20 | public let exchangeAccountId: String? 21 | /// The account used for exchanging the funds 22 | public let exchangeAccount: Account? 23 | /// The address of the wallet used for exchanging the funds 24 | public let exchangeWalletAddress: String? 25 | /// The wallet used for exchanging the funds 26 | public let exchangeWallet: Wallet? 27 | } 28 | 29 | extension TransactionExchange: Decodable { 30 | private enum CodingKeys: String, CodingKey { 31 | case rate 32 | case calculatedAt = "calculated_at" 33 | case exchangePairId = "exchange_pair_id" 34 | case exchangePair = "exchange_pair" 35 | case exchangeAccountId = "exchange_account_id" 36 | case exchangeAccount = "exchange_account" 37 | case exchangeWalletAddress = "exchange_wallet_address" 38 | case exchangeWallet = "exchange_wallet" 39 | } 40 | 41 | public init(from decoder: Decoder) throws { 42 | let container = try decoder.container(keyedBy: CodingKeys.self) 43 | rate = try container.decodeIfPresent(Double.self, forKey: .rate) 44 | calculatedAt = try container.decodeIfPresent(Date.self, forKey: .calculatedAt) 45 | exchangePairId = try container.decodeIfPresent(String.self, forKey: .exchangePairId) 46 | exchangePair = try container.decodeIfPresent(ExchangePair.self, forKey: .exchangePair) 47 | exchangeAccountId = try container.decodeIfPresent(String.self, forKey: .exchangeAccountId) 48 | exchangeAccount = try container.decodeIfPresent(Account.self, forKey: .exchangeAccount) 49 | exchangeWalletAddress = try container.decodeIfPresent(String.self, forKey: .exchangeWalletAddress) 50 | exchangeWallet = try container.decodeIfPresent(Wallet.self, forKey: .exchangeWallet) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Source/Core/Models/TransactionSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionSource.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 27/2/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import BigInt 10 | 11 | /// Represents a transaction source contained in a transaction object 12 | public struct TransactionSource { 13 | /// The address of the source 14 | public let address: String 15 | /// The amount of token (down to subunit to unit) 16 | public let amount: BigInt 17 | /// The token of the source 18 | public let token: Token 19 | /// The user corresponding to the source (if any) 20 | public let user: User? 21 | /// The account corresponding to the source (if any) 22 | public let account: Account? 23 | } 24 | 25 | extension TransactionSource: Decodable { 26 | private enum CodingKeys: String, CodingKey { 27 | case address 28 | case amount 29 | case token 30 | case user 31 | case account 32 | } 33 | 34 | public init(from decoder: Decoder) throws { 35 | let container = try decoder.container(keyedBy: CodingKeys.self) 36 | address = try container.decode(String.self, forKey: .address) 37 | amount = try container.decode(BigInt.self, forKey: .amount) 38 | token = try container.decode(Token.self, forKey: .token) 39 | user = try container.decodeIfPresent(User.self, forKey: .user) 40 | account = try container.decodeIfPresent(Account.self, forKey: .account) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Source/Core/Operations/Listable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Listable.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 12/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represents an object that can be retrived in a collection 10 | public protocol Listable {} 11 | 12 | public extension Listable where Self: Decodable { 13 | public typealias ListRequest = Request> 14 | public typealias ListRequestCallback = (Response<[Self]>) -> Void 15 | 16 | @discardableResult 17 | internal static func list(using client: HTTPAPI, 18 | endpoint: APIEndpoint, 19 | callback: @escaping ListRequestCallback) -> ListRequest? { 20 | return client.request(toEndpoint: endpoint, callback: { result in 21 | switch result { 22 | case let .success(list): 23 | callback(.success(data: list.data)) 24 | case let .fail(error): 25 | callback(.fail(error: error)) 26 | } 27 | }) 28 | } 29 | } 30 | 31 | /// Represents an object that can be retrieved in a paginated collection 32 | public protocol PaginatedListable: Filterable, Sortable {} 33 | 34 | public extension PaginatedListable where Self: Decodable { 35 | public typealias PaginatedListRequest = Request> 36 | public typealias PaginatedListRequestCallback = (Response>) -> Void 37 | 38 | @discardableResult 39 | internal static func list(using client: HTTPAPI, 40 | endpoint: APIEndpoint, 41 | callback: @escaping PaginatedListRequestCallback) -> PaginatedListRequest? { 42 | return client.request(toEndpoint: endpoint, callback: { result in 43 | switch result { 44 | case let .success(list): 45 | callback(.success(data: list)) 46 | case let .fail(error): 47 | callback(.fail(error: error)) 48 | } 49 | }) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/Core/Operations/QREncodable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QREncodable.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 5/6/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// A protocol that takes care of the encoding and generating QR images of different structs 10 | public protocol QREncodable { 11 | func qrImage(withSize size: CGSize) -> UIImage? 12 | } 13 | 14 | public extension QREncodable where Self == TransactionRequest { 15 | /// Generates a QR image containing the encoded transaction request formattedId 16 | /// 17 | /// - Parameter size: the desired image size 18 | /// - Returns: A QR image if the transaction request was successfuly encoded, nil otherwise. 19 | public func qrImage(withSize size: CGSize = CGSize(width: 200, height: 200)) -> UIImage? { 20 | guard let data = self.formattedId.data(using: .isoLatin1) else { return nil } 21 | return QRGenerator.generateQRCode(fromData: data, outputSize: size) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/Core/Operations/Retrievable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Retrievable.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 11/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Represent an Object that can be uniquely retrived 10 | public protocol Retrievable {} 11 | 12 | public extension Retrievable where Self: Decodable { 13 | public typealias RetrieveRequest = Request 14 | public typealias RetrieveRequestCallback = RetrieveRequest.Callback 15 | 16 | @discardableResult 17 | internal static func retrieve(using client: HTTPAPI, 18 | endpoint: T, 19 | callback: @escaping RetrieveRequestCallback) -> RetrieveRequest? { 20 | return client.request(toEndpoint: endpoint, callback: callback) 21 | } 22 | 23 | @discardableResult 24 | internal func retrieve(using client: HTTPAPI, 25 | endpoint: T, 26 | callback: @escaping RetrieveRequestCallback) -> RetrieveRequest? { 27 | return client.request(toEndpoint: endpoint, callback: callback) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Source/Core/QRCode/QRGenerator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRGenerator.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 6/2/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct QRGenerator { 12 | static func generateQRCode(fromData data: Data, outputSize: CGSize) -> UIImage? { 13 | guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil } 14 | 15 | qrFilter.setDefaults() 16 | qrFilter.setValue(data, forKey: "inputMessage") 17 | 18 | guard let ciImage = qrFilter.outputImage else { return nil } 19 | 20 | let ciImageSize = ciImage.extent.size 21 | let wRatio = outputSize.width / ciImageSize.width 22 | let hRatio = outputSize.height / ciImageSize.height 23 | let transform = CGAffineTransform(scaleX: wRatio, y: hRatio) 24 | let scaledImage = ciImage.transformed(by: transform) 25 | let ciContext = CIContext() 26 | guard let cgImage = ciContext.createCGImage(scaledImage, from: scaledImage.extent) else { return nil } 27 | return UIImage(cgImage: cgImage) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Source/Core/QRCode/QRScannerLoadingView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRScannerLoadingView.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 12/2/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class QRScannerLoadingView: UIView { 12 | lazy var loadingSpinner: UIActivityIndicatorView = { 13 | let spinner = UIActivityIndicatorView(style: UIActivityIndicatorView.Style.whiteLarge) 14 | spinner.hidesWhenStopped = true 15 | spinner.translatesAutoresizingMaskIntoConstraints = false 16 | self.addSubview(spinner) 17 | [NSLayoutConstraint.Attribute.centerX, NSLayoutConstraint.Attribute.centerY].forEach({ attribute in 18 | self.addConstraint(NSLayoutConstraint(item: spinner, 19 | attribute: attribute, 20 | relatedBy: .equal, 21 | toItem: self, 22 | attribute: attribute, 23 | multiplier: 1, 24 | constant: 0)) 25 | }) 26 | return spinner 27 | }() 28 | 29 | override init(frame: CGRect) { 30 | super.init(frame: frame) 31 | self.backgroundColor = .clear 32 | } 33 | 34 | required init?(coder aDecoder: NSCoder) { 35 | super.init(coder: aDecoder) 36 | self.backgroundColor = .clear 37 | } 38 | 39 | func showLoading() { 40 | self.loadingSpinner.startAnimating() 41 | } 42 | 43 | func hideLoading() { 44 | self.loadingSpinner.stopAnimating() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Source/Core/QRCode/QRScannerOverlayView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRScannerOverlayView.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 9/2/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class QRScannerOverlayView: UIView { 12 | private lazy var outlineLayer: CAShapeLayer = { 13 | let outlineLayer = CAShapeLayer() 14 | outlineLayer.backgroundColor = UIColor.clear.cgColor 15 | outlineLayer.fillColor = UIColor.clear.cgColor 16 | outlineLayer.strokeColor = UIColor.white.cgColor 17 | outlineLayer.lineWidth = 2 18 | outlineLayer.lineDashPattern = [5.0, 4.0] 19 | outlineLayer.lineDashPhase = 0 20 | return outlineLayer 21 | }() 22 | 23 | private lazy var maskLayer: CAShapeLayer = { 24 | let maskLayer = CAShapeLayer() 25 | maskLayer.fillRule = CAShapeLayerFillRule.evenOdd 26 | maskLayer.fillColor = UIColor.black.cgColor 27 | maskLayer.opacity = 0.6 28 | return maskLayer 29 | }() 30 | 31 | override func draw(_ rect: CGRect) { 32 | var innerRect = rect.insetBy(dx: 50, dy: 50) 33 | let minSize = min(innerRect.width, innerRect.height) 34 | 35 | if innerRect.width != minSize { 36 | innerRect.origin.x += (innerRect.width - minSize) / 2 37 | innerRect.size.width = minSize 38 | } else if innerRect.height != minSize { 39 | innerRect.origin.y += (innerRect.height - minSize) / 2 40 | innerRect.size.height = minSize 41 | } 42 | let innerPath = UIBezierPath(roundedRect: innerRect, cornerRadius: 3) 43 | let outerPath = UIBezierPath(rect: rect) 44 | outerPath.usesEvenOddFillRule = true 45 | outerPath.append(innerPath) 46 | 47 | self.outlineLayer.path = innerPath.cgPath 48 | self.maskLayer.path = outerPath.cgPath 49 | 50 | self.layer.addSublayer(self.outlineLayer) 51 | self.layer.addSublayer(self.maskLayer) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Source/Core/QRCode/QRVerifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRVerifier.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 7/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// Takes care of fetching objects decoded by the QR code scanner. 10 | public protocol QRVerifier { 11 | func onData(data: String, callback: @escaping Request.Callback) 12 | } 13 | -------------------------------------------------------------------------------- /Source/Core/Websocket/SocketChannel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketChannel.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 12/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | protocol SocketSendable: class { 10 | func send(topic: String, event: SocketEventSend) -> SocketMessage 11 | } 12 | 13 | struct SocketChannel { 14 | let topic: String 15 | private let dispatcher: SocketDispatcher? 16 | private weak var socket: SocketSendable? 17 | 18 | init(topic: String, socket: SocketSendable, dispatcher: SocketDispatcher?) { 19 | self.topic = topic 20 | self.socket = socket 21 | self.dispatcher = dispatcher 22 | } 23 | 24 | func join() { 25 | self.socket?.send(topic: self.topic, event: .join).onSuccess({ _ in 26 | self.dispatcher?.dispatchJoin() 27 | }) 28 | } 29 | 30 | func leave(onSuccess: @escaping (() -> Void)) { 31 | self.socket?.send(topic: self.topic, event: .leave).onSuccess({ _ in 32 | self.dispatcher?.dispatchLeave() 33 | onSuccess() 34 | }) 35 | } 36 | 37 | func dispatchEvents(forMessage message: SocketMessage) { 38 | guard let payload = message.dataReceived else { return } 39 | self.dispatcher?.dispatchPayload(payload) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/Core/Websocket/SocketDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketDelegate.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 9/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | /// A protocol containing the websocket connection events 10 | public protocol SocketConnectionDelegate: class { 11 | func didConnect() 12 | func didDisconnect(_ error: OMGError?) 13 | } 14 | 15 | /// The root protocol of all events that are available when listening any topic 16 | public protocol EventDelegate: class { 17 | func didStartListening() 18 | func didStopListening() 19 | func onError(_ error: APIError) 20 | } 21 | 22 | /// The protocol containing events that are dispatched when listening to a user topic 23 | public protocol UserEventDelegate: EventDelegate { 24 | func on(_ object: WebsocketObject, error: APIError?, forEvent event: SocketEvent) 25 | } 26 | 27 | /// The protocol containing events that are dispatched when listening to a transaction request topic 28 | public protocol TransactionRequestEventDelegate: EventDelegate { 29 | func onTransactionConsumptionRequest(_ transactionConsumption: TransactionConsumption) 30 | func onSuccessfulTransactionConsumptionFinalized(_ transactionConsumption: TransactionConsumption) 31 | func onFailedTransactionConsumptionFinalized(_ transactionConsumption: TransactionConsumption, error: APIError) 32 | } 33 | 34 | /// The protocol containing events that are dispatched when listening to a transaction consumption topic 35 | public protocol TransactionConsumptionEventDelegate: EventDelegate { 36 | func onSuccessfulTransactionConsumptionFinalized(_ transactionConsumption: TransactionConsumption) 37 | func onFailedTransactionConsumptionFinalized(_ transactionConsumption: TransactionConsumption, error: APIError) 38 | } 39 | -------------------------------------------------------------------------------- /Source/Core/Websocket/SocketEvent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketEvent.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 20/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | enum SocketEventSend: String, Encodable { 10 | case heartbeat 11 | case join = "phx_join" 12 | case leave = "phx_leave" 13 | } 14 | 15 | /// This enum describes the diferent event that can be received from the websockets. 16 | /// 17 | /// - reply: A reply from a previously sent message 18 | /// - error: An error that occured 19 | /// - close: Closure of a topic 20 | /// - transactionConsumptionRequest: A new consumption request on a transaction request 21 | /// - transactionConsumptionFinalized: A consumption has been finalized 22 | /// - other: Any other unhandled event (as a string) 23 | public enum SocketEvent: Decodable { 24 | case reply 25 | case error 26 | case close 27 | case transactionConsumptionRequest 28 | case transactionConsumptionFinalized 29 | case other(event: String) 30 | 31 | public var eventName: String { 32 | return self.rawValue 33 | } 34 | 35 | public init(from decoder: Decoder) throws { 36 | let container = try decoder.singleValueContainer() 37 | let event = try container.decode(String.self) 38 | self = SocketEvent(rawValue: event)! 39 | } 40 | } 41 | 42 | extension SocketEvent: RawRepresentable { 43 | public typealias RawValue = String 44 | 45 | public init?(rawValue: String) { 46 | switch rawValue { 47 | case "phx_error": self = .error 48 | case "phx_close": self = .close 49 | case "phx_reply": self = .reply 50 | case "transaction_consumption_request": self = .transactionConsumptionRequest 51 | case "transaction_consumption_finalized": self = .transactionConsumptionFinalized 52 | default: self = .other(event: rawValue) 53 | } 54 | } 55 | 56 | public var rawValue: String { 57 | switch self { 58 | case .error: return "phx_error" 59 | case .close: return "phx_close" 60 | case .reply: return "phx_reply" 61 | case .transactionConsumptionRequest: return "transaction_consumption_request" 62 | case .transactionConsumptionFinalized: return "transaction_consumption_finalized" 63 | case let .other(event: event): return event 64 | } 65 | } 66 | } 67 | 68 | extension SocketEvent: Equatable { 69 | public static func == (lhs: SocketEvent, rhs: SocketEvent) -> Bool { 70 | return lhs.rawValue == rhs.rawValue 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Source/Core/Websocket/SocketMessage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketMessage.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 12/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | class SocketMessage { 10 | let dataSent: SocketPayloadSend? 11 | var dataReceived: SocketPayloadReceive? 12 | private var errorHandler: ((APIError) -> Void)? 13 | private var successHandler: ((GenericObjectEnum?) -> Void)? 14 | 15 | init(socketPayload: SocketPayloadSend) { 16 | self.dataSent = socketPayload 17 | } 18 | 19 | init(socketPayload: SocketPayloadReceive) { 20 | self.dataSent = nil 21 | self.dataReceived = socketPayload 22 | } 23 | 24 | @discardableResult 25 | func onSuccess(_ handler: @escaping ((GenericObjectEnum?) -> Void)) -> SocketMessage { 26 | self.successHandler = handler 27 | return self 28 | } 29 | 30 | @discardableResult 31 | func onError(_ handler: @escaping ((APIError) -> Void)) -> SocketMessage { 32 | self.errorHandler = handler 33 | return self 34 | } 35 | 36 | func topic() -> String { 37 | return self.dataSent?.topic ?? self.dataReceived?.topic ?? "undefined" 38 | } 39 | 40 | func handleResponse(withPayload payload: SocketPayloadReceive) { 41 | self.dataReceived = payload 42 | self.fireCallbacksAndCleanup() 43 | } 44 | 45 | private func fireCallbacksAndCleanup() { 46 | defer { 47 | self.errorHandler = nil 48 | self.successHandler = nil 49 | } 50 | if let error = self.dataReceived?.error { 51 | self.errorHandler?(error) 52 | } else { 53 | self.successHandler?(self.dataReceived?.data?.object) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Source/Core/Websocket/SocketObject.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketObject.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 9/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | struct GenericObject { 10 | let object: GenericObjectEnum 11 | } 12 | 13 | extension GenericObject: Decodable { 14 | private enum CodingKeys: String, CodingKey { 15 | case objectType = "object" 16 | } 17 | 18 | public init(from decoder: Decoder) throws { 19 | let container = try decoder.container(keyedBy: CodingKeys.self) 20 | let objectType: String? = try container.decodeIfPresent(String.self, forKey: .objectType) 21 | guard let decodedObject = try GenericObjectEnum(objectType: objectType, decoder: decoder) else { 22 | throw OMGError.socketError(message: "Unknown object type") 23 | } 24 | self.object = decodedObject 25 | } 26 | } 27 | 28 | public enum WebsocketObject { 29 | case transactionConsumption(object: TransactionConsumption) 30 | } 31 | 32 | enum GenericObjectEnum { 33 | case transactionConsumption(object: TransactionConsumption) 34 | case error(error: OMGError) 35 | case other(object: [String: Any]) 36 | } 37 | 38 | extension GenericObjectEnum { 39 | init?(objectType: String?, decoder: Decoder) throws { 40 | guard let objectType = objectType else { 41 | self = .other(object: [:]) 42 | return 43 | } 44 | switch objectType { 45 | case "transaction_consumption": 46 | self = .transactionConsumption(object: try TransactionConsumption(from: decoder)) 47 | default: self = .error(error: OMGError.socketError(message: "Invalid payload")) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/Core/Websocket/SocketPayload.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketPayload.swift 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 12/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | struct SocketPayloadSend { 10 | let topic: String 11 | let event: SocketEventSend 12 | let ref: String 13 | let data: [String: Any] 14 | 15 | init(topic: String, event: SocketEventSend, ref: String, data: [String: Any] = [:]) { 16 | self.topic = topic 17 | self.event = event 18 | self.ref = ref 19 | self.data = data 20 | } 21 | } 22 | 23 | extension SocketPayloadSend: APIParameters { 24 | private enum CodingKeys: String, CodingKey { 25 | case topic 26 | case event 27 | case data 28 | case ref 29 | } 30 | 31 | func encode(to encoder: Encoder) throws { 32 | var container = encoder.container(keyedBy: CodingKeys.self) 33 | try container.encode(topic, forKey: .topic) 34 | try container.encode(event, forKey: .event) 35 | try container.encode(data, forKey: .data) 36 | try container.encode(ref, forKey: .ref) 37 | } 38 | } 39 | 40 | struct SocketPayloadReceive: Decodable { 41 | let topic: String 42 | let event: SocketEvent 43 | let ref: String? 44 | let data: GenericObject? 45 | let version: String 46 | let success: Bool 47 | let error: APIError? 48 | } 49 | -------------------------------------------------------------------------------- /Source/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.1.2 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Source/OmiseGO.h: -------------------------------------------------------------------------------- 1 | // 2 | // OmiseGO.h 3 | // OmiseGO 4 | // 5 | // Created by Mederic Petit on 9/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for OmiseGO. 12 | FOUNDATION_EXPORT double OmiseGOVersionNumber; 13 | 14 | //! Project version string for OmiseGO. 15 | FOUNDATION_EXPORT const unsigned char OmiseGOVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | -------------------------------------------------------------------------------- /Tests/Admin/APITests/AdminCredentialTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AdminCredentialTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 14/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class AdminCredentialTests: XCTestCase { 13 | func testIsAuthenticatedIsFalseWithoutAUserId() { 14 | var credentials = AdminCredential() 15 | credentials.authenticationToken = "123" 16 | XCTAssertFalse(credentials.isAuthenticated()) 17 | } 18 | 19 | func testIsAuthenticatedIsFalseWithoutAToken() { 20 | var credentials = AdminCredential() 21 | credentials.userId = "123" 22 | XCTAssertFalse(credentials.isAuthenticated()) 23 | } 24 | 25 | func testIsAuthenticatedIsTrueWithAUserIdAndAToken() { 26 | let credentials = AdminCredential(userId: "123", authenticationToken: "123") 27 | XCTAssertTrue(credentials.isAuthenticated()) 28 | } 29 | 30 | func testUpdateCredentialSuccessfully() { 31 | var credentials = AdminCredential() 32 | XCTAssertNil(credentials.userId) 33 | XCTAssertNil(credentials.authenticationToken) 34 | let authenticationToken = StubGenerator.authenticationToken(token: "token", user: StubGenerator.user(id: "user_id")) 35 | credentials.update(withAuthenticationToken: authenticationToken) 36 | XCTAssertEqual(credentials.authenticationToken, "token") 37 | XCTAssertEqual(credentials.userId, "user_id") 38 | } 39 | 40 | func testAuthenticationReturnsNilAfterInvalidating() { 41 | var credentials = AdminCredential(userId: "123", authenticationToken: "123") 42 | credentials.invalidate() 43 | XCTAssertNil(try credentials.authentication()) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/AccountAdminFixtureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AccountAdminFixtureTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 18/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class AccountAdminFixtureTests: FixtureAdminTestCase { 13 | func testGetListOfAccounts() { 14 | let expectation = self.expectation(description: "List accounts") 15 | let params: PaginatedListParams = PaginatedListParams(page: 1, perPage: 10, sortBy: .name, sortDirection: .ascending) 16 | let request = Account.list(using: self.testClient, params: params) { result in 17 | defer { expectation.fulfill() } 18 | switch result { 19 | case let .success(data: paginatedAccounts): 20 | let accounts = paginatedAccounts.data 21 | XCTAssertEqual(paginatedAccounts.pagination.currentPage, 1) 22 | XCTAssertEqual(paginatedAccounts.pagination.perPage, 10) 23 | XCTAssertTrue(paginatedAccounts.pagination.isFirstPage) 24 | XCTAssertTrue(paginatedAccounts.pagination.isLastPage) 25 | XCTAssertEqual(accounts.count, 2) 26 | XCTAssertEqual(accounts.first!.id, "acc_01cnfz5sh5zmhx4xwd6m1rethy") 27 | XCTAssertEqual(accounts[1].id, "acc_01cnnna53f35n80pnmbf730s29") 28 | case let .fail(error: error): 29 | XCTFail("\(error)") 30 | } 31 | } 32 | XCTAssertNotNil(request) 33 | waitForExpectations(timeout: 15.0, handler: nil) 34 | } 35 | 36 | func testGetAccount() { 37 | let expectation = self.expectation(description: "Get an account from its id") 38 | let params = AccountGetParams(id: "acc_01cnfz5sh5zmhx4xwd6m1rethy") 39 | let request = Account.get(using: self.testClient, params: params) { result in 40 | defer { expectation.fulfill() } 41 | switch result { 42 | case let .success(data: account): 43 | XCTAssertEqual(account.id, "acc_01cnfz5sh5zmhx4xwd6m1rethy") 44 | case let .fail(error: error): 45 | XCTFail("\(error)") 46 | } 47 | } 48 | XCTAssertNotNil(request) 49 | waitForExpectations(timeout: 15.0, handler: nil) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/FixtureAdminAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FixtureAdminAPI.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 14/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | 11 | class FixtureAdminAPI: HTTPAdminAPI { 12 | let fixturesDirectoryURL: URL 13 | 14 | init(fixturesDirectoryURL: URL, config: AdminConfiguration) { 15 | self.fixturesDirectoryURL = fixturesDirectoryURL 16 | super.init(config: config) 17 | } 18 | 19 | @discardableResult 20 | override func request(toEndpoint endpoint: APIEndpoint, 21 | callback: Request.Callback?) -> Request? { 22 | do { 23 | let request: FixtureRequest = FixtureRequest(fixturesDirectoryURL: self.fixturesDirectoryURL, 24 | client: self, 25 | endpoint: endpoint, 26 | callback: callback) 27 | return try request.start() 28 | } catch let error as NSError { 29 | operationQueue.addOperation { callback?(.fail(error: .other(error: error))) } 30 | } catch let error as OMGError { 31 | operationQueue.addOperation { callback?(.fail(error: error)) } 32 | } 33 | 34 | return nil 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/FixtureAdminTestCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FixtureAdminTestCase.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 14/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class FixtureAdminTestCase: XCTestCase { 13 | var testClient: FixtureAdminAPI { 14 | let bundle = Bundle(for: FixtureAdminTestCase.self) 15 | let url = bundle.url(forResource: "admin_fixtures", withExtension: nil)! 16 | let credentials = AdminCredential(userId: "user_id", authenticationToken: "token") 17 | let config = AdminConfiguration(baseURL: "http://localhost:4000", credentials: credentials) 18 | return FixtureAdminAPI(fixturesDirectoryURL: url, config: config) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/LoginAdminFixtureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginAdminFixtureTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 14/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class LoginAdminFixtureTests: XCTestCase { 13 | var testClient: FixtureAdminAPI { 14 | let bundle = Bundle(for: LoginAdminFixtureTests.self) 15 | let url = bundle.url(forResource: "admin_fixtures", withExtension: nil)! 16 | let config = AdminConfiguration(baseURL: "http://localhst:4000") 17 | return FixtureAdminAPI(fixturesDirectoryURL: url, config: config) 18 | } 19 | 20 | func testLoginSuccessfullyAndUpdateToken() { 21 | let expectation = self.expectation(description: "Log an admin in successfully and updates the client authentication") 22 | XCTAssertNil(try! self.testClient.config.credentials.authentication()) 23 | let client = self.testClient 24 | let params = LoginParams(email: "email", password: "password") 25 | let request = client.login(withParams: params, callback: { result in 26 | defer { expectation.fulfill() } 27 | switch result { 28 | case let .fail(error: error): 29 | XCTFail(error.message) 30 | case let .success(data: authenticationToken): 31 | XCTAssertEqual(authenticationToken.token, "azJRj09l7jvR8KhTqUs3") 32 | XCTAssertEqual(authenticationToken.user.id, "usr_01cc02x0v98qcctvycfx4vsk8x") 33 | XCTAssertNotNil(try! client.config.credentials.authentication()) 34 | } 35 | }) 36 | XCTAssertNotNil(request) 37 | waitForExpectations(timeout: 15.0, handler: nil) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/LogoutAdminFixtureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LogoutAdminFixtureTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 17/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class LogoutAdminFixtureTests: FixtureAdminTestCase { 13 | func testAuthenticationIsInvalidedAfterLogout() { 14 | let expectation = self.expectation(description: "Authentication should be nil after logout") 15 | XCTAssertNotNil(try! self.testClient.config.credentials.authentication()) 16 | let client = self.testClient 17 | let request = client.logout { _ in 18 | defer { expectation.fulfill() } 19 | XCTAssertNil(try! client.config.credentials.authentication()) 20 | } 21 | XCTAssertNotNil(request) 22 | waitForExpectations(timeout: 15.0, handler: nil) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/RequestAdminFixtureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestAdminFixtureTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 17/9/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class RequestAdminFixtureTests: FixtureAdminTestCase { 13 | func testBuildRequest() { 14 | do { 15 | let urlRequest = try RequestBuilder(configuration: testClient.config) 16 | .buildHTTPURLRequest(withEndpoint: TestAPIEndpoint()) 17 | 18 | guard let httpHeaders = urlRequest.allHTTPHeaderFields else { 19 | XCTFail("Missing HTTP headers") 20 | return 21 | } 22 | 23 | XCTAssertEqual(httpHeaders["Authorization"], "OMGAdmin dXNlcl9pZDp0b2tlbg==") 24 | XCTAssertEqual(httpHeaders["Accept"], 25 | "application/vnd.omisego.v\(self.testClient.config.apiVersion)+json") 26 | XCTAssertEqual(httpHeaders["Content-Type"], 27 | "application/vnd.omisego.v\(self.testClient.config.apiVersion)+json; charset=utf-8") 28 | XCTAssertNil(urlRequest.httpBody) 29 | XCTAssertEqual(urlRequest.httpMethod, "POST") 30 | XCTAssertEqual(urlRequest.timeoutInterval, 6) 31 | } catch let error { 32 | XCTFail(error.localizedDescription) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/admin_fixtures/api/account.all.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "pagination": { 6 | "per_page": 10, 7 | "is_last_page": true, 8 | "is_first_page": true, 9 | "current_page": 1 10 | }, 11 | "object": "list", 12 | "data": [ 13 | { 14 | "updated_at": "2018-08-24T09:47:29.116420Z", 15 | "socket_topic": "account:acc_01cnfz5sh5zmhx4xwd6m1rethy", 16 | "parent_id": null, 17 | "object": "account", 18 | "name": "Account 1", 19 | "metadata": {}, 20 | "master": true, 21 | "id": "acc_01cnfz5sh5zmhx4xwd6m1rethy", 22 | "encrypted_metadata": {}, 23 | "description": "Master Account", 24 | "created_at": "2018-08-22T04:44:38.823385Z", 25 | "category_ids": [], 26 | "categories": { 27 | "object": "list", 28 | "data": [] 29 | }, 30 | "avatar": { 31 | "thumb": null, 32 | "small": null, 33 | "original": null, 34 | "large": null 35 | } 36 | }, 37 | { 38 | "updated_at": "2018-08-24T09:47:42.575342Z", 39 | "socket_topic": "account:acc_01cnnna53f35n80pnmbf730s29", 40 | "parent_id": "acc_01cnfz5sh5zmhx4xwd6m1rethy", 41 | "object": "account", 42 | "name": "Account 2", 43 | "metadata": {}, 44 | "master": false, 45 | "id": "acc_01cnnna53f35n80pnmbf730s29", 46 | "encrypted_metadata": {}, 47 | "description": null, 48 | "created_at": "2018-08-24T09:47:42.575319Z", 49 | "category_ids": [], 50 | "categories": { 51 | "object": "list", 52 | "data": [] 53 | }, 54 | "avatar": { 55 | "thumb": null, 56 | "small": null, 57 | "original": null, 58 | "large": null 59 | } 60 | } 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/admin_fixtures/api/account.get.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "account", 6 | "updated_at": "2018-08-24T09:47:29.116420Z", 7 | "socket_topic": "account:acc_01cnfz5sh5zmhx4xwd6m1rethy", 8 | "parent_id": null, 9 | "object": "account", 10 | "name": "Account 1", 11 | "metadata": {}, 12 | "master": true, 13 | "id": "acc_01cnfz5sh5zmhx4xwd6m1rethy", 14 | "encrypted_metadata": {}, 15 | "description": "Master Account", 16 | "created_at": "2018-08-22T04:44:38.823385Z", 17 | "category_ids": [], 18 | "categories": { 19 | "object": "list", 20 | "data": [] 21 | }, 22 | "avatar": { 23 | "thumb": null, 24 | "small": null, 25 | "original": null, 26 | "large": null 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/admin_fixtures/api/admin.login.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "authentication_token", 6 | "authentication_token": "azJRj09l7jvR8KhTqUs3", 7 | "user_id": "usr_01cc02x0v98qcctvycfx4vsk8x", 8 | "user": { 9 | "id": "usr_01cc02x0v98qcctvycfx4vsk8x", 10 | "provider_user_id": null, 11 | "username": null, 12 | "email": "user@example.com", 13 | "socket_topic": "user:usr_01cc02x0v98qcctvycfx4vsk8x", 14 | "metadata": {}, 15 | "encrypted_metadata": {}, 16 | "created_at": "2018-01-01T00:00:00Z", 17 | "updated_at": "2018-01-01T00:00:00Z" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/admin_fixtures/api/me.logout.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Admin/FixtureTests/admin_fixtures/api/wallet.get.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "user_id": null, 6 | "user": null, 7 | "updated_at": "2018-08-22T04:44:38.837395Z", 8 | "socket_topic": "wallet:ixsz977823599563", 9 | "object": "wallet", 10 | "name": "primary", 11 | "metadata": {}, 12 | "identifier": "primary", 13 | "encrypted_metadata": {}, 14 | "enabled": true, 15 | "created_at": "2018-08-22T04:44:38.837384Z", 16 | "balances": [ 17 | { 18 | "token": { 19 | "updated_at": "2018-08-22T07:53:13.800904Z", 20 | "symbol": "TK1", 21 | "subunit_to_unit": 1, 22 | "object": "token", 23 | "name": "Token 1", 24 | "metadata": {}, 25 | "id": "tok_TK1_01cng9z3a8yn58ts806vbpefxw", 26 | "encrypted_metadata": {}, 27 | "enabled": true, 28 | "created_at": "2018-08-22T07:53:13.800896Z" 29 | }, 30 | "object": "balance", 31 | "amount": 37585 32 | }, 33 | { 34 | "token": { 35 | "updated_at": "2018-08-23T07:21:03.542632Z", 36 | "symbol": "TK2", 37 | "subunit_to_unit": 1, 38 | "object": "token", 39 | "name": "Token 2", 40 | "metadata": {}, 41 | "id": "tok_TK2_01cnjtgx9p89p9g1pa2qjzk9mf", 42 | "encrypted_metadata": {}, 43 | "enabled": true, 44 | "created_at": "2018-08-23T07:21:03.542625Z" 45 | }, 46 | "object": "balance", 47 | "amount": 9999999469 48 | } 49 | ], 50 | "address": "ixsz977823599563", 51 | "account_id": "acc_01cnfz5sh5zmhx4xwd6m1rethy", 52 | "account": { 53 | "updated_at": "2018-08-24T09:47:29.116420Z", 54 | "socket_topic": "account:acc_01cnfz5sh5zmhx4xwd6m1rethy", 55 | "parent_id": null, 56 | "object": "account", 57 | "name": "Account 1", 58 | "metadata": {}, 59 | "master": true, 60 | "id": "acc_01cnfz5sh5zmhx4xwd6m1rethy", 61 | "encrypted_metadata": {}, 62 | "description": "Master Account", 63 | "created_at": "2018-08-22T04:44:38.823385Z", 64 | "category_ids": [], 65 | "categories": { 66 | "object": "list", 67 | "data": [] 68 | }, 69 | "avatar": { 70 | "thumb": null, 71 | "small": null, 72 | "original": null, 73 | "large": null 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Tests/Client/APITests/ClientCredentialTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClientCredentialTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 9/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class ClientCredentialTests: XCTestCase { 13 | func testIsAuthenticatedIsFalseWhenNoAuthenticationToken() { 14 | let credentials = ClientCredential(apiKey: "api_key") 15 | XCTAssertFalse(credentials.isAuthenticated()) 16 | } 17 | 18 | func testIsAuthenticatedIsTrueWithAnAuthenticationToken() { 19 | let credentials = ClientCredential(apiKey: "api_key", authenticationToken: "123") 20 | XCTAssertTrue(credentials.isAuthenticated()) 21 | } 22 | 23 | func testUpdateCredentialSuccessfully() { 24 | var credentials = ClientCredential(apiKey: "api_key") 25 | XCTAssertNil(credentials.authenticationToken) 26 | let authenticationToken = StubGenerator.authenticationToken(token: "123") 27 | credentials.update(withAuthenticationToken: authenticationToken) 28 | XCTAssertEqual(credentials.authenticationToken, "123") 29 | } 30 | 31 | func testAuthenticationReturnsNilIfAuthenticationTokenIsNotSpecified() { 32 | var credentials = ClientCredential(apiKey: "api_key", authenticationToken: "auth_token") 33 | credentials.invalidate() 34 | XCTAssertNil(try credentials.authentication()) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/FixtureClientAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FixtureClientAPI.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 17/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | 11 | class FixtureClientAPI: HTTPClientAPI { 12 | let fixturesDirectoryURL: URL 13 | 14 | init(fixturesDirectoryURL: URL, config: ClientConfiguration) { 15 | self.fixturesDirectoryURL = fixturesDirectoryURL 16 | super.init(config: config) 17 | } 18 | 19 | @discardableResult 20 | override func request(toEndpoint endpoint: APIEndpoint, 21 | callback: Request.Callback?) -> Request? { 22 | do { 23 | let request: FixtureRequest = FixtureRequest(fixturesDirectoryURL: self.fixturesDirectoryURL, 24 | client: self, 25 | endpoint: endpoint, 26 | callback: callback) 27 | return try request.start() 28 | } catch let error as NSError { 29 | operationQueue.addOperation { callback?(.fail(error: .other(error: error))) } 30 | } catch let error as OMGError { 31 | operationQueue.addOperation { callback?(.fail(error: error)) } 32 | } 33 | 34 | return nil 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/FixtureClientTestCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FixtureClientTestCase.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 10/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class FixtureClientTestCase: XCTestCase { 13 | var testClient: FixtureClientAPI { 14 | let bundle = Bundle(for: FixtureClientTestCase.self) 15 | let url = bundle.url(forResource: "client_fixtures", withExtension: nil)! 16 | let credentials = ClientCredential(apiKey: "some_api_key", authenticationToken: "some_token") 17 | let config = ClientConfiguration(baseURL: "http://localhost:4000", credentials: credentials) 18 | return FixtureClientAPI(fixturesDirectoryURL: url, config: config) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/LoginFixtureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginFixtureTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 15/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class LoginFixtureTests: XCTestCase { 13 | var testClient: FixtureClientAPI { 14 | let bundle = Bundle(for: FixtureClientTestCase.self) 15 | let url = bundle.url(forResource: "client_fixtures", withExtension: nil)! 16 | let credentials = ClientCredential(apiKey: "some_api_key") 17 | let config = ClientConfiguration(baseURL: "http://localhst:4000", credentials: credentials) 18 | return FixtureClientAPI(fixturesDirectoryURL: url, config: config) 19 | } 20 | 21 | func testLoginSuccessfullyAndUpdateToken() { 22 | let expectation = self.expectation(description: "Log a user in successfully and updates the client authentication") 23 | XCTAssertNil(try! self.testClient.config.credentials.authentication()) 24 | let client = self.testClient 25 | let params = LoginParams(email: "email", password: "password") 26 | let request = client.login(withParams: params, callback: { result in 27 | defer { expectation.fulfill() } 28 | switch result { 29 | case let .fail(error: error): 30 | XCTFail(error.message) 31 | case let .success(data: authenticationToken): 32 | XCTAssertEqual(authenticationToken.token, "azJRj09l7jvR8KhTqUs3") 33 | XCTAssertEqual(authenticationToken.user.id, "usr_01cc02x0v98qcctvycfx4vsk8x") 34 | XCTAssertNotNil(try! client.config.credentials.authentication()) 35 | } 36 | }) 37 | XCTAssertNotNil(request) 38 | waitForExpectations(timeout: 15.0, handler: nil) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/LogoutFixtureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LogoutFixtureTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 27/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class LogoutFixtureTests: FixtureClientTestCase { 13 | func testAuthenticationIsInvalidedAfterLogout() { 14 | let expectation = self.expectation(description: "Authentication should be nil after logout") 15 | XCTAssertNotNil(try! self.testClient.config.credentials.authentication()) 16 | let client = self.testClient 17 | let request = client.logout { _ in 18 | defer { expectation.fulfill() } 19 | XCTAssertNil(try! client.config.credentials.authentication()) 20 | } 21 | XCTAssertNotNil(request) 22 | waitForExpectations(timeout: 15.0, handler: nil) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/RequestFixtureTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestFixtureTest.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 13/11/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class RequestFixtureTest: FixtureClientTestCase { 13 | func testBuildRequest() { 14 | do { 15 | let urlRequest = try RequestBuilder(configuration: testClient.config) 16 | .buildHTTPURLRequest(withEndpoint: TestAPIEndpoint()) 17 | 18 | guard let httpHeaders = urlRequest.allHTTPHeaderFields else { 19 | XCTFail("Missing HTTP headers") 20 | return 21 | } 22 | 23 | XCTAssertEqual(httpHeaders["Authorization"], "OMGClient c29tZV9hcGlfa2V5OnNvbWVfdG9rZW4=") 24 | XCTAssertEqual(httpHeaders["Accept"], 25 | "application/vnd.omisego.v\(self.testClient.config.apiVersion)+json") 26 | XCTAssertEqual(httpHeaders["Content-Type"], 27 | "application/vnd.omisego.v\(self.testClient.config.apiVersion)+json; charset=utf-8") 28 | XCTAssertNil(urlRequest.httpBody) 29 | XCTAssertEqual(urlRequest.httpMethod, "POST") 30 | XCTAssertEqual(urlRequest.timeoutInterval, 6) 31 | } catch let error { 32 | XCTFail(error.localizedDescription) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/SettingFixtureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingFixtureTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 12/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class SettingFixtureTests: FixtureClientTestCase { 13 | func testGetSettings() { 14 | let expectation = self.expectation(description: "Get settings for current user") 15 | let request = Setting.get(using: self.testClient) { result in 16 | defer { expectation.fulfill() } 17 | switch result { 18 | case let .success(setting): 19 | XCTAssertTrue(setting.tokens.count == 2) 20 | XCTAssertEqual(setting.tokens[0].id, "BTC:123") 21 | XCTAssertEqual(setting.tokens[0].symbol, "BTC") 22 | XCTAssertEqual(setting.tokens[0].name, "Bitcoin") 23 | XCTAssertEqual(setting.tokens[0].subUnitToUnit, 100_000) 24 | XCTAssertTrue(setting.tokens[0].metadata.isEmpty) 25 | XCTAssertTrue(setting.tokens[0].encryptedMetadata.isEmpty) 26 | XCTAssertEqual(setting.tokens[0].createdAt, "2018-01-01T00:00:00Z".toDate()) 27 | XCTAssertEqual(setting.tokens[0].updatedAt, "2018-01-01T00:00:00Z".toDate()) 28 | XCTAssertEqual(setting.tokens[1].id, "OMG:123") 29 | XCTAssertEqual(setting.tokens[1].symbol, "OMG") 30 | XCTAssertEqual(setting.tokens[1].name, "OmiseGO") 31 | XCTAssertEqual(setting.tokens[1].subUnitToUnit, 100_000_000) 32 | XCTAssertTrue(setting.tokens[1].metadata.isEmpty) 33 | XCTAssertTrue(setting.tokens[1].encryptedMetadata.isEmpty) 34 | XCTAssertEqual(setting.tokens[1].createdAt, "2018-01-01T00:00:00Z".toDate()) 35 | XCTAssertEqual(setting.tokens[1].updatedAt, "2018-01-01T00:00:00Z".toDate()) 36 | case let .fail(error): 37 | XCTFail("\(error)") 38 | } 39 | } 40 | XCTAssertNotNil(request) 41 | waitForExpectations(timeout: 15.0, handler: nil) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/SignupFixtureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SignupFixtureTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 22/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class SignupFixtureTests: XCTestCase { 13 | var testClient: FixtureClientAPI { 14 | let bundle = Bundle(for: FixtureClientTestCase.self) 15 | let url = bundle.url(forResource: "client_fixtures", withExtension: nil)! 16 | let credentials = ClientCredential(apiKey: "some_api_key") 17 | let config = ClientConfiguration(baseURL: "http://localhst:4000", credentials: credentials) 18 | return FixtureClientAPI(fixturesDirectoryURL: url, config: config) 19 | } 20 | 21 | func testSignupSuccessfully() { 22 | let expectation = self.expectation(description: "Signup a user successfully") 23 | XCTAssertNil(try! self.testClient.config.credentials.authentication()) 24 | let client = self.testClient 25 | let params = SignupParams(email: "email@example.com", 26 | password: "password", 27 | passwordConfirmation: "password") 28 | let request = client.signup(withParams: params) { result in 29 | defer { expectation.fulfill() } 30 | switch result { 31 | case let .fail(error: error): 32 | XCTFail(error.message) 33 | case .success(data: _): break 34 | } 35 | } 36 | XCTAssertNotNil(request) 37 | waitForExpectations(timeout: 15.0, handler: nil) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/me.create_transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "transaction", 6 | "id": "ce3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 7 | "from": { 8 | "object": "transaction_source", 9 | "address": "1e3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 10 | "amount": 1000, 11 | "token": { 12 | "object": "token", 13 | "id": "BTC:xe3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 14 | "symbol": "BTC", 15 | "name": "Bitcoin", 16 | "subunit_to_unit": 100, 17 | "metadata": {}, 18 | "encrypted_metadata": {}, 19 | "created_at": "2018-01-01T00:00:00Z", 20 | "updated_at": "2018-01-01T00:00:00Z" 21 | } 22 | }, 23 | "to": { 24 | "object": "transaction_source", 25 | "address": "2e3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 26 | "amount": 1000, 27 | "token": { 28 | "object": "token", 29 | "id": "BTC:xe3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 30 | "symbol": "BTC", 31 | "name": "Bitcoin", 32 | "subunit_to_unit": 100, 33 | "metadata": {}, 34 | "encrypted_metadata": {}, 35 | "created_at": "2018-01-01T00:00:00Z", 36 | "updated_at": "2018-01-01T00:00:00Z" 37 | } 38 | }, 39 | "exchange": { 40 | "object": "exchange", 41 | "rate": 1, 42 | "calculated_at": null, 43 | "exchange_pair_id": null, 44 | "exchange_pair": null, 45 | "exchange_account_id": null, 46 | "exchange_account": null, 47 | "exchange_wallet_address": null, 48 | "exchange_wallet": null 49 | }, 50 | "status": "confirmed", 51 | "metadata": {}, 52 | "encrypted_metadata": {}, 53 | "created_at": "2018-01-01T00:00:00Z" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/me.create_transaction_request.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "transaction_request", 6 | "type": "receive", 7 | "id": "8eb0160e-1c96-481a-88e1-899399cc84dc", 8 | "consumption_interval_duration": null, 9 | "max_consumptions_per_interval": null, 10 | "max_consumptions_per_interval_per_user": null, 11 | "token": { 12 | "object": "token", 13 | "id": "BTC:861020af-17b6-49ee-a0cb-661a4d2d1f95", 14 | "symbol": "BTC", 15 | "name": "Bitcoin", 16 | "subunit_to_unit": 100000, 17 | "metadata": {}, 18 | "encrypted_metadata": {}, 19 | "created_at": "2018-01-01T00:00:00Z", 20 | "updated_at": "2018-01-01T00:00:00Z" 21 | }, 22 | "amount": 1337, 23 | "address": "3b7f1c68-e3bd-4f8f-9916-4af19be95d00", 24 | "user": { 25 | "object": "user", 26 | "id": "6f56efa1-caf9-4348-8e0f-f5af283f17ee", 27 | "provider_user_id": "a_provider_user_id", 28 | "username": "john.doe@example.com", 29 | "socket_topic": "user:6f56efa1-caf9-4348-8e0f-f5af283f17ee", 30 | "metadata": {}, 31 | "encrypted_metadata": {}, 32 | "created_at": "2018-01-01T00:00:00Z", 33 | "updated_at": "2018-01-01T00:00:00Z" 34 | }, 35 | "accountId": null, 36 | "correlation_id": "31009545-db10-4287-82f4-afb46d9741d8", 37 | "status": "valid", 38 | "socket_topic": "transaction_request:8eb0160e-1c96-481a-88e1-899399cc84dc", 39 | "require_confirmation": true, 40 | "max_consumptions": 1, 41 | "consumption_lifetime": 1000, 42 | "created_at": "2018-01-01T00:00:00Z", 43 | "expiration_date": "2019-01-01T00:00:00Z", 44 | "expiration_reason": "Expired", 45 | "expired_at": "2019-01-01T00:00:00Z", 46 | "allow_amount_override": true, 47 | "max_consumptions_per_user": null, 48 | "formatted_id": "|8eb0160e-1c96-481a-88e1-899399cc84dc", 49 | "metadata": {}, 50 | "encrypted_metadata": {}, 51 | "exchange_account_id": null, 52 | "exchange_account": null, 53 | "exchange_wallet_address": null, 54 | "exchange_wallet": null 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/me.get.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "user", 6 | "id": "cec34607-0761-4a59-8357-18963e42a1aa", 7 | "provider_user_id": "wijf-fbancomw-dqwjudb", 8 | "username": "john.doe@example.com", 9 | "socket_topic": "user:cec34607-0761-4a59-8357-18963e42a1aa", 10 | "metadata": { 11 | "first_name": "John", 12 | "last_name": "Doe", 13 | "object": { 14 | "my_key": "my_value", 15 | "my_nested_object": { 16 | "my_nested_key": "my_nested_value" 17 | } 18 | }, 19 | "array": [ 20 | "value_1", "value_2" 21 | ] 22 | }, 23 | "encrypted_metadata": {}, 24 | "created_at": "2018-01-01T00:00:00Z", 25 | "updated_at": "2018-01-01T00:00:00Z" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/me.get_settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "setting", 6 | "tokens": [ 7 | { 8 | "object": "token", 9 | "id": "BTC:123", 10 | "symbol": "BTC", 11 | "name": "Bitcoin", 12 | "subunit_to_unit": 100000, 13 | "metadata": {}, 14 | "encrypted_metadata": {}, 15 | "created_at": "2018-01-01T00:00:00Z", 16 | "updated_at": "2018-01-01T00:00:00Z" 17 | }, 18 | { 19 | "object": "token", 20 | "id": "OMG:123", 21 | "symbol": "OMG", 22 | "name": "OmiseGO", 23 | "subunit_to_unit": 100000000, 24 | "metadata": {}, 25 | "encrypted_metadata": {}, 26 | "created_at": "2018-01-01T00:00:00Z", 27 | "updated_at": "2018-01-01T00:00:00Z" 28 | } 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/me.get_transaction_request.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "transaction_request", 6 | "type": "receive", 7 | "id": "8eb0160e-1c96-481a-88e1-899399cc84dc", 8 | "consumption_interval_duration": 10000, 9 | "max_consumptions_per_interval": 10, 10 | "max_consumptions_per_interval_per_user": 1, 11 | "token": { 12 | "object": "token", 13 | "id": "BTC:861020af-17b6-49ee-a0cb-661a4d2d1f95", 14 | "symbol": "BTC", 15 | "name": "Bitcoin", 16 | "subunit_to_unit": 100000, 17 | "metadata": {}, 18 | "encrypted_metadata": {}, 19 | "created_at": "2018-01-01T00:00:00Z", 20 | "updated_at": "2018-01-01T00:00:00Z" 21 | }, 22 | "amount": 1337, 23 | "address": "3b7f1c68-e3bd-4f8f-9916-4af19be95d00", 24 | "user": { 25 | "object": "user", 26 | "id": "6f56efa1-caf9-4348-8e0f-f5af283f17ee", 27 | "provider_user_id": "a_provider_user_id", 28 | "username": "john.doe@example.com", 29 | "socket_topic": "user:6f56efa1-caf9-4348-8e0f-f5af283f17ee", 30 | "metadata": {}, 31 | "encrypted_metadata": {}, 32 | "created_at": "2018-01-01T00:00:00Z", 33 | "updated_at": "2018-01-01T00:00:00Z" 34 | }, 35 | "accountId": null, 36 | "correlation_id": "31009545-db10-4287-82f4-afb46d9741d8", 37 | "status": "valid", 38 | "socket_topic": "transaction_request:8eb0160e-1c96-481a-88e1-899399cc84dc", 39 | "require_confirmation": true, 40 | "max_consumptions": 1, 41 | "consumption_lifetime": 1000, 42 | "created_at": "2018-01-01T00:00:00Z", 43 | "expiration_date": "2019-01-01T00:00:00Z", 44 | "expiration_reason": "Expired", 45 | "expired_at": "2019-01-01T00:00:00Z", 46 | "allow_amount_override": true, 47 | "max_consumptions_per_user": null, 48 | "formatted_id": "|907056a4-fc2d-47cb-af19-5e73aade7ece", 49 | "metadata": {}, 50 | "encrypted_metadata": {}, 51 | "exchange_account_id": null, 52 | "exchange_account": null, 53 | "exchange_wallet_address": null, 54 | "exchange_wallet": null 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/me.get_transactions.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "list", 6 | "data": [ 7 | { 8 | "object": "transaction", 9 | "id": "ce3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 10 | "from": { 11 | "object": "transaction_source", 12 | "address": "1e3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 13 | "amount": 1000, 14 | "token": { 15 | "object": "token", 16 | "id": "BTC:xe3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 17 | "symbol": "BTC", 18 | "name": "Bitcoin", 19 | "subunit_to_unit": 100, 20 | "metadata": {}, 21 | "encrypted_metadata": {}, 22 | "created_at": "2018-01-01T00:00:00Z", 23 | "updated_at": "2018-01-01T00:00:00Z" 24 | } 25 | }, 26 | "to": { 27 | "object": "transaction_source", 28 | "address": "2e3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 29 | "amount": 1000, 30 | "token": { 31 | "object": "token", 32 | "id": "BTC:xe3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 33 | "symbol": "BTC", 34 | "name": "Bitcoin", 35 | "subunit_to_unit": 100, 36 | "metadata": {}, 37 | "encrypted_metadata": {}, 38 | "created_at": "2018-01-01T00:00:00Z", 39 | "updated_at": "2018-01-01T00:00:00Z" 40 | } 41 | }, 42 | "exchange": { 43 | "object": "exchange", 44 | "rate": 1, 45 | "calculated_at": null, 46 | "exchange_pair_id": null, 47 | "exchange_pair": null, 48 | "exchange_account_id": null, 49 | "exchange_account": null, 50 | "exchange_wallet_address": null, 51 | "exchange_wallet": null 52 | }, 53 | "status": "confirmed", 54 | "metadata": {}, 55 | "encrypted_metadata": {}, 56 | "created_at": "2018-01-01T00:00:00Z", 57 | "error_code": null, 58 | "error_description": null 59 | } 60 | 61 | ], 62 | "pagination": { 63 | "per_page": 10, 64 | "current_page": 1, 65 | "is_first_page": true, 66 | "is_last_page": true 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/me.get_wallets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "list", 6 | "data": [ 7 | { 8 | "object": "wallet", 9 | "address": "2c2e0f2e-fa0f-4abe-8516-9e92cf003486", 10 | "balances": [ 11 | { 12 | "object": "balance", 13 | "amount": 103100, 14 | "token": { 15 | "id": "OMG:123", 16 | "symbol": "OMG", 17 | "subunit_to_unit": 10000, 18 | "object": "token", 19 | "name": "OmiseGO", 20 | "metadata": {}, 21 | "encrypted_metadata": {}, 22 | "created_at": "2018-01-01T00:00:00Z", 23 | "updated_at": "2018-01-01T00:00:00Z" 24 | } 25 | }, 26 | { 27 | "object": "balance", 28 | "amount": 133700, 29 | "token": { 30 | "id": "KNC:123", 31 | "symbol": "KNC", 32 | "subunit_to_unit": 10000, 33 | "object": "token", 34 | "name": "Kyber", 35 | "metadata": {}, 36 | "encrypted_metadata": {}, 37 | "created_at": "2018-01-01T00:00:00Z", 38 | "updated_at": "2018-01-01T00:00:00Z" 39 | } 40 | } 41 | ], 42 | "name": "primary", 43 | "identifier": "primary", 44 | "user_id": "cec34607-0761-4a59-8357-18963e42a1aa", 45 | "user": { 46 | "id": "cec34607-0761-4a59-8357-18963e42a1aa", 47 | "provider_user_id": "wijf-fbancomw-dqwjudb", 48 | "username": "john.doe@example.com", 49 | "socket_topic": "user:cec34607-0761-4a59-8357-18963e42a1aa", 50 | "metadata": {}, 51 | "encrypted_metadata": {}, 52 | "created_at": "2018-01-01T00:00:00Z", 53 | "updated_at": "2018-01-01T00:00:00Z" 54 | }, 55 | "account_id": null, 56 | "account": null, 57 | "metadata": {}, 58 | "encrypted_metadata": {} 59 | } 60 | ] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/me.logout.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/user.login.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "authentication_token", 6 | "authentication_token": "azJRj09l7jvR8KhTqUs3", 7 | "user_id": "usr_01cc02x0v98qcctvycfx4vsk8x", 8 | "user": { 9 | "id": "usr_01cc02x0v98qcctvycfx4vsk8x", 10 | "provider_user_id": null, 11 | "username": null, 12 | "email": "user@example.com", 13 | "socket_topic": "user:usr_01cc02x0v98qcctvycfx4vsk8x", 14 | "metadata": {}, 15 | "encrypted_metadata": {}, 16 | "created_at": "2018-01-01T00:00:00Z", 17 | "updated_at": "2018-01-01T00:00:00Z" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/user.reset_password.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/user.signup.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Client/FixtureTests/client_fixtures/api/user.update_password.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": {} 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Client/LiveTests/LiveClientTestCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LiveClientTestCase.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 18/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class LiveClientTestCase: LiveTestCase { 13 | var testClient: HTTPClientAPI! 14 | var testSocketClient: SocketClient! 15 | 16 | override func setUp() { 17 | super.setUp() 18 | self.testClient = HTTPClientAPI(config: self.validHTTPConfig()) 19 | self.testSocketClient = SocketClient(config: self.validSocketConfig(), delegate: nil) 20 | } 21 | 22 | private func validHTTPConfig() -> ClientConfiguration { 23 | let credentials = ClientCredential(apiKey: self.validAPIKey, 24 | authenticationToken: self.validAuthenticationToken) 25 | return ClientConfiguration(baseURL: self.validBaseURL, credentials: credentials) 26 | } 27 | 28 | private func validSocketConfig() -> ClientConfiguration { 29 | let credentials = ClientCredential(apiKey: self.validAPIKey, 30 | authenticationToken: self.validAuthenticationToken) 31 | return ClientConfiguration(baseURL: self.validWebsocketURL, credentials: credentials) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/Client/LiveTests/ResponseLiveTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResponseLiveTest.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 18/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class ResponseLiveTest: LiveClientTestCase { 13 | func testWrongEndpoint() { 14 | let expectation = self.expectation(description: "Error response") 15 | let endpoint = TestAPIEndpoint(path: "not_existing") 16 | let request: Request? = self.testClient.request(toEndpoint: endpoint) { result in 17 | defer { expectation.fulfill() } 18 | switch result { 19 | case .success(data: _): 20 | XCTFail("Should not succeed") 21 | case let .fail(error): 22 | switch error { 23 | case let .api(apiError: apiError): 24 | XCTAssertEqual(apiError.code, .endPointNotFound) 25 | default: 26 | XCTFail("Error should be an API error") 27 | } 28 | } 29 | } 30 | XCTAssertNotNil(request) 31 | waitForExpectations(timeout: 15.0, handler: nil) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/Client/LiveTests/SettingLiveTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingLiveTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 10/11/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class SettingLiveTests: LiveClientTestCase { 13 | func testGetSettings() { 14 | let expectation = self.expectation(description: "Setting result") 15 | let request = Setting.get(using: self.testClient) { result in 16 | defer { expectation.fulfill() } 17 | switch result { 18 | case let .success(setting): 19 | XCTAssert(!setting.tokens.isEmpty) 20 | case let .fail(error): 21 | XCTFail("\(error)") 22 | } 23 | } 24 | XCTAssertNotNil(request) 25 | waitForExpectations(timeout: 15.0, handler: nil) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/Client/LiveTests/TransactionLiveTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionLiveTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 23/2/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class TransactionLiveTests: LiveClientTestCase { 13 | func testGetTransactionList() { 14 | let expectation = self.expectation(description: "Get paginated list of transactions") 15 | let paginationParams = PaginatedListParams( 16 | page: 1, 17 | perPage: 10, 18 | sortBy: .createdAt, 19 | sortDirection: .descending) 20 | let params = TransactionListParams(paginatedListParams: paginationParams, address: nil) 21 | let request = Transaction.list( 22 | using: self.testClient, 23 | params: params) { result in 24 | defer { expectation.fulfill() } 25 | switch result { 26 | case let .success(paginatedList): 27 | XCTAssertEqual(paginatedList.pagination.currentPage, 1) 28 | XCTAssertTrue(paginatedList.pagination.isFirstPage) 29 | case let .fail(error): 30 | XCTFail("\(error)") 31 | } 32 | } 33 | XCTAssertNotNil(request) 34 | waitForExpectations(timeout: 15.0, handler: nil) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/Client/LiveTests/UserLiveTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserLiveTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 18/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import OmiseGO 11 | import XCTest 12 | 13 | class UserLiveTests: LiveClientTestCase { 14 | func testCurrentUserRetrieve() { 15 | let expectation = self.expectation(description: "Get current user from authentication token") 16 | let request = User.getCurrent(using: self.testClient) { result in 17 | defer { expectation.fulfill() } 18 | switch result { 19 | case let .success(user): 20 | XCTAssertNotNil(user) 21 | case let .fail(error): 22 | XCTFail("\(error)") 23 | } 24 | } 25 | XCTAssertNotNil(request) 26 | waitForExpectations(timeout: 15.0, handler: nil) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Client/LiveTests/WalletLiveTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WalletLiveTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 10/11/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class WalletLiveTests: LiveClientTestCase { 13 | func testGetAll() { 14 | let expectation = self.expectation(description: "Get the list of wallets") 15 | let request = Wallet.getAll(using: self.testClient) { result in 16 | defer { expectation.fulfill() } 17 | switch result { 18 | case let .success(data: addresses): 19 | XCTAssert(!addresses.isEmpty) 20 | case let .fail(error: error): 21 | XCTFail("\(error)") 22 | } 23 | } 24 | XCTAssertNotNil(request) 25 | waitForExpectations(timeout: 15.0, handler: nil) 26 | } 27 | 28 | func testGetMain() { 29 | let expectation = self.expectation(description: "Get the main wallet") 30 | let request = Wallet.getMain(using: self.testClient) { result in 31 | defer { expectation.fulfill() } 32 | switch result { 33 | case .success(data: _): 34 | XCTAssertTrue(true) 35 | case let .fail(error: error): 36 | XCTFail("\(error)") 37 | } 38 | } 39 | XCTAssertNotNil(request) 40 | waitForExpectations(timeout: 15.0, handler: nil) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Tests/Core/APITests/CredentialEncoderTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CredentialEncoderTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 9/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class CredentialEncoderTests: XCTestCase { 13 | func testEncodeAuthorizationHeaderCorrectly() { 14 | XCTAssertEqual( 15 | try! CredentialEncoder.encode(value1: "123", value2: "123", scheme: "OMGClient"), 16 | "OMGClient \("123:123".data(using: .utf8)!.base64EncodedString())" 17 | ) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/Core/APITests/HTTPClientTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPClientTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 11/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class HTTPClientTests: XCTestCase { 13 | func testIsAuthenticatedIsTrueWhenAuthenticated() { 14 | let config = TestConfiguration(baseURL: "http://localhost:4000", credentials: TestCredential(authenticated: true)) 15 | let client = HTTPAPI(config: config) 16 | XCTAssertTrue(client.isAuthenticated) 17 | } 18 | 19 | func testIsAuthenticatedIsFalseWhenNotAuthenticated() { 20 | let config = TestConfiguration(baseURL: "http://localhost:4000", credentials: TestCredential(authenticated: false)) 21 | let client = HTTPAPI(config: config) 22 | XCTAssertFalse(client.isAuthenticated) 23 | } 24 | 25 | func testInvalidURL() { 26 | let expectation = self.expectation(description: "Invalid url") 27 | let config = TestConfiguration(baseURL: "invalid url @") 28 | let client = HTTPAPI(config: config) 29 | let dummyEndpoint = TestAPIEndpoint() 30 | let request: Request? = client.request(toEndpoint: dummyEndpoint) { result in 31 | defer { 32 | expectation.fulfill() 33 | } 34 | switch result { 35 | case .success(data: _): 36 | XCTFail("Request should not be executed if base url is not correct") 37 | case let .fail(error): 38 | switch error { 39 | case .configuration(message: _): break 40 | default: XCTFail("Error should be a configuration error") 41 | } 42 | } 43 | } 44 | XCTAssertNil(request, "Request should be nil") 45 | waitForExpectations(timeout: 15.0, handler: nil) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Tests/Core/APITests/RequestTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestTest.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 6/2/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class RequestTest: XCTestCase { 13 | let client: HTTPAPI = HTTPAPI(config: TestConfiguration()) 14 | 15 | func testStartRequest() { 16 | let request: Request = 17 | Request(client: client, endpoint: TestAPIEndpoint()) { _ in } 18 | do { 19 | XCTAssertNil(request.task) 20 | _ = try request.start() 21 | XCTAssertNotNil(request.task) 22 | } catch let error { 23 | XCTFail(error.localizedDescription) 24 | } 25 | } 26 | 27 | func testCancelRequest() { 28 | let expectation = self.expectation(description: "Task is cancelled") 29 | let dummyEndpoint = TestAPIEndpoint() 30 | let request: Request = 31 | Request(client: client, 32 | endpoint: dummyEndpoint) { result in 33 | defer { expectation.fulfill() } 34 | switch result { 35 | case .success: XCTFail("Expected failure") 36 | case let .fail(error: error): 37 | XCTAssertEqual(error.description, "I/O error: cancelled") 38 | } 39 | } 40 | do { 41 | XCTAssertNil(request.task) 42 | _ = try request.start() 43 | XCTAssertNotNil(request.task) 44 | request.cancel() 45 | self.wait(for: [expectation], timeout: 10) 46 | XCTAssertEqual(request.task!.state, .completed) 47 | } catch let error { 48 | XCTFail(error.localizedDescription) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/DecodingFixtureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DecodingFixtureTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 25/6/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class DecodingFixtureTests: FixtureTestCase { 13 | func testFailToDecodeANumberWhenExpectingAString() { 14 | let e = self.expectation(description: "Raise a decoding error") 15 | let endpoint = TestAPIEndpoint(path: "dummy.decoding_error") 16 | let request: Request? = self.testClient.request(toEndpoint: endpoint) { result in 17 | switch result { 18 | case .success(data: _): XCTFail("Excpected a decoding error") 19 | case let .fail(error: error): 20 | defer { e.fulfill() } 21 | XCTAssertEqual(error.message, "decoding error: Expected to decode String but found a number instead.") 22 | } 23 | } 24 | self.waitForExpectations(timeout: 5, handler: nil) 25 | XCTAssertNotNil(request) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/FixtureTestCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FixtureTestCase.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 10/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class FixtureTestCase: XCTestCase { 13 | var testClient: FixtureCoreAPI { 14 | let bundle = Bundle(for: FixtureTestCase.self) 15 | let url = bundle.url(forResource: "core_fixtures", withExtension: nil)! 16 | let config = TestConfiguration() 17 | return FixtureCoreAPI(fixturesDirectoryURL: url, config: config) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/ListableTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListableTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 7/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class ListableTests: FixtureTestCase { 13 | func testListableFailure() { 14 | let expectation = self.expectation(description: "Fails to load the response for this dummy object") 15 | TestListable.list(using: self.testClient) { response in 16 | defer { expectation.fulfill() } 17 | switch response { 18 | case .success(data: _): XCTFail("Shouldn't succeed") 19 | case let .fail(error: error): 20 | XCTAssertEqual(error.message, "error_message") 21 | } 22 | } 23 | waitForExpectations(timeout: 15.0, handler: nil) 24 | } 25 | 26 | func testPaginatedListableFailure() { 27 | let expectation = self.expectation(description: "Fails to load the response for this paginated dummy object") 28 | PaginatedTestListable.list(using: self.testClient) { response in 29 | defer { expectation.fulfill() } 30 | switch response { 31 | case .success(data: _): XCTFail("Shouldn't succeed") 32 | case let .fail(error: error): 33 | XCTAssertEqual(error.message, "error_message") 34 | } 35 | } 36 | waitForExpectations(timeout: 15.0, handler: nil) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/ResponseFixtureTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResponseTest.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 10/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class ResponseFixtureTest: FixtureTestCase { 13 | func testParseSuccessResponse() { 14 | let expectation = self.expectation(description: "Parse success response") 15 | let endpoint = TestAPIEndpoint(path: "dummy.success") 16 | let request: Request? = self.testClient.request(toEndpoint: endpoint) { result in 17 | defer { expectation.fulfill() } 18 | switch result { 19 | case let .success(object): 20 | XCTAssertEqual(object.object, "success_test_object") 21 | case let .fail(error): 22 | XCTFail("\(error)") 23 | } 24 | } 25 | XCTAssertNotNil(request) 26 | waitForExpectations(timeout: 15.0, handler: nil) 27 | } 28 | 29 | func testParseErrorResponse() { 30 | let expectation = self.expectation(description: "Parse error response") 31 | let endpoint = TestAPIEndpoint(path: "dummy.failure") 32 | let request: Request? = self.testClient.request(toEndpoint: endpoint) { result in 33 | defer { expectation.fulfill() } 34 | switch result { 35 | case .success(data: _): 36 | XCTFail("Should not succeed") 37 | case let .fail(error): 38 | XCTAssertEqual(error.description, "error_message") 39 | } 40 | } 41 | XCTAssertNotNil(request) 42 | waitForExpectations(timeout: 15.0, handler: nil) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/api/dummy.decoding_error.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": 1234 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/api/dummy.failure.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": false, 4 | "data": { 5 | "object": "error", 6 | "code": "error_code", 7 | "description": "error_message" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/api/dummy.listable.failure.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": false, 4 | "data": { 5 | "object": "error", 6 | "code": "error_code", 7 | "description": "error_message" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/api/dummy.paginated_listable.failure.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": false, 4 | "data": { 5 | "object": "error", 6 | "code": "error_code", 7 | "description": "error_message" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/api/dummy.success.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "object": "success_test_object" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/account.json: -------------------------------------------------------------------------------- 1 | { 2 | "object": "account", 3 | "id": "acc_01CA2P8JQANS5ATY5GJ5ETMJCF", 4 | "parent_id": "acc_01CA26PKGE49AABZD6K6MSHN0Y", 5 | "name": "Account Name", 6 | "description": "The account description", 7 | "master": false, 8 | "metadata": {}, 9 | "encrypted_metadata": {}, 10 | "avatar": { 11 | "original": "original_url", 12 | "large": "large_url", 13 | "small": "small_url", 14 | "thumb": "thumb_url" 15 | }, 16 | "created_at": "2018-01-01T00:00:00Z", 17 | "updated_at": "2018-01-01T10:00:00Z" 18 | } 19 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/api_error.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": "client:invalid_parameter", 3 | "description": "Invalid parameters" 4 | } 5 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/authentication_token.json: -------------------------------------------------------------------------------- 1 | { 2 | "authentication_token": "azJRj09l7jvR8KhTqUs3", 3 | "user_id": "usr_01cc02x0v98qcctvycfx4vsk8x", 4 | "user": { 5 | "id": "usr_01cc02x0v98qcctvycfx4vsk8x", 6 | "provider_user_id": "wijf-fbancomw-dqwjudb", 7 | "username": "john.doe@example.com", 8 | "socket_topic": "user:usr_01cc02x0v98qcctvycfx4vsk8x", 9 | "metadata": {}, 10 | "encrypted_metadata": {}, 11 | "created_at": "2018-01-01T00:00:00Z", 12 | "updated_at": "2018-01-01T00:00:00Z" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/avatar.json: -------------------------------------------------------------------------------- 1 | { 2 | "original": "original_url", 3 | "large": "large_url", 4 | "small": "small_url", 5 | "thumb": "thumb_url" 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/balance.json: -------------------------------------------------------------------------------- 1 | { 2 | "amount": 103100, 3 | "token": { 4 | "id": "OMG:123", 5 | "symbol": "OMG", 6 | "subunit_to_unit": 10000, 7 | "name": "OmiseGO", 8 | "metadata": {}, 9 | "encrypted_metadata": {}, 10 | "created_at": "2018-01-01T00:00:00Z", 11 | "updated_at": "2018-01-01T00:00:00Z" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/bigint_int32.json: -------------------------------------------------------------------------------- 1 | { 2 | "value": 2147483647, 3 | } 4 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/bigint_int64.json: -------------------------------------------------------------------------------- 1 | { 2 | "value": 922337203685400, 3 | } 4 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/bigint_invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "value": 999999999999999999999999999999999999991 3 | } 4 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/bigint_over_int64.json: -------------------------------------------------------------------------------- 1 | { 2 | "value": 99999999999999999999999999999999999998, 3 | } 4 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/dates.json: -------------------------------------------------------------------------------- 1 | { 2 | "date_1": "2018-01-01T01:00:00.000000Z", 3 | "date_2": "2018-01-01T02:00:00.000Z", 4 | "date_3": "2018-01-01T03:00:00Z" 5 | } 6 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/dates_invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "invalid_date": "an invalid date" 3 | } 4 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/exchange_pair.json: -------------------------------------------------------------------------------- 1 | { 2 | "object": "exchange_pair", 3 | "id": "exg_01cgvppyrz2pprj6s0zmc26p2p", 4 | "name": "ETH/OMG", 5 | "from_token_id": "tok_ETH_01cbfge9qhmsdbjyb7a8e8pxt3", 6 | "from_token": { 7 | "id": "tok_ETH_01cbfge9qhmsdbjyb7a8e8pxt3", 8 | "symbol": "ETH", 9 | "name": "Ethereum", 10 | "subunit_to_unit": 100000, 11 | "metadata": {}, 12 | "encrypted_metadata": {}, 13 | "created_at": "2018-01-01T00:00:00Z", 14 | "updated_at": "2018-01-01T00:00:00Z" 15 | }, 16 | "to_token_id": "tok_OMG_01cgvrqbfpa23ehkmrtqpbsyyp", 17 | "to_token": { 18 | "id": "tok_OMG_01cgvrqbfpa23ehkmrtqpbsyyp", 19 | "symbol": "OMG", 20 | "name": "OmiseGO", 21 | "subunit_to_unit": 10000, 22 | "metadata": {}, 23 | "encrypted_metadata": {}, 24 | "created_at": "2018-01-01T00:00:00Z", 25 | "updated_at": "2018-01-01T00:00:00Z" 26 | }, 27 | "rate": 0.017, 28 | "created_at": "2018-01-01T00:00:00Z", 29 | "updated_at": "2018-01-01T10:00:00Z" 30 | } 31 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/json_list_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "data": ["value_1", "value_2"], 6 | "pagination": { 7 | "per_page": 10, 8 | "current_page": 1, 9 | "is_first_page": true, 10 | "is_last_page": true 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/json_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "data": { 5 | "a_key": "a_value" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata":{ 3 | "a_string": "some_string", 4 | "an_integer": 1, 5 | "a_bool": true, 6 | "a_double": 12.34, 7 | "an_object": { 8 | "a_key": "a_value", 9 | "a_nested_object": { 10 | "a_nested_key": "a_nested_value" 11 | } 12 | }, 13 | "an_array": [ 14 | "value_1", "value_2" 15 | ], 16 | "a_null_key": null 17 | }, 18 | "metadata_array":[ 19 | "value_1", 20 | 1, 21 | true, 22 | 13.37, 23 | { 24 | "a_key": "a_value" 25 | }, 26 | ["a_nested_value"] 27 | ], 28 | "optional_metadata": { 29 | "a_string": "some_string" 30 | }, 31 | "optional_metadata_array": ["a_value"] 32 | } 33 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/metadata_null.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": null 3 | } 4 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/pagination.json: -------------------------------------------------------------------------------- 1 | { 2 | "per_page": 10, 3 | "current_page": 1, 4 | "is_first_page": true, 5 | "is_last_page": true 6 | } 7 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "tokens": [ 3 | { 4 | "id": "OMG:123", 5 | "symbol": "OMG", 6 | "name": "OmiseGO", 7 | "subunit_to_unit": 100000000, 8 | "metadata": {}, 9 | "encrypted_metadata": {}, 10 | "created_at": "2018-01-01T00:00:00Z", 11 | "updated_at": "2018-01-01T00:00:00Z" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/socket_response_failure.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": false, 4 | "topic": "a_topic", 5 | "ref": "1", 6 | "event": "an_event", 7 | "error": { 8 | "object": "error", 9 | "code": "client:invalid_parameter", 10 | "description": "Invalid parameters" 11 | }, 12 | "data": null, 13 | } 14 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/socket_response_reply.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "topic": "a_topic", 5 | "ref": "2", 6 | "error": null, 7 | "event": "phx_reply", 8 | "data": {} 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/socket_response_unknown_object.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "success": true, 4 | "topic": "a_topic", 5 | "ref": "1", 6 | "event": "an_event", 7 | "error": null, 8 | "data": { 9 | "object": "an unknown object", 10 | "a_param": "a_value" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/token.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "OMG:123", 3 | "symbol": "OMG", 4 | "name": "OmiseGO", 5 | "subunit_to_unit": 100000000, 6 | "metadata": {}, 7 | "encrypted_metadata": {}, 8 | "created_at": "2018-01-01T00:00:00Z", 9 | "updated_at": "2018-01-01T00:00:00Z" 10 | } 11 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "object": "transaction", 3 | "id": "ce3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 4 | "from": { 5 | "object": "transaction_source", 6 | "address": "1e3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 7 | "amount": 1000, 8 | "token": { 9 | "object": "token", 10 | "id": "BTC:xe3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 11 | "symbol": "BTC", 12 | "name": "Bitcoin", 13 | "subunit_to_unit": 100, 14 | "metadata": {}, 15 | "encrypted_metadata": {}, 16 | "created_at": "2018-01-01T00:00:00Z", 17 | "updated_at": "2018-01-01T00:00:00Z" 18 | } 19 | }, 20 | "to": { 21 | "object": "transaction_source", 22 | "address": "2e3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 23 | "amount": 1000, 24 | "token": { 25 | "object": "token", 26 | "id": "BTC:xe3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 27 | "symbol": "BTC", 28 | "name": "Bitcoin", 29 | "subunit_to_unit": 100, 30 | "metadata": {}, 31 | "encrypted_metadata": {}, 32 | "created_at": "2018-01-01T00:00:00Z", 33 | "updated_at": "2018-01-01T00:00:00Z" 34 | } 35 | }, 36 | "exchange": { 37 | "object": "exchange", 38 | "rate": 1, 39 | "calculated_at": null, 40 | "exchange_pair_id": null, 41 | "exchange_pair": null, 42 | "exchange_account_id": null, 43 | "exchange_account": null, 44 | "exchange_wallet_address": null, 45 | "exchange_wallet": null 46 | }, 47 | "status": "confirmed", 48 | "metadata": {}, 49 | "encrypted_metadata": {}, 50 | "created_at": "2018-01-01T00:00:00Z", 51 | "error_code": "transaction:same_address", 52 | "error_description": "Same address" 53 | } 54 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/transaction_source.json: -------------------------------------------------------------------------------- 1 | { 2 | "object": "transaction_source", 3 | "address": "2e3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 4 | "amount": 1000, 5 | "token": { 6 | "object": "token", 7 | "id": "BTC:xe3982f5-4a27-498d-a91b-7bb2e2a8d3d1", 8 | "symbol": "BTC", 9 | "name": "Bitcoin", 10 | "subunit_to_unit": 100, 11 | "metadata": {}, 12 | "encrypted_metadata": {}, 13 | "created_at": "2018-01-01T00:00:00Z", 14 | "updated_at": "2018-01-01T00:00:00Z" 15 | }, 16 | "user": { 17 | "id": "cec34607-0761-4a59-8357-18963e42a1aa", 18 | "provider_user_id": "wijf-fbancomw-dqwjudb", 19 | "username": "john.doe@example.com", 20 | "email": "john.doe@example.com", 21 | "socket_topic": "user:cec34607-0761-4a59-8357-18963e42a1aa", 22 | "metadata": {}, 23 | "encrypted_metadata": {}, 24 | "created_at": "2018-01-01T00:00:00Z", 25 | "updated_at": "2018-01-01T00:00:00Z" 26 | }, 27 | "account": { 28 | "object": "account", 29 | "id": "acc_01CA2P8JQANS5ATY5GJ5ETMJCF", 30 | "parent_id": "acc_01CA26PKGE49AABZD6K6MSHN0Y", 31 | "name": "Account Name", 32 | "description": "The account description", 33 | "master": false, 34 | "metadata": {}, 35 | "encrypted_metadata": {}, 36 | "avatar": { 37 | "original": "original_url", 38 | "large": "large_url", 39 | "small": "small_url", 40 | "thumb": "thumb_url" 41 | }, 42 | "created_at": "2018-01-01T00:00:00Z", 43 | "updated_at": "2018-01-01T10:00:00Z" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "cec34607-0761-4a59-8357-18963e42a1aa", 3 | "provider_user_id": "wijf-fbancomw-dqwjudb", 4 | "username": "john.doe@example.com", 5 | "email": "john.doe@example.com", 6 | "socket_topic": "user:cec34607-0761-4a59-8357-18963e42a1aa", 7 | "metadata": {}, 8 | "encrypted_metadata": {}, 9 | "created_at": "2018-01-01T00:00:00Z", 10 | "updated_at": "2018-01-01T00:00:00Z" 11 | } 12 | -------------------------------------------------------------------------------- /Tests/Core/FixtureTests/core_fixtures/objects/wallet.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "2c2e0f2e-fa0f-4abe-8516-9e92cf003486", 3 | "balances": [ 4 | { 5 | "amount": 103100, 6 | "token": { 7 | "id": "OMG:123", 8 | "symbol": "OMG", 9 | "subunit_to_unit": 10000, 10 | "name": "OmiseGO", 11 | "metadata": {}, 12 | "encrypted_metadata": {}, 13 | "created_at": "2018-01-01T00:00:00Z", 14 | "updated_at": "2018-01-01T00:00:00Z" 15 | } 16 | } 17 | ], 18 | "name": "primary", 19 | "identifier": "primary", 20 | "user_id": "cec34607-0761-4a59-8357-18963e42a1aa", 21 | "user": { 22 | "id": "cec34607-0761-4a59-8357-18963e42a1aa", 23 | "provider_user_id": "wijf-fbancomw-dqwjudb", 24 | "username": "john.doe@example.com", 25 | "socket_topic": "user:cec34607-0761-4a59-8357-18963e42a1aa", 26 | "metadata": {}, 27 | "encrypted_metadata": {}, 28 | "created_at": "2018-01-01T00:00:00Z", 29 | "updated_at": "2018-01-01T00:00:00Z" 30 | }, 31 | "account_id": null, 32 | "account": null, 33 | "metadata": {}, 34 | "encrypted_metadata": {} 35 | } 36 | -------------------------------------------------------------------------------- /Tests/Core/Helpers/Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 23/2/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension String { 12 | func toDate(withFormat format: String? = "yyyy-MM-dd'T'HH:mm:ssZ") -> Date { 13 | let formatter = DateFormatter() 14 | formatter.dateFormat = format 15 | return formatter.date(from: self)! 16 | } 17 | } 18 | 19 | extension String { 20 | func uglifiedEncodedString() -> String { 21 | return replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: " ", with: "") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/Core/ModelTests/AccountTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AccountTest.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 20/4/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class AccountTest: XCTestCase { 13 | func testEquatable() { 14 | let account1 = StubGenerator.account(id: "123") 15 | let account2 = StubGenerator.account(id: "123") 16 | let account3 = StubGenerator.account(id: "321") 17 | XCTAssertEqual(account1, account2) 18 | XCTAssertNotEqual(account1, account3) 19 | } 20 | 21 | func testHashable() { 22 | let account1 = StubGenerator.account(id: "123") 23 | let account2 = StubGenerator.account(id: "123") 24 | let set: Set = [account1, account2] 25 | XCTAssertEqual(account1.hashValue, "123".hashValue) 26 | XCTAssertEqual(set.count, 1) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Core/ModelTests/AuthenticationTokenTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AuthenticationTokenTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 15/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class AuthenticationTokenTests: XCTestCase { 13 | func testEquatable() { 14 | let token1 = StubGenerator.authenticationToken(token: "123") 15 | let token2 = StubGenerator.authenticationToken(token: "123") 16 | let token3 = StubGenerator.authenticationToken(token: "789") 17 | XCTAssertEqual(token1, token2) 18 | XCTAssertNotEqual(token1, token3) 19 | } 20 | 21 | func testHashable() { 22 | let token1 = StubGenerator.authenticationToken(token: "123") 23 | let token2 = StubGenerator.authenticationToken(token: "123") 24 | let set: Set = [token1, token2] 25 | XCTAssertEqual(token1.hashValue, "123".hashValue) 26 | XCTAssertEqual(set.count, 1) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Core/ModelTests/ExchangePairTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExchangePairTest.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 29/6/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class ExchangePairTest: XCTestCase { 13 | func testEquatable() { 14 | let pair1 = StubGenerator.exchangePair(id: "123") 15 | let pair2 = StubGenerator.exchangePair(id: "123") 16 | let pair3 = StubGenerator.exchangePair(id: "321") 17 | XCTAssertEqual(pair1, pair2) 18 | XCTAssertNotEqual(pair1, pair3) 19 | } 20 | 21 | func testHashable() { 22 | let pair1 = StubGenerator.exchangePair(id: "123") 23 | let pair2 = StubGenerator.exchangePair(id: "123") 24 | let set: Set = [pair1, pair2] 25 | XCTAssertEqual(pair1.hashValue, "123".hashValue) 26 | XCTAssertEqual(set.count, 1) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Core/ModelTests/TokenTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TokenTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 20/11/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class TokenTests: XCTestCase { 13 | func testEquatable() { 14 | let token1 = StubGenerator.token(id: "OMG:123") 15 | let token2 = StubGenerator.token(id: "OMG:123") 16 | let token3 = StubGenerator.token(id: "BTC:123") 17 | XCTAssertEqual(token1, token2) 18 | XCTAssertNotEqual(token1, token3) 19 | } 20 | 21 | func testHashable() { 22 | let token1 = StubGenerator.token(id: "OMG:123") 23 | let token2 = StubGenerator.token(id: "OMG:123") 24 | let set: Set = [token1, token2] 25 | XCTAssertEqual(token1.hashValue, "OMG:123".hashValue) 26 | XCTAssertEqual(set.count, 1) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Core/ModelTests/TransactionConsumptionTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionConsumptionTest.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 13/2/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class TransactionConsumptionTest: XCTestCase { 13 | func testEquatable() { 14 | let transactionConsumption1 = StubGenerator.transactionConsumption(id: "1") 15 | let transactionConsumption2 = StubGenerator.transactionConsumption(id: "1") 16 | let transactionConsumption3 = StubGenerator.transactionConsumption(id: "2") 17 | XCTAssertEqual(transactionConsumption1, transactionConsumption2) 18 | XCTAssertNotEqual(transactionConsumption1, transactionConsumption3) 19 | } 20 | 21 | func testHashable() { 22 | let transactionConsumption1 = StubGenerator.transactionConsumption(id: "1") 23 | let transactionConsumption2 = StubGenerator.transactionConsumption(id: "1") 24 | let set: Set = [transactionConsumption1, transactionConsumption2] 25 | XCTAssertEqual(transactionConsumption1.hashValue, "1".hashValue) 26 | XCTAssertEqual(set.count, 1) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Core/ModelTests/TransactionRequestTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionRequestTest.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 5/2/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class TransactionRequestTest: XCTestCase { 13 | func testQRCodeImage() { 14 | let transactionRequest = StubGenerator.transactionRequest() 15 | if let qrImage = transactionRequest.qrImage() { 16 | let decodedText = TestQRHelper.readQRCode(fromImage: qrImage) 17 | XCTAssertEqual(decodedText, transactionRequest.formattedId) 18 | } else { 19 | XCTFail("QR image should not be nil") 20 | } 21 | } 22 | 23 | func testEquatable() { 24 | let transactionRequest1 = StubGenerator.transactionRequest(id: "1") 25 | let transactionRequest2 = StubGenerator.transactionRequest(id: "1") 26 | let transactionRequest3 = StubGenerator.transactionRequest(id: "2") 27 | XCTAssertEqual(transactionRequest1, transactionRequest2) 28 | XCTAssertNotEqual(transactionRequest1, transactionRequest3) 29 | } 30 | 31 | func testHashable() { 32 | let transactionRequest1 = StubGenerator.transactionRequest(id: "1") 33 | let transactionRequest2 = StubGenerator.transactionRequest(id: "1") 34 | let set: Set = [transactionRequest1, transactionRequest2] 35 | XCTAssertEqual(transactionRequest1.hashValue, "1".hashValue) 36 | XCTAssertEqual(set.count, 1) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Tests/Core/ModelTests/TransactionTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransactionTest.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 23/2/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class TransactionTest: XCTestCase { 13 | func testEquatable() { 14 | let transaction1 = StubGenerator.transaction(id: "1") 15 | let transaction2 = StubGenerator.transaction(id: "1") 16 | let transaction3 = StubGenerator.transaction(id: "2") 17 | XCTAssertEqual(transaction1, transaction2) 18 | XCTAssertNotEqual(transaction1, transaction3) 19 | } 20 | 21 | func testHashable() { 22 | let transaction1 = StubGenerator.transaction(id: "1") 23 | let transaction2 = StubGenerator.transaction(id: "1") 24 | let set: Set = [transaction1, transaction2] 25 | XCTAssertEqual(transaction1.hashValue, "1".hashValue) 26 | XCTAssertEqual(set.count, 1) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Core/ModelTests/UserTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 20/11/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class UserTests: XCTestCase { 13 | func testEquatable() { 14 | let user1 = StubGenerator.user(id: "123") 15 | let user2 = StubGenerator.user(id: "123") 16 | let user3 = StubGenerator.user(id: "321") 17 | XCTAssertEqual(user1, user2) 18 | XCTAssertNotEqual(user1, user3) 19 | } 20 | 21 | func testHashable() { 22 | let user1 = StubGenerator.user(id: "123") 23 | let user2 = StubGenerator.user(id: "123") 24 | let set: Set = [user1, user2] 25 | XCTAssertEqual(user1.hashValue, "123".hashValue) 26 | XCTAssertEqual(set.count, 1) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Core/ModelTests/WalletTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WalletTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 20/11/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | import XCTest 11 | 12 | class WalletTests: XCTestCase { 13 | func testEquatable() { 14 | let address1 = StubGenerator.wallet(address: "123") 15 | let address2 = StubGenerator.wallet(address: "123") 16 | let address3 = StubGenerator.wallet(address: "321") 17 | XCTAssertEqual(address1, address2) 18 | XCTAssertNotEqual(address1, address3) 19 | } 20 | 21 | func testHashable() { 22 | let address1 = StubGenerator.wallet(address: "123") 23 | let address2 = StubGenerator.wallet(address: "123") 24 | let set: Set = [address1, address2] 25 | XCTAssertEqual(address1.hashValue, "123".hashValue) 26 | XCTAssertEqual(set.count, 1) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Core/OMGNumberFormatterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OMGNumberFormatterTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 18/6/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import BigInt 10 | @testable import OmiseGO 11 | import XCTest 12 | 13 | class OMGNumberFormatterTests: XCTestCase { 14 | let locale = NSLocale.current 15 | 16 | func testStringToBigIntWithSubunitToUnit() { 17 | let sut = OMGNumberFormatter(locale: self.locale, precision: 1) 18 | let result = sut.number(from: "10", subunitToUnit: 1_000_000_000_000_000_000) 19 | XCTAssertEqual(result, BigInt("10000000000000000000")) 20 | } 21 | 22 | func testStringToBigIntWithDecimal() { 23 | let sut = OMGNumberFormatter(locale: self.locale, precision: 1) 24 | let result = sut.number(from: "10", decimals: 18) 25 | XCTAssertEqual(result, BigInt("10000000000000000000")) 26 | } 27 | 28 | func testStringToBigIntWithDecimalAndPrecision() { 29 | let sut = OMGNumberFormatter(locale: self.locale, precision: 10000) 30 | let result = sut.number(from: "10", decimals: 18) 31 | XCTAssertEqual(result, BigInt("10000000000000000000")) 32 | } 33 | 34 | func testStringFromBigIntWithSubunitToUnit() { 35 | let sut = OMGNumberFormatter(locale: self.locale, precision: 1) 36 | let result = sut.string(from: BigInt("10000000000000000000"), subunitToUnit: 1_000_000_000_000_000_000) 37 | XCTAssertEqual(result, "10") 38 | } 39 | 40 | func testStringFromBigIntWithDecimal() { 41 | let sut = OMGNumberFormatter(locale: self.locale, precision: 1) 42 | let result = sut.string(from: BigInt("10000000000000000000"), decimals: 18) 43 | XCTAssertEqual(result, "10") 44 | } 45 | 46 | func testStringFromBigIntWithDecimalAndPrecision() { 47 | let sut = OMGNumberFormatter(locale: self.locale, precision: 2) 48 | let result = sut.string(from: BigInt("1"), decimals: 2) 49 | XCTAssertEqual(result, "0\(self.locale.decimalSeparator ?? ".")01") 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Tests/Core/QRCodeTests/QRGeneratorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRGeneratorTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 6/2/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class QRGeneratorTest: XCTestCase { 13 | func testImageSize() { 14 | let data = "Test data".data(using: .isoLatin1)! 15 | if let qrCode = QRGenerator.generateQRCode(fromData: data, outputSize: CGSize(width: 150, height: 150)) { 16 | XCTAssertEqual(qrCode.size.width, 150) 17 | XCTAssertEqual(qrCode.size.height, 150) 18 | } else { 19 | XCTFail("Failed to generate the qrCode") 20 | } 21 | } 22 | 23 | func testGeneratedQRCodeContainsInputText() { 24 | let inputText = "Test data" 25 | let data = inputText.data(using: .isoLatin1)! 26 | if let qrCode = QRGenerator.generateQRCode(fromData: data, outputSize: CGSize(width: 200, height: 200)) { 27 | let decodedText = TestQRHelper.readQRCode(fromImage: qrCode) 28 | XCTAssertEqual(decodedText, inputText) 29 | } else { 30 | XCTFail("Failed to generate the qrCode") 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/Core/QRCodeTests/QRReaderTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRReaderTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 12/2/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import AVFoundation 10 | @testable import OmiseGO 11 | import XCTest 12 | 13 | class QRReaderTest: XCTestCase { 14 | func testCallbackIsCalled() { 15 | let e = self.expectation(description: "calls delegate when decoding data") 16 | let delegate = DummyQRReaderDelegate(ex: e) 17 | let reader = TestQRReader(delegate: delegate) 18 | reader.mockValueFound(value: "123") 19 | waitForExpectations(timeout: 1, handler: nil) 20 | XCTAssertEqual(delegate.decodedData, "123") 21 | } 22 | } 23 | 24 | class DummyQRReaderDelegate: QRReaderDelegate { 25 | let e: XCTestExpectation 26 | var decodedData: String? 27 | 28 | init(ex: XCTestExpectation) { 29 | self.e = ex 30 | } 31 | 32 | func onDecodedData(decodedData: String) { 33 | self.decodedData = decodedData 34 | self.e.fulfill() 35 | } 36 | 37 | func onUserPermissionChoice(granted _: Bool) {} 38 | } 39 | -------------------------------------------------------------------------------- /Tests/Core/QRCodeTests/QRScannerViewTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRScannerViewTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 7/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class QRScannerViewTest: XCTestCase { 13 | func testInitWithCoder() { 14 | XCTAssertNil(QRScannerView(coder: NSCoder())) 15 | } 16 | 17 | func testInitWithFrame() { 18 | let frame = CGRect(x: 0, y: 0, width: 100, height: 100) 19 | let layer = CALayer() 20 | let view = QRScannerView(frame: frame, readerPreviewLayer: layer) 21 | XCTAssertEqual(view.frame, frame) 22 | XCTAssertEqual(view.readerPreviewLayer, layer) 23 | } 24 | 25 | func testLayoutSubviews() { 26 | let frame = CGRect(x: 0, y: 0, width: 100, height: 100) 27 | let layer = CALayer() 28 | let view = QRScannerView(frame: frame, readerPreviewLayer: layer) 29 | XCTAssertEqual(layer.frame, CGRect(x: 0, y: 0, width: 0, height: 0)) 30 | view.layoutSubviews() 31 | XCTAssertEqual(layer.frame, frame) 32 | } 33 | 34 | func testSetup() { 35 | let frame = CGRect(x: 0, y: 0, width: 100, height: 100) 36 | let layer = CALayer() 37 | let view = QRScannerView(frame: frame, readerPreviewLayer: layer) 38 | view.setup() 39 | XCTAssertTrue(view.subviews.contains(view.cameraView)) 40 | XCTAssertTrue(view.subviews.contains(view.overlayView)) 41 | XCTAssertTrue(view.subviews.contains(view.cancelButton)) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Tests/Core/SocketsTests/FixtureSocketClient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FixtureSocketClient.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 23/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import Starscream 10 | 11 | class FixtureWebsocketClient: WebSocketClient { 12 | var sslClientCertificate: SSLClientCertificate? 13 | 14 | var delegate: WebSocketDelegate? 15 | var pongDelegate: WebSocketPongDelegate? 16 | var disableSSLCertValidation: Bool = true 17 | var overrideTrustHostname: Bool = false 18 | var desiredTrustHostname: String? 19 | var security: SSLTrustValidator? 20 | var enabledSSLCipherSuites: [SSLCipherSuite]? 21 | var isConnected: Bool = false 22 | 23 | var didWriteString: String? 24 | var didWriteData: Data? 25 | 26 | var shouldAutoConnect = true 27 | 28 | func connect() { 29 | self.isConnected = self.shouldAutoConnect 30 | } 31 | 32 | func disconnect(forceTimeout _: TimeInterval?, closeCode _: UInt16) { 33 | self.isConnected = false 34 | } 35 | 36 | func write(string: String, completion: (() -> Void)?) { 37 | self.didWriteString = string 38 | completion?() 39 | } 40 | 41 | func write(data: Data, completion: (() -> Void)?) { 42 | self.didWriteData = data 43 | completion?() 44 | (self.delegate as? TestWebSocketDelegate)?.websocketDidSendData(socket: self, data: data) 45 | } 46 | 47 | func write(ping _: Data, completion: (() -> Void)?) { 48 | completion?() 49 | } 50 | 51 | func write(pong _: Data, completion: (() -> Void)?) { 52 | completion?() 53 | } 54 | 55 | func simulateReply() { 56 | let data = StubGenerator.fileContent(forResource: "socket_response_reply") 57 | self.delegate?.websocketDidReceiveMessage(socket: self, text: String(data: data, encoding: .utf8)!) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Tests/Core/SocketsTests/SocketMessageTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SocketMessageTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 22/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class SocketMessageTests: XCTestCase { 13 | var socketMessage: SocketMessage! 14 | 15 | override func setUp() { 16 | super.setUp() 17 | let payload = SocketPayloadSend(topic: "a_topic", event: .join, ref: "1", data: [:]) 18 | self.socketMessage = SocketMessage(socketPayload: payload) 19 | } 20 | 21 | func testCallsSuccessHandlerWhenSucceed() { 22 | let expectation = self.expectation(description: "Calls success handler when succeed") 23 | let payload = StubGenerator.socketPayloadReceive() 24 | let handler: ((GenericObjectEnum?) -> Void) = { response in 25 | switch response { 26 | case let .some(.transactionConsumption(object: tc)): XCTAssertNotNil(tc) 27 | default: XCTFail("Unexpected response") 28 | } 29 | expectation.fulfill() 30 | } 31 | self.socketMessage.onSuccess(handler) 32 | self.socketMessage.handleResponse(withPayload: payload) 33 | self.waitForExpectations(timeout: 1, handler: nil) 34 | } 35 | 36 | func testCallsErrorHandlerWhenFail() { 37 | let expectation = self.expectation(description: "Calls failure handler when fail") 38 | let payload = StubGenerator.socketPayloadReceive(error: APIError(code: .websocketError, description: ""), 39 | success: false) 40 | let handler: ((APIError) -> Void) = { error in 41 | XCTAssertEqual(error.code, .websocketError) 42 | expectation.fulfill() 43 | } 44 | self.socketMessage.onError(handler) 45 | self.socketMessage.handleResponse(withPayload: payload) 46 | self.waitForExpectations(timeout: 1, handler: nil) 47 | } 48 | 49 | func testTopicReturnsCorrectValue() { 50 | let payloadSend = SocketPayloadSend(topic: "topic_a", event: .join, ref: "1", data: [:]) 51 | let socketMessageSend = SocketMessage(socketPayload: payloadSend) 52 | XCTAssertEqual(socketMessageSend.topic(), "topic_a") 53 | let payloadReceive = StubGenerator.socketPayloadReceive(topic: "topic_b") 54 | let socketMessageReceive = SocketMessage(socketPayload: payloadReceive) 55 | XCTAssertEqual(socketMessageReceive.topic(), "topic_b") 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/QRScannerViewController+Test.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QRScannerViewController+Test.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 9/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | 11 | extension QRScannerViewController { 12 | convenience init?(delegate: QRScannerViewControllerDelegate, verifier: TestQRVerifier, cancelButtonTitle: String) { 13 | self.init(delegate: delegate, 14 | verifier: verifier, 15 | cancelButtonTitle: cancelButtonTitle, 16 | viewModel: QRScannerViewModel(verifier: verifier)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestAPIEndpoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestAPIEndpoint.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 9/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | 11 | struct TestAPIEndpoint: APIEndpoint { 12 | let path: String 13 | let task: HTTPTask 14 | 15 | init(path: String = "/test", task: HTTPTask = .requestPlain) { 16 | self.path = path 17 | self.task = task 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestBigUInt.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestBigUInt.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 18/6/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import BigInt 10 | @testable import OmiseGO 11 | 12 | struct TestBigUInt { 13 | let value: BigInt 14 | } 15 | 16 | extension TestBigUInt: Codable { 17 | private enum CodingKeys: String, CodingKey { 18 | case value 19 | } 20 | 21 | func encode(to encoder: Encoder) throws { 22 | var container = encoder.container(keyedBy: CodingKeys.self) 23 | try container.encode(value, forKey: .value) 24 | } 25 | 26 | init(from decoder: Decoder) throws { 27 | let container = try decoder.container(keyedBy: CodingKeys.self) 28 | value = try container.decode(BigInt.self, forKey: .value) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestConfiguration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestConfiguration.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 9/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | 11 | struct TestConfiguration: Configuration { 12 | let apiVersion: String = "1" 13 | 14 | let baseURL: String 15 | 16 | var credentials: Credential 17 | 18 | let debugLog: Bool = false 19 | 20 | init(baseURL: String = "http://localhost:4000", credentials: TestCredential = TestCredential(authenticated: true)) { 21 | self.baseURL = baseURL 22 | self.credentials = credentials 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestCredential.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestCredential.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 9/8/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | 11 | struct TestCredential: Credential { 12 | var authenticated: Bool 13 | 14 | init(authenticated: Bool) { 15 | self.authenticated = authenticated 16 | } 17 | 18 | func isAuthenticated() -> Bool { 19 | return self.authenticated 20 | } 21 | 22 | mutating func update(withAuthenticationToken _: AuthenticationToken) { 23 | self.authenticated = true 24 | } 25 | 26 | func authentication() throws -> String? { 27 | return self.authenticated ? "OMGClient \("123:123".data(using: .utf8)!.base64EncodedString())" : nil 28 | } 29 | 30 | mutating func invalidate() { 31 | self.authenticated = false 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestDate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestDate.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 23/2/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct TestDate: Decodable { 12 | let date1: Date 13 | let date2: Date 14 | let date3: Date 15 | 16 | enum CodingKeys: String, CodingKey { 17 | case date1 = "date_1" 18 | case date2 = "date_2" 19 | case date3 = "date_3" 20 | } 21 | } 22 | 23 | struct TestDateInvalid: Decodable { 24 | let invalidDate: Date 25 | 26 | enum CodingKeys: String, CodingKey { 27 | case invalidDate = "invalid_date" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestListable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestListable.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 7/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | 11 | struct TestListable: Decodable, Listable { 12 | static func list(using client: HTTPAPI, 13 | callback: @escaping ListRequestCallback) { 14 | let endpoint = TestAPIEndpoint(path: "dummy.listable.failure") 15 | self.list(using: client, endpoint: endpoint, callback: callback) 16 | } 17 | } 18 | 19 | struct PaginatedTestListable: Decodable, PaginatedListable { 20 | let dummy: String = "123" 21 | 22 | enum FilterableFields: String, RawEnumerable { 23 | case dummy 24 | } 25 | 26 | enum SortableFields: String, RawEnumerable { 27 | case dummy 28 | } 29 | 30 | static func list(using client: HTTPAPI, 31 | callback: @escaping PaginatedTestListable.PaginatedListRequestCallback) { 32 | let endpoint = TestAPIEndpoint(path: "dummy.listable.failure") 33 | self.list(using: client, endpoint: endpoint, callback: callback) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestObject.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestObject.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 11/10/2017. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import UIKit 11 | 12 | struct TestObject: APIParameters, Decodable { 13 | func encodedPayload() -> Data? { 14 | return try? JSONEncoder().encode(self) 15 | } 16 | 17 | var object: String = "" 18 | } 19 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestQRHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestQRHelper.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 7/2/2018. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct TestQRHelper { 12 | static func readQRCode(fromImage image: UIImage) -> String { 13 | let detector: CIDetector = CIDetector(ofType: CIDetectorTypeQRCode, 14 | context: nil, 15 | options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])! 16 | let features = detector.features(in: CIImage(image: image)!) 17 | var result: String = "" 18 | for feature in features as! [CIQRCodeFeature] { 19 | result += feature.messageString ?? "" 20 | } 21 | return result 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestSortable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestSortable.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 23/2/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import OmiseGO 10 | 11 | struct TestPaginatedListable: PaginatedListable { 12 | let aSortableAttribute: String 13 | let aNonSortableAttribute: String 14 | 15 | let aSearchableAttribute: String 16 | let aNonSearchableAttribute: String 17 | 18 | enum SortableFields: String, RawEnumerable { 19 | case aSortableAttribute = "a_sortable_attribute" 20 | } 21 | 22 | enum FilterableFields: String, RawEnumerable { 23 | case aFilterableAttribute = "a_searchable_attribute" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/Core/TestMocks/TestWebSocketDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestWebSocketDelegate.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 23/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | import Starscream 10 | import XCTest 11 | 12 | class TestWebSocketDelegate: WebSocketDelegate { 13 | var didConnect: Bool = false 14 | var didDisconnect: Bool = false 15 | var didReceiveText: String? 16 | var didReceiveData: Data? 17 | var didSendData: Data? 18 | 19 | let expectation: XCTestExpectation? 20 | 21 | init(expectation: XCTestExpectation? = nil) { 22 | self.expectation = expectation 23 | } 24 | 25 | func websocketDidConnect(socket _: WebSocketClient) { 26 | self.didConnect = true 27 | } 28 | 29 | func websocketDidDisconnect(socket _: WebSocketClient, error _: Error?) { 30 | self.didDisconnect = true 31 | } 32 | 33 | func websocketDidReceiveMessage(socket _: WebSocketClient, text: String) { 34 | self.didReceiveText = text 35 | self.expectation?.fulfill() 36 | } 37 | 38 | func websocketDidReceiveData(socket _: WebSocketClient, data: Data) { 39 | self.didReceiveData = data 40 | self.expectation?.fulfill() 41 | } 42 | 43 | func websocketDidSendData(socket _: WebSocketClient, data: Data) { 44 | self.didSendData = data 45 | self.expectation?.fulfill() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Tests/Core/ToolsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ToolsTests.swift 3 | // Tests 4 | // 5 | // Created by Mederic Petit on 7/3/18. 6 | // Copyright © 2017-2018 Omise Go Pte. Ltd. All rights reserved. 7 | // 8 | 9 | @testable import OmiseGO 10 | import XCTest 11 | 12 | class ToolsTests: XCTestCase { 13 | func testDateToString() { 14 | let date = Date(timeIntervalSince1970: 0) 15 | let defaultFormat = date.toString(timeZone: TimeZone(secondsFromGMT: 0)) 16 | XCTAssertEqual(defaultFormat, "1970-01-01T00:00:00Z") 17 | let customFormat = date.toString(withFormat: "yyyy MM dd HH:mm:ss", timeZone: TimeZone(secondsFromGMT: 0)) 18 | XCTAssertEqual(customFormat, "1970 01 01 00:00:00") 19 | } 20 | 21 | func testDecodingContainerProtocol() { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/secret.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | OMG_BASE_URL 6 | 7 | OMG_WEBSOCKET_URL 8 | 9 | OMG_API_KEY 10 | 11 | OMG_CLIENT_AUTHENTICATION_TOKEN 12 | 13 | OMG_TOKEN_ID 14 | 15 | 16 | 17 | --------------------------------------------------------------------------------