From b4e9c91eedc2b7bb82a24d72ccb68a0ae3a640b3 Mon Sep 17 00:00:00 2001 From: Russel Date: Fri, 22 Nov 2019 10:30:17 +0300 Subject: [PATCH 1/2] fix amount and promise bug Signed-off-by: Russel --- Example/IrohaExample/ViewController.swift | 4 +- Example/Podfile.lock | 6 +- .../Scenarious/IRCreateAssetTest.m | 5 +- IntegrationTests/Scenarious/IRGetAssetsTest.m | 131 +++++++++++++++++- IrohaCommunication.podspec | 2 +- .../Private/Commands/IRAddAssetQuantity.h | 2 +- .../Private/Commands/IRAddAssetQuantity.m | 2 +- .../Commands/IRSubtractAssetQuantity.h | 2 +- .../Commands/IRSubtractAssetQuantity.m | 2 +- .../Private/Commands/IRTransferAsset.h | 2 +- .../Private/Commands/IRTransferAsset.m | 2 +- .../Classes/Private/Models/IRCommand+Proto.m | 12 +- .../Public/Builder/IRTransactionBuilder.h | 6 +- .../Public/Builder/IRTransactionBuilder.m | 6 +- .../Extensions/NSDecimalNumber+IRAmount.h | 14 ++ .../Extensions/NSDecimalNumber+IRAmount.m | 21 +++ .../Classes/Public/Model/Common/IRAmount.h | 8 ++ .../Classes/Public/Model/Common/IRAmount.m | 43 ++++-- .../Classes/Public/Model/IRCommand.h | 6 +- .../Classes/Public/Promise/IRPromise.m | 41 ++++-- Tests/Model/IRAmountTests.m | 52 +++++++ Tests/Promise/IRPromiseTests.m | 66 ++++++++- Tests/Transaction/IRTransactionTests.m | 2 +- 23 files changed, 378 insertions(+), 59 deletions(-) create mode 100644 IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.h create mode 100644 IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.m diff --git a/Example/IrohaExample/ViewController.swift b/Example/IrohaExample/ViewController.swift index 314b85759..4706086fb 100755 --- a/Example/IrohaExample/ViewController.swift +++ b/Example/IrohaExample/ViewController.swift @@ -179,7 +179,7 @@ class ViewController: UIViewController { print("Creating new one and minting \(Constants.assetMintVolume)") do { - let mintAmount = try IRAmountFactory.amount(fromUnsignedInteger: Constants.assetMintVolume) + let mintAmount = try IRAmountFactory.transferAmount(fromUnsignedInteger: Constants.assetMintVolume) let transaction = try IRTransactionBuilder(creatorAccountId: self.adminAccountId) .createAsset(self.assetId, precision: 1) .addAssetQuantity(self.assetId, amount: mintAmount) @@ -206,7 +206,7 @@ class ViewController: UIViewController { private func transfer(to newAccountId: IRAccountId, amount: UInt, description: String) -> IRPromise { do { - let amountObject = try IRAmountFactory.amount(fromUnsignedInteger: amount) + let amountObject = try IRAmountFactory.transferAmount(fromUnsignedInteger: amount) let transaction = try IRTransactionBuilder(creatorAccountId: adminAccountId) .transferAsset(adminAccountId, destinationAccount: newAccountId, diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 856e25762..b9492043f 100755 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -24,7 +24,7 @@ PODS: - gRPC/Main (1.11.0): - gRPC-Core (= 1.11.0) - gRPC-RxLibrary (= 1.11.0) - - IrohaCommunication (3.4.0): + - IrohaCommunication (3.4.1): - BoringSSL (= 10.0.3) - gRPC-ProtoRPC (= 1.11.0) - IrohaCrypto @@ -62,11 +62,11 @@ SPEC CHECKSUMS: gRPC-Core: 164639cd8ae18ca8b65477fafb2efbaecf4f181a gRPC-ProtoRPC: bb5fddf3424aa4fad74d76736578a79fe40e244e gRPC-RxLibrary: 26d53d1b1f306befd4ad4e15bd6de27839a82481 - IrohaCommunication: 1519ba62909b1d8283244a6b9098b330bae2beab + IrohaCommunication: 988a6f7fe468a863486e183fb8da617519ccb94e IrohaCrypto: 4eb85b5edbf7667b5ffcef1b5104357f18ca8e81 nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3 Protobuf: 8a9838fba8dae3389230e1b7f8c104aa32389c03 PODFILE CHECKSUM: 29089a97c3781ec366ef8266addf4289525ff849 -COCOAPODS: 1.8.0 +COCOAPODS: 1.8.4 diff --git a/IntegrationTests/Scenarious/IRCreateAssetTest.m b/IntegrationTests/Scenarious/IRCreateAssetTest.m index e292b7ff9..947ecc657 100755 --- a/IntegrationTests/Scenarious/IRCreateAssetTest.m +++ b/IntegrationTests/Scenarious/IRCreateAssetTest.m @@ -12,7 +12,7 @@ @interface IRCreateAssetTest : IRBaseIrohaContainerTests @implementation IRCreateAssetTest -- (void)testCreateAddSubtractQueryAsset { +- (void)testCreateAddQueryAsset { NSError *error = nil; id assetId = [IRAssetIdFactory assetIdWithName:@"dummycoin" domain:self.domain @@ -32,7 +32,8 @@ - (void)testCreateAddSubtractQueryAsset { signatoryPublicKeys:@[self.adminPublicKey] error:&error]; - id addAmount = [IRAmountFactory amountFromUnsignedInteger:200 error:&error]; + id addAmount = [IRAmountFactory transferAmountFromUnsignedInteger:200 + error:&error]; if (error) { XCTFail(); diff --git a/IntegrationTests/Scenarious/IRGetAssetsTest.m b/IntegrationTests/Scenarious/IRGetAssetsTest.m index de8524da9..6692bf32f 100644 --- a/IntegrationTests/Scenarious/IRGetAssetsTest.m +++ b/IntegrationTests/Scenarious/IRGetAssetsTest.m @@ -34,7 +34,8 @@ - (void)testGetAssetsInSinglePage { signatoryPublicKeys:@[self.adminPublicKey] error:&error]; - id addAmount = [IRAmountFactory amountFromUnsignedInteger:200 error:&error]; + id addAmount = [IRAmountFactory transferAmountFromUnsignedInteger:200 + error:&error]; if (error) { XCTFail(); @@ -148,7 +149,8 @@ - (void)testGetAssetsInSeveralPages { signatoryPublicKeys:@[self.adminPublicKey] error:&error]; - id addAmount = [IRAmountFactory amountFromUnsignedInteger:200 error:&error]; + id addAmount = [IRAmountFactory transferAmountFromUnsignedInteger:200 + error:&error]; if (error) { XCTFail(); @@ -238,7 +240,7 @@ - (void)testGetAssetsInSeveralPages { id assetsResponse = result; id firstAsset = [assetsResponse.accountAssets firstObject]; - + XCTAssertEqual(assetsResponse.totalCount, 2); XCTAssertEqualObjects(assetsResponse.nextAssetId.identifier, secondAssetId.identifier); XCTAssertEqualObjects(firstAsset.assetId.identifier, firstAssetId.identifier); @@ -269,4 +271,127 @@ - (void)testGetAssetsInSeveralPages { [self waitForExpectations:@[expectation] timeout:120.0]; } +- (void)testCreateTransferThenFetchAssetWithZeroBalance { + NSError *error = nil; + id assetId = [IRAssetIdFactory assetIdWithName:@"dummycoin" + domain:self.domain + error:&error]; + + if (error) { + XCTFail(); + return; + } + + id newAccount = [IRAccountIdFactory accountIdWithName:@"new" + domain:self.domain + error:&error]; + + id newKeypair = [[[IREd25519KeyFactory alloc] init] createRandomKeypair]; + + if (error) { + XCTFail(); + return; + } + + UInt32 assetPrecision = 2; + IRTransactionBuilder *assetTransactionBuilder = [IRTransactionBuilder + builderWithCreatorAccountId:self.adminAccountId]; + assetTransactionBuilder = [assetTransactionBuilder createAsset:assetId precision:assetPrecision]; + + id assetTransaction = [[assetTransactionBuilder build:&error] + signedWithSignatories:@[self.adminSigner] + signatoryPublicKeys:@[self.adminPublicKey] + error:&error]; + + id addAmount = [IRAmountFactory transferAmountFromUnsignedInteger:200 + error:&error]; + + if (error) { + XCTFail(); + return; + } + + XCTestExpectation *expectation = [XCTestExpectation new]; + + [self.iroha executeTransaction:assetTransaction].onThen(^IRPromise * _Nullable (id result) { + return [IRRepeatableStatusStream onTransactionStatus:IRTransactionStatusCommitted + withHash:result + from:self.iroha]; + }).onThen(^IRPromise * _Nullable (id result) { + IRTransactionBuilder *transactionBuilder = [IRTransactionBuilder builderWithCreatorAccountId:self.adminAccountId]; + transactionBuilder = [transactionBuilder createAccount:newAccount + publicKey:newKeypair.publicKey]; + transactionBuilder = [transactionBuilder addAssetQuantity:assetId + amount:addAmount]; + transactionBuilder = [transactionBuilder transferAsset:self.adminAccountId + destinationAccount:newAccount + assetId:assetId + description:@"" + amount:addAmount]; + + NSError *error = nil; + id transaction = [[transactionBuilder build:&error] + signedWithSignatories:@[self.adminSigner] + signatoryPublicKeys:@[self.adminPublicKey] error:&error]; + + if (error) { + return [IRPromise promiseWithResult:error]; + } + + return [self.iroha executeTransaction:transaction]; + }).onThen(^IRPromise * _Nullable (id result) { + return [IRRepeatableStatusStream onTransactionStatus:IRTransactionStatusCommitted + withHash:result + from:self.iroha]; + }).onThen(^IRPromise * _Nullable (id result) { + IRQueryBuilder *queryBuilder = [IRQueryBuilder builderWithCreatorAccountId:self.adminAccountId]; + id pagination = [IRAssetPaginationFactory assetPagination:1 startingAssetId:assetId]; + queryBuilder = [queryBuilder getAccountAssets:self.adminAccountId pagination:pagination]; + + NSError *error = nil; + id request = [[queryBuilder build:&error] signedWithSignatory:self.adminSigner + signatoryPublicKey:self.adminPublicKey + error:&error]; + + if (error) { + return [IRPromise promiseWithResult:error]; + } + + return [self.iroha executeQueryRequest:request]; + }).onThen(^IRPromise * _Nullable (id result) { + NSLog(@"%@", result); + if ([result conformsToProtocol:@protocol(IRAccountAssetsResponse)]) { + id assetsResponse = result; + + id asset = [assetsResponse.accountAssets firstObject]; + + XCTAssertEqualObjects(asset.assetId.identifier, assetId.identifier); + XCTAssertEqual(asset.balance.value.intValue, 0); + + return [IRPromise promiseWithResult:nil]; + } else { + NSString *message = [NSString stringWithFormat:@"Invalid get assets response %@", NSStringFromClass([result class])]; + NSError *error = [NSError errorWithDomain:@"co.jp.getassetstest" + code:0 + userInfo:@{NSLocalizedDescriptionKey: message}]; + + return [IRPromise promiseWithResult:error]; + } + }).onThen(^IRPromise * _Nullable (id result) { + NSLog(@"%@", result); + + [expectation fulfill]; + + return nil; + }).onError(^IRPromise * _Nullable (NSError *error) { + XCTFail(); + NSLog(@"%@", error); + + [expectation fulfill]; + return nil; + }); + + [self waitForExpectations:@[expectation] timeout:120.0];; +} + @end diff --git a/IrohaCommunication.podspec b/IrohaCommunication.podspec index 106fd5d3b..4ddd89593 100755 --- a/IrohaCommunication.podspec +++ b/IrohaCommunication.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'IrohaCommunication' - s.version = '3.4.1' + s.version = '3.5.0' s.summary = 'Helper classes to use for communication with Iroha blockchain.' s.homepage = 'https://github.com/hyperledger/iroha-ios' diff --git a/IrohaCommunication/Classes/Private/Commands/IRAddAssetQuantity.h b/IrohaCommunication/Classes/Private/Commands/IRAddAssetQuantity.h index be767caa8..8e9e8901d 100755 --- a/IrohaCommunication/Classes/Private/Commands/IRAddAssetQuantity.h +++ b/IrohaCommunication/Classes/Private/Commands/IRAddAssetQuantity.h @@ -10,6 +10,6 @@ @interface IRAddAssetQuantity : NSObject - (nonnull instancetype)initWithAssetId:(nonnull id)assetId - amount:(nonnull id)amount; + amount:(nonnull id)amount; @end diff --git a/IrohaCommunication/Classes/Private/Commands/IRAddAssetQuantity.m b/IrohaCommunication/Classes/Private/Commands/IRAddAssetQuantity.m index c8230b417..499dd7252 100755 --- a/IrohaCommunication/Classes/Private/Commands/IRAddAssetQuantity.m +++ b/IrohaCommunication/Classes/Private/Commands/IRAddAssetQuantity.m @@ -11,7 +11,7 @@ @implementation IRAddAssetQuantity @synthesize amount = _amount; - (nonnull instancetype)initWithAssetId:(nonnull id)assetId - amount:(nonnull id)amount { + amount:(nonnull id)amount { if (self = [super init]) { _assetId = assetId; _amount = amount; diff --git a/IrohaCommunication/Classes/Private/Commands/IRSubtractAssetQuantity.h b/IrohaCommunication/Classes/Private/Commands/IRSubtractAssetQuantity.h index 33d23aae2..574560cbf 100755 --- a/IrohaCommunication/Classes/Private/Commands/IRSubtractAssetQuantity.h +++ b/IrohaCommunication/Classes/Private/Commands/IRSubtractAssetQuantity.h @@ -10,6 +10,6 @@ @interface IRSubtractAssetQuantity : NSObject - (nonnull instancetype)initWithAssetId:(nonnull id)assetId - amount:(nonnull id)amount; + amount:(nonnull id)amount; @end diff --git a/IrohaCommunication/Classes/Private/Commands/IRSubtractAssetQuantity.m b/IrohaCommunication/Classes/Private/Commands/IRSubtractAssetQuantity.m index 9ad07e3d1..71e54fbae 100755 --- a/IrohaCommunication/Classes/Private/Commands/IRSubtractAssetQuantity.m +++ b/IrohaCommunication/Classes/Private/Commands/IRSubtractAssetQuantity.m @@ -11,7 +11,7 @@ @implementation IRSubtractAssetQuantity @synthesize amount = _amount; - (nonnull instancetype)initWithAssetId:(nonnull id)assetId - amount:(nonnull id)amount { + amount:(nonnull id)amount { if (self = [super init]) { _assetId = assetId; diff --git a/IrohaCommunication/Classes/Private/Commands/IRTransferAsset.h b/IrohaCommunication/Classes/Private/Commands/IRTransferAsset.h index f3ddb0ded..aed68a6a2 100755 --- a/IrohaCommunication/Classes/Private/Commands/IRTransferAsset.h +++ b/IrohaCommunication/Classes/Private/Commands/IRTransferAsset.h @@ -13,6 +13,6 @@ destinationAccountId:(nonnull id)destinationAccountId assetId:(nonnull id)assetId transferDescription:(nonnull NSString *)transferDescription - amount:(nonnull id)amount; + amount:(nonnull id)amount; @end diff --git a/IrohaCommunication/Classes/Private/Commands/IRTransferAsset.m b/IrohaCommunication/Classes/Private/Commands/IRTransferAsset.m index d7acaeb87..c10e5ca72 100755 --- a/IrohaCommunication/Classes/Private/Commands/IRTransferAsset.m +++ b/IrohaCommunication/Classes/Private/Commands/IRTransferAsset.m @@ -17,7 +17,7 @@ - (nonnull instancetype)initWithSourceAccountId:(nonnull id)sourceA destinationAccountId:(nonnull id)destinationAccountId assetId:(nonnull id)assetId transferDescription:(nonnull NSString *)transferDescription - amount:(nonnull id)amount { + amount:(nonnull id)amount { if (self = [super init]) { _sourceAccountId = sourceAccountId; diff --git a/IrohaCommunication/Classes/Private/Models/IRCommand+Proto.m b/IrohaCommunication/Classes/Private/Models/IRCommand+Proto.m index f28c94516..e84771dab 100755 --- a/IrohaCommunication/Classes/Private/Models/IRCommand+Proto.m +++ b/IrohaCommunication/Classes/Private/Models/IRCommand+Proto.m @@ -330,8 +330,8 @@ @implementation IRCommandProtoFactory NSString *transferDescription = pbCommand.description_p ? pbCommand.description_p : @""; - id amount = [IRAmountFactory amountFromString:pbCommand.amount - error:error]; + id amount = [IRAmountFactory transferAmountFromString:pbCommand.amount + error:error]; if (!amount) { return nil; @@ -407,8 +407,8 @@ @implementation IRCommandProtoFactory return nil; } - id amount = [IRAmountFactory amountFromString:pbCommand.amount - error:error]; + id amount = [IRAmountFactory transferAmountFromString:pbCommand.amount + error:error]; if (!amount) { return nil; @@ -475,8 +475,8 @@ @implementation IRCommandProtoFactory return nil; } - id amount = [IRAmountFactory amountFromString:pbCommand.amount - error:error]; + id amount = [IRAmountFactory transferAmountFromString:pbCommand.amount + error:error]; if (!amount) { return nil; diff --git a/IrohaCommunication/Classes/Public/Builder/IRTransactionBuilder.h b/IrohaCommunication/Classes/Public/Builder/IRTransactionBuilder.h index 8e0b24843..2545ec414 100755 --- a/IrohaCommunication/Classes/Public/Builder/IRTransactionBuilder.h +++ b/IrohaCommunication/Classes/Public/Builder/IRTransactionBuilder.h @@ -28,10 +28,10 @@ typedef NS_ENUM(NSUInteger, IRTransactionBuilderError) { + (nonnull instancetype)builderWithCreatorAccountId:(nonnull id)creator; - (nonnull instancetype)addAssetQuantity:(nonnull id)assetId - amount:(nonnull id)amount; + amount:(nonnull id)amount; - (nonnull instancetype)subtractAssetQuantity:(nonnull id)assetId - amount:(nonnull id)amount; + amount:(nonnull id)amount; - (nonnull instancetype)addPeer:(nonnull id)address publicKey:(nonnull id)publicKey; @@ -77,7 +77,7 @@ typedef NS_ENUM(NSUInteger, IRTransactionBuilderError) { destinationAccount:(nonnull id)destinationAccountId assetId:(nonnull id)assetId description:(nonnull NSString *)transferDescription - amount:(nonnull id)amount; + amount:(nonnull id)amount; - (nonnull instancetype)removePeer:(nonnull id)peerKey; diff --git a/IrohaCommunication/Classes/Public/Builder/IRTransactionBuilder.m b/IrohaCommunication/Classes/Public/Builder/IRTransactionBuilder.m index 19f137e03..2feade033 100755 --- a/IrohaCommunication/Classes/Public/Builder/IRTransactionBuilder.m +++ b/IrohaCommunication/Classes/Public/Builder/IRTransactionBuilder.m @@ -42,7 +42,7 @@ + (nonnull instancetype)builderWithCreatorAccountId:(nonnull id)cre } - (nonnull instancetype)addAssetQuantity:(nonnull id)assetId - amount:(nonnull id)amount { + amount:(nonnull id)amount { IRAddAssetQuantity *command = [[IRAddAssetQuantity alloc] initWithAssetId:assetId amount:amount]; @@ -53,7 +53,7 @@ - (nonnull instancetype)addAssetQuantity:(nonnull id)assetId } - (nonnull instancetype)subtractAssetQuantity:(nonnull id)assetId - amount:(nonnull id)amount { + amount:(nonnull id)amount { IRSubtractAssetQuantity *command = [[IRSubtractAssetQuantity alloc] initWithAssetId:assetId amount:amount]; @@ -212,7 +212,7 @@ - (nonnull instancetype)transferAsset:(nonnull id)sourceAccountId destinationAccount:(nonnull id)destinationAccountId assetId:(nonnull id)assetId description:(nonnull NSString *)transferDescription - amount:(nonnull id)amount { + amount:(nonnull id)amount { IRTransferAsset *command = [[IRTransferAsset alloc] initWithSourceAccountId:sourceAccountId destinationAccountId:destinationAccountId diff --git a/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.h b/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.h new file mode 100644 index 000000000..062a51df2 --- /dev/null +++ b/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.h @@ -0,0 +1,14 @@ +/** + * Copyright Soramitsu Co., Ltd. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#import +#import "IRAmount.h" + +@interface NSDecimalNumber (IRAmount) + ++ (nullable NSDecimalNumber*)decimalNumberWithAmountValue:(nonnull NSString*)value; ++ (nullable NSDecimalNumber*)decimalNumberWithAmount:(nonnull id)amount; + +@end diff --git a/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.m b/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.m new file mode 100644 index 000000000..29cba2da9 --- /dev/null +++ b/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.m @@ -0,0 +1,21 @@ +/** +* Copyright Soramitsu Co., Ltd. All Rights Reserved. +* SPDX-License-Identifier: Apache-2.0 +*/ + +#import "NSDecimalNumber+IRAmount.h" + +static NSString * const DECIMAL_SEPARATOR = @"."; + +@implementation NSDecimalNumber (IRAmount) + ++ (nullable NSDecimalNumber*)decimalNumberWithAmountValue:(nonnull NSString*)value { + return [NSDecimalNumber decimalNumberWithString:value + locale:@{NSLocaleDecimalSeparator: DECIMAL_SEPARATOR}]; +} + ++ (nullable NSDecimalNumber*)decimalNumberWithAmount:(id)amount { + return [NSDecimalNumber decimalNumberWithAmountValue:amount.value]; +} + +@end diff --git a/IrohaCommunication/Classes/Public/Model/Common/IRAmount.h b/IrohaCommunication/Classes/Public/Model/Common/IRAmount.h index d498e8d2c..6384fd7c2 100755 --- a/IrohaCommunication/Classes/Public/Model/Common/IRAmount.h +++ b/IrohaCommunication/Classes/Public/Model/Common/IRAmount.h @@ -11,6 +11,10 @@ @end +@protocol IRTransferAmount + +@end + typedef NS_ENUM(NSUInteger, IRAmountError) { IRInvalidAmountValue }; @@ -19,6 +23,10 @@ typedef NS_ENUM(NSUInteger, IRAmountError) { + (nullable id)amountFromString:(nonnull NSString *)amount error:(NSError *_Nullable*_Nullable)error; + (nullable id)amountFromUnsignedInteger:(NSUInteger)amount error:(NSError *_Nullable*_Nullable)error; ++ (nullable id)transferAmountFromString:(nonnull NSString *)amount + error:(NSError *_Nullable*_Nullable)error; ++ (nullable id)transferAmountFromUnsignedInteger:(NSUInteger)amount + error:(NSError *_Nullable*_Nullable)error; @end diff --git a/IrohaCommunication/Classes/Public/Model/Common/IRAmount.m b/IrohaCommunication/Classes/Public/Model/Common/IRAmount.m index caec5ba66..6a6197b8b 100755 --- a/IrohaCommunication/Classes/Public/Model/Common/IRAmount.m +++ b/IrohaCommunication/Classes/Public/Model/Common/IRAmount.m @@ -4,12 +4,9 @@ */ #import "IRAmount.h" +#import "NSDecimalNumber+IRAmount.h" - -static NSString * const DECIMAL_SEPARATOR = @"."; - - -@interface IRAmount : NSObject +@interface IRAmount : NSObject - (instancetype)initWithString:(nonnull NSString *)amountString; @@ -37,7 +34,7 @@ - (NSString *)description { @implementation IRAmountFactory -+ (nullable id)amountFromString:(nonnull NSString *)amount error:(NSError *_Nullable*_Nullable)error { ++ (nullable IRAmount*)concreteFromString:(nonnull NSString *)amount error:(NSError *_Nullable*_Nullable)error { NSCharacterSet *invalidSymbols = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]; if ([amount rangeOfCharacterFromSet:invalidSymbols].location != NSNotFound) { @@ -50,12 +47,11 @@ @implementation IRAmountFactory return nil; } - NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:amount - locale:@{NSLocaleDecimalSeparator: DECIMAL_SEPARATOR}]; + NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithAmountValue:amount]; - if (!decimalNumber || [decimalNumber isEqualToNumber:[NSDecimalNumber notANumber]] || [decimalNumber doubleValue] <= 0.0) { + if (!decimalNumber || [decimalNumber isEqualToNumber:[NSDecimalNumber notANumber]]) { if (error) { - NSString *message = @"Amount must be positive"; + NSString *message = @"Invalid amount value"; *error = [NSError errorWithDomain:NSStringFromClass([IRAmountFactory class]) code:IRInvalidAmountValue userInfo:@{NSLocalizedDescriptionKey: message}]; @@ -66,8 +62,35 @@ @implementation IRAmountFactory return [[IRAmount alloc] initWithString:[decimalNumber stringValue]]; } ++ (nullable id)amountFromString:(nonnull NSString *)amount error:(NSError *_Nullable*_Nullable)error { + return [self concreteFromString:amount error:error]; +} + + (nullable id)amountFromUnsignedInteger:(NSUInteger)amount error:(NSError *_Nullable*_Nullable)error { return [self amountFromString:[@(amount) stringValue] error:error]; } ++ (nullable id)transferAmountFromString:(nonnull NSString *)amount + error:(NSError *_Nullable*_Nullable)error { + IRAmount *irAmount = [self concreteFromString:amount error:error]; + + NSComparisonResult result = [[NSDecimalNumber decimalNumberWithAmount:irAmount] compare:NSDecimalNumber.zero]; + if (result == NSOrderedDescending) { + return irAmount; + } else { + if (error) { + NSString *message = @"Amount value must be positive"; + *error = [NSError errorWithDomain:NSStringFromClass([IRAmountFactory class]) + code:IRInvalidAmountValue + userInfo:@{NSLocalizedDescriptionKey: message}]; + } + return nil; + } +} + ++ (nullable id)transferAmountFromUnsignedInteger:(NSUInteger)amount + error:(NSError *_Nullable*_Nullable)error { + return [self transferAmountFromString:[@(amount) stringValue] error:error]; +} + @end diff --git a/IrohaCommunication/Classes/Public/Model/IRCommand.h b/IrohaCommunication/Classes/Public/Model/IRCommand.h index 4ef7a7563..fb35976ab 100755 --- a/IrohaCommunication/Classes/Public/Model/IRCommand.h +++ b/IrohaCommunication/Classes/Public/Model/IRCommand.h @@ -24,7 +24,7 @@ @protocol IRAddAssetQuantity @property (nonatomic, readonly) id _Nonnull assetId; -@property (nonatomic, readonly) id _Nonnull amount; +@property (nonatomic, readonly) id _Nonnull amount; @end @@ -137,7 +137,7 @@ @protocol IRSubtractAssetQuantity @property (nonatomic, readonly) id _Nonnull assetId; -@property (nonatomic, readonly) id _Nonnull amount; +@property (nonatomic, readonly) id _Nonnull amount; @end @@ -148,7 +148,7 @@ @property (nonatomic, readonly) id _Nonnull destinationAccountId; @property (nonatomic, readonly) id _Nonnull assetId; @property (nonatomic, readonly) NSString * _Nonnull transferDescription; -@property (nonatomic, readonly) id _Nonnull amount; +@property (nonatomic, readonly) id _Nonnull amount; @end diff --git a/IrohaCommunication/Classes/Public/Promise/IRPromise.m b/IrohaCommunication/Classes/Public/Promise/IRPromise.m index 455909da9..faa9b6f10 100755 --- a/IrohaCommunication/Classes/Public/Promise/IRPromise.m +++ b/IrohaCommunication/Classes/Public/Promise/IRPromise.m @@ -44,42 +44,53 @@ + (nonnull instancetype)promiseWithResult:(nullable id)result { - (IRPromise* _Nonnull (^)(IRPromiseResultHandler _Nonnull))onThen { return ^(IRPromiseResultHandler block) { - IRPromise* promise = [[IRPromise alloc] init]; + IRPromise *promise = nil; dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); - self.resultHandler = block; - self.errorHandler = nil; + if (self.isFulfilled) { + if (![self.result isKindOfClass:[NSError class]]) { + promise = block(self.result); + } else { + promise = [[IRPromise alloc] init]; + [promise fulfillWithResult:self.result]; + } + } else { + promise = [[IRPromise alloc] init]; - self.next = promise; + self.resultHandler = block; + self.errorHandler = nil; - if (self.isFulfilled) { - [self triggerResultProcessing]; + self.next = promise; } dispatch_semaphore_signal(self.semaphore); - return promise; + return promise != nil ? promise : [IRPromise promise]; }; } - (IRPromise* _Nonnull (^)(IRPromiseErrorHandler _Nonnull))onError { return ^(IRPromiseErrorHandler block) { - IRPromise* promise = [[IRPromise alloc] init]; + IRPromise* promise = nil; dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); - self.resultHandler = nil; - self.errorHandler = block; - self.next = promise; - if (self.isFulfilled) { - [self triggerResultProcessing]; + if ([self.result isKindOfClass:[NSError class]]) { + promise = block(self.result); + } + } else { + promise = [[IRPromise alloc] init]; + + self.resultHandler = nil; + self.errorHandler = block; + self.next = promise; } dispatch_semaphore_signal(self.semaphore); - return promise; + return promise != nil ? promise : [IRPromise promise]; }; } @@ -134,7 +145,7 @@ - (void)triggerResultProcessing { [resultPromise copyHandlersFromPromise:_next]; if (resultPromise.isFulfilled) { - [self triggerResultProcessing]; + [resultPromise triggerResultProcessing]; } } else if(_next) { diff --git a/Tests/Model/IRAmountTests.m b/Tests/Model/IRAmountTests.m index fb9a33b76..c17aa2721 100755 --- a/Tests/Model/IRAmountTests.m +++ b/Tests/Model/IRAmountTests.m @@ -22,6 +22,16 @@ @"89a789" }; +static const NSUInteger INVALID_STRING_TRANSFER_AMOUNT_COUNT = 6; +static NSString * const INVALID_STRING_TRANSFER_AMOUNT[] = { + @"", + @"0", + @"0.0", + @"-10.21", + @"1,0789", + @"89a789" +}; + @interface IRAmountTests : XCTestCase @end @@ -70,4 +80,46 @@ - (void)testValidIntAmount { } } +- (void)testValidStringTransferAmount { + for (NSUInteger i = 0; i < VALID_STRING_AMOUNT_COUNT; i++) { + id amount = [IRAmountFactory transferAmountFromString:VALID_STRING_AMOUNT[i] + error:nil]; + + XCTAssertNotNil(amount); + XCTAssertEqualObjects(amount.value, VALID_STRING_AMOUNT[i]); + } +} + +- (void)testValidIntTransferAmount { + for (NSUInteger i = 1e3; i < 1e5; i += 1e4) { + NSError *error = nil; + id amount = [IRAmountFactory transferAmountFromUnsignedInteger:i + error:&error]; + + XCTAssertNotNil(amount); + XCTAssertNil(error); + } +} + +- (void)testInvalidStringTransferAmountWithError { + for (NSUInteger i = 0; i < INVALID_STRING_TRANSFER_AMOUNT_COUNT; i++) { + NSError *error = nil; + id amount = [IRAmountFactory transferAmountFromString:INVALID_STRING_TRANSFER_AMOUNT[i] + error:&error]; + + XCTAssertNil(amount); + XCTAssertNotNil(error); + XCTAssertEqual(error.code, IRInvalidAmountValue); + } +} + +- (void)testInvalidStringTransferAmountWithoutError { + for (NSUInteger i = 0; i < INVALID_STRING_TRANSFER_AMOUNT_COUNT; i++) { + id amount = [IRAmountFactory transferAmountFromString:INVALID_STRING_TRANSFER_AMOUNT[i] + error:nil]; + + XCTAssertNil(amount); + } +} + @end diff --git a/Tests/Promise/IRPromiseTests.m b/Tests/Promise/IRPromiseTests.m index 49579eae3..faa5195e5 100755 --- a/Tests/Promise/IRPromiseTests.m +++ b/Tests/Promise/IRPromiseTests.m @@ -104,7 +104,7 @@ - (void)testWithErrorFullfiled { [self waitForExpectations:@[expectation] timeout:10]; } -- (void)testFirstFullWithError { +- (void)testFirstFullfillWithError { XCTestExpectation *expectation = [[XCTestExpectation alloc] init]; NSError *error = [NSError errorWithDomain:@"Test domain" @@ -128,4 +128,68 @@ - (void)testFirstFullWithError { [self waitForExpectations:@[expectation] timeout:10.0]; } +- (void)testHandleImmediateResultReturnedFromError { + XCTestExpectation *expectation = [[XCTestExpectation alloc] init]; + + NSError *error = [NSError errorWithDomain:@"Test domain" + code:0 + userInfo:nil]; + + NSString *initialResult = @"Initial result"; + NSString *expectedResult = @"Expected result"; + + [IRPromise promiseWithResult:initialResult].onThen(^IRPromise*(id result){ + return [IRPromise promiseWithResult:error]; + }).onThen(^IRPromise*(id result) { + XCTFail(); + + return nil; + }).onError(^IRPromise*(NSError *error) { + return [IRPromise promiseWithResult:expectedResult]; + }).onThen(^IRPromise*(id result) { + XCTAssertEqualObjects(result, expectedResult); + + [expectation fulfill]; + + return nil; + }); + + [self waitForExpectations:@[expectation] timeout:10.0]; +} + +- (void)testHandleAsyncResultReturnedFromErrorAndThenReturnError { + XCTestExpectation *expectation = [[XCTestExpectation alloc] init]; + + NSError *error = [NSError errorWithDomain:@"Test domain" + code:0 + userInfo:nil]; + + NSString *initialResult = @"Initial result"; + NSString *expectedResult = @"Expected result"; + + IRPromise *asyncPromise = [IRPromise promise]; + + asyncPromise.onThen(^IRPromise*(id result){ + return [IRPromise promiseWithResult:error]; + }).onThen(^IRPromise*(id result) { + XCTFail(); + + return nil; + }).onError(^IRPromise*(NSError *error) { + return [IRPromise promiseWithResult:expectedResult]; + }).onThen(^IRPromise*(id result) { + XCTAssertEqualObjects(result, expectedResult); + + [expectation fulfill]; + + return nil; + }); + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [asyncPromise fulfillWithResult:initialResult]; + }); + + [self waitForExpectations:@[expectation] timeout:10.0]; +} + @end diff --git a/Tests/Transaction/IRTransactionTests.m b/Tests/Transaction/IRTransactionTests.m index 02f571554..be782e009 100755 --- a/Tests/Transaction/IRTransactionTests.m +++ b/Tests/Transaction/IRTransactionTests.m @@ -179,7 +179,7 @@ - (void)testBatchInitialization { port:VALID_PORT error:nil]; - id amount = [IRAmountFactory amountFromUnsignedInteger:100 error:nil]; + id amount = [IRAmountFactory transferAmountFromUnsignedInteger:100 error:nil]; id roleName = [IRRoleNameFactory roleWithName:VALID_ROLE error:nil]; From 39625caae2cf79df176761cfae0ce7303e6ac9b7 Mon Sep 17 00:00:00 2001 From: Russel Date: Fri, 22 Nov 2019 11:31:15 +0300 Subject: [PATCH 2/2] refactor code style Signed-off-by: Russel --- .../Classes/Public/Extensions/NSDecimalNumber+IRAmount.h | 4 ++-- .../Classes/Public/Extensions/NSDecimalNumber+IRAmount.m | 4 ++-- IrohaCommunication/Classes/Public/Model/Common/IRAmount.m | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.h b/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.h index 062a51df2..741725998 100644 --- a/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.h +++ b/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.h @@ -8,7 +8,7 @@ @interface NSDecimalNumber (IRAmount) -+ (nullable NSDecimalNumber*)decimalNumberWithAmountValue:(nonnull NSString*)value; -+ (nullable NSDecimalNumber*)decimalNumberWithAmount:(nonnull id)amount; ++ (nullable NSDecimalNumber *)decimalNumberWithAmountValue:(nonnull NSString *)value; ++ (nullable NSDecimalNumber *)decimalNumberWithAmount:(nonnull id)amount; @end diff --git a/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.m b/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.m index 29cba2da9..133adf378 100644 --- a/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.m +++ b/IrohaCommunication/Classes/Public/Extensions/NSDecimalNumber+IRAmount.m @@ -9,12 +9,12 @@ @implementation NSDecimalNumber (IRAmount) -+ (nullable NSDecimalNumber*)decimalNumberWithAmountValue:(nonnull NSString*)value { ++ (nullable NSDecimalNumber *)decimalNumberWithAmountValue:(nonnull NSString *)value { return [NSDecimalNumber decimalNumberWithString:value locale:@{NSLocaleDecimalSeparator: DECIMAL_SEPARATOR}]; } -+ (nullable NSDecimalNumber*)decimalNumberWithAmount:(id)amount { ++ (nullable NSDecimalNumber *)decimalNumberWithAmount:(id)amount { return [NSDecimalNumber decimalNumberWithAmountValue:amount.value]; } diff --git a/IrohaCommunication/Classes/Public/Model/Common/IRAmount.m b/IrohaCommunication/Classes/Public/Model/Common/IRAmount.m index 6a6197b8b..a716d8079 100755 --- a/IrohaCommunication/Classes/Public/Model/Common/IRAmount.m +++ b/IrohaCommunication/Classes/Public/Model/Common/IRAmount.m @@ -34,7 +34,8 @@ - (NSString *)description { @implementation IRAmountFactory -+ (nullable IRAmount*)concreteFromString:(nonnull NSString *)amount error:(NSError *_Nullable*_Nullable)error { ++ (nullable IRAmount *)concreteAmountFromString:(nonnull NSString *)amount + error:(NSError *_Nullable*_Nullable)error { NSCharacterSet *invalidSymbols = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]; if ([amount rangeOfCharacterFromSet:invalidSymbols].location != NSNotFound) { @@ -63,7 +64,7 @@ + (nullable IRAmount*)concreteFromString:(nonnull NSString *)amount error:(NSErr } + (nullable id)amountFromString:(nonnull NSString *)amount error:(NSError *_Nullable*_Nullable)error { - return [self concreteFromString:amount error:error]; + return [self concreteAmountFromString:amount error:error]; } + (nullable id)amountFromUnsignedInteger:(NSUInteger)amount error:(NSError *_Nullable*_Nullable)error { @@ -72,7 +73,7 @@ + (nullable IRAmount*)concreteFromString:(nonnull NSString *)amount error:(NSErr + (nullable id)transferAmountFromString:(nonnull NSString *)amount error:(NSError *_Nullable*_Nullable)error { - IRAmount *irAmount = [self concreteFromString:amount error:error]; + IRAmount *irAmount = [self concreteAmountFromString:amount error:error]; NSComparisonResult result = [[NSDecimalNumber decimalNumberWithAmount:irAmount] compare:NSDecimalNumber.zero]; if (result == NSOrderedDescending) {