diff --git a/BVSDK.podspec b/BVSDK.podspec index 7de916fa..cb0ac607 100644 --- a/BVSDK.podspec +++ b/BVSDK.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |s| s.name = "BVSDK" - s.version = '8.13.2' + s.version = '8.13.3' s.homepage = 'https://developer.bazaarvoice.com/' s.license = { :type => 'Commercial', :text => 'See https://developer.bazaarvoice.com/API_Terms_of_Use' } s.author = { 'Bazaarvoice' => 'support@bazaarvoice.com' } diff --git a/BVSDK.xcodeproj/project.pbxproj b/BVSDK.xcodeproj/project.pbxproj index ab0faa5c..7473fb13 100644 --- a/BVSDK.xcodeproj/project.pbxproj +++ b/BVSDK.xcodeproj/project.pbxproj @@ -704,6 +704,8 @@ B78683D02D096C1900BBCE3F /* BVSummarisedFeaturesQueryTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B78683CF2D096C1900BBCE3F /* BVSummarisedFeaturesQueryTest.swift */; }; B78683D32D096FD900BBCE3F /* BVProductSentimentsErrorResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = B78683D22D096FD900BBCE3F /* BVProductSentimentsErrorResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; B78683D52D096FEE00BBCE3F /* BVProductSentimentsErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = B78683D42D096FEE00BBCE3F /* BVProductSentimentsErrorResponse.m */; }; + B78F94682D548EA500D9ECC4 /* BVProductSentimentsError.m in Sources */ = {isa = PBXBuildFile; fileRef = B78F94672D548EA500D9ECC4 /* BVProductSentimentsError.m */; }; + B78F94692D548EA900D9ECC4 /* BVProductSentimentsError.h in Headers */ = {isa = PBXBuildFile; fileRef = B78F94662D548E9600D9ECC4 /* BVProductSentimentsError.h */; }; B7B3B95C2BAAB48D00A2831B /* BVSubmittedVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = B7B3B95B2BAAB48D00A2831B /* BVSubmittedVideo.m */; }; B7B3B95E2BAAB4B500A2831B /* BVVideoSubmission.h in Headers */ = {isa = PBXBuildFile; fileRef = B7E7C6A72BA2D70F006632CF /* BVVideoSubmission.h */; settings = {ATTRIBUTES = (Public, ); }; }; B7B3B95F2BAAB4B700A2831B /* BVSubmittedVideo.h in Headers */ = {isa = PBXBuildFile; fileRef = B7B3B95D2BAAB49F00A2831B /* BVSubmittedVideo.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1450,6 +1452,8 @@ B78683CF2D096C1900BBCE3F /* BVSummarisedFeaturesQueryTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BVSummarisedFeaturesQueryTest.swift; sourceTree = ""; }; B78683D22D096FD900BBCE3F /* BVProductSentimentsErrorResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVProductSentimentsErrorResponse.h; sourceTree = ""; }; B78683D42D096FEE00BBCE3F /* BVProductSentimentsErrorResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVProductSentimentsErrorResponse.m; sourceTree = ""; }; + B78F94662D548E9600D9ECC4 /* BVProductSentimentsError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVProductSentimentsError.h; sourceTree = ""; }; + B78F94672D548EA500D9ECC4 /* BVProductSentimentsError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVProductSentimentsError.m; sourceTree = ""; }; B7B3B95B2BAAB48D00A2831B /* BVSubmittedVideo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVSubmittedVideo.m; sourceTree = ""; }; B7B3B95D2BAAB49F00A2831B /* BVSubmittedVideo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BVSubmittedVideo.h; sourceTree = ""; }; B7B3B9602BAAB62100A2831B /* BVVideoSubmissionResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BVVideoSubmissionResponse.m; sourceTree = ""; }; @@ -2935,6 +2939,8 @@ B78683B92CEDE78D00BBCE3F /* NSError+BVProductSentimentsErrorCodeParser.m */, B78683D22D096FD900BBCE3F /* BVProductSentimentsErrorResponse.h */, B78683D42D096FEE00BBCE3F /* BVProductSentimentsErrorResponse.m */, + B78F94662D548E9600D9ECC4 /* BVProductSentimentsError.h */, + B78F94672D548EA500D9ECC4 /* BVProductSentimentsError.m */, ); path = Errors; sourceTree = ""; @@ -3017,8 +3023,8 @@ B7C833522D2E79D30088B7C0 /* BVProductExpressionsResponse.m */, ); path = ProductExpressions; - sourceTree = ""; - }; + sourceTree = ""; + }; B7C8335C2D2FA9020088B7C0 /* ReviewSummarisation */ = { isa = PBXGroup; children = ( @@ -3122,6 +3128,7 @@ 87F2DD411DAD585E00FB43F3 /* BVRecommendedProduct.h in Headers */, B58639BB214AFE0A00EFD763 /* BVSDKConfiguration.h in Headers */, 87F2DD051DAD585E00FB43F3 /* BVQuestionsCollectionView.h in Headers */, + B78F94692D548EA900D9ECC4 /* BVProductSentimentsError.h in Headers */, 87F2DC1E1DAD585E00FB43F3 /* BVPixel.h in Headers */, 87F2DC991DAD585E00FB43F3 /* BVReview.h in Headers */, 87F2DCCF1DAD585E00FB43F3 /* BVAnswerSubmissionResponse.h in Headers */, @@ -3783,6 +3790,7 @@ B575C3871FBDFD6F000F890B /* BVUASSubmission.m in Sources */, 87E810E61ECCA0190032C753 /* BVCommentsSortOption.m in Sources */, 875411761E1F201E006C5C6E /* BVNotificationsAnalyticsHelper.m in Sources */, + B78F94682D548EA500D9ECC4 /* BVProductSentimentsError.m in Sources */, 87D425281E8EE39700147FDB /* BVViewedCGCEvent.m in Sources */, 87F2DD061DAD585E00FB43F3 /* BVQuestionsCollectionView.m in Sources */, 87F2DCE21DAD585E00FB43F3 /* BVPhotoSubmission.m in Sources */, diff --git a/BVSDK/BVAnalytics/BVPixelEvents/BVPixelTypes.h b/BVSDK/BVAnalytics/BVPixelEvents/BVPixelTypes.h index f7c54c45..865ffd49 100644 --- a/BVSDK/BVAnalytics/BVPixelEvents/BVPixelTypes.h +++ b/BVSDK/BVAnalytics/BVPixelEvents/BVPixelTypes.h @@ -61,7 +61,8 @@ typedef NS_ENUM(NSInteger, BVPixelProductType) { BVPixelProductTypeProductRecommendations, BVPixelProductTypePIN, BVPixelProductTypeLocation, - BVPixelProductTypeProgressiveSubmission + BVPixelProductTypeProgressiveSubmission, + BVPixelProductTypeProductSentiments }; @interface BVPixelProductTypeUtil : NSObject diff --git a/BVSDK/BVAnalytics/BVPixelEvents/BVPixelTypes.m b/BVSDK/BVAnalytics/BVPixelEvents/BVPixelTypes.m index 9376f1be..d9a2db66 100644 --- a/BVSDK/BVAnalytics/BVPixelEvents/BVPixelTypes.m +++ b/BVSDK/BVAnalytics/BVPixelEvents/BVPixelTypes.m @@ -94,6 +94,8 @@ + (NSString *)toString:(BVPixelProductType)productType { return @"Curations"; case BVPixelProductTypeProgressiveSubmission: return @"ProgressiveSubmission"; + case BVPixelProductTypeProductSentiments: + return @"ProductSentiments"; default: return @"UnknownProduct"; } diff --git a/BVSDK/BVCommon/BVSDKConstants.h b/BVSDK/BVCommon/BVSDKConstants.h index 56d918a8..2a78d5b1 100644 --- a/BVSDK/BVCommon/BVSDKConstants.h +++ b/BVSDK/BVCommon/BVSDKConstants.h @@ -10,7 +10,7 @@ #define BVSDKConstants_h /// Provides the master version of the SDK. -#define BV_SDK_VERSION @"8.13.2" +#define BV_SDK_VERSION @"8.13.3" /// Conversation SDK Version #define SDK_HEADER_NAME @"X-UA-BV-SDK" diff --git a/BVSDK/BVProductSentiments/Sentiments/Common/BVProductSentimentsRequest.h b/BVSDK/BVProductSentiments/Sentiments/Common/BVProductSentimentsRequest.h index 47d3ffe5..a274b83d 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Common/BVProductSentimentsRequest.h +++ b/BVSDK/BVProductSentiments/Sentiments/Common/BVProductSentimentsRequest.h @@ -20,8 +20,6 @@ - (nonnull NSString *)getPassKey; - (nonnull NSError *)limitError:(NSInteger)limit; -- (nonnull NSError *)tooManyProductsError: - (nonnull NSArray *)productIds; - (void) loadContent:(nonnull BVProductSentimentsRequest *)request diff --git a/BVSDK/BVProductSentiments/Sentiments/Common/BVProductSentimentsRequest.m b/BVSDK/BVProductSentiments/Sentiments/Common/BVProductSentimentsRequest.m index 156c0d7f..63c95c30 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Common/BVProductSentimentsRequest.m +++ b/BVSDK/BVProductSentiments/Sentiments/Common/BVProductSentimentsRequest.m @@ -7,12 +7,12 @@ #import #import "BVProductSentimentsRequest.h" -//#import "BVDisplayErrorResponse.h" #import "BVLogger+Private.h" #import "BVNetworkingManager.h" #import "BVSDKConfiguration.h" #import "BVSDKManager+Private.h" #import "BVStringKeyValuePair.h" +#import "BVProductSentimentsErrorResponse.h" @interface BVProductSentimentsRequest () @property(strong, nonatomic) @@ -28,22 +28,22 @@ - (instancetype)init { - (nonnull NSMutableArray *)createParams { NSMutableArray *params = [NSMutableArray array]; -// [params -// addObject:[BVStringKeyValuePair pairWithKey:@"apiversion" value:@"5.4"]]; + [params + addObject:[BVStringKeyValuePair pairWithKey:@"apiversion" value:@"5.4"]]; // [params addObject:[BVStringKeyValuePair pairWithKey:@"passkey" // value:[self getPassKey]]]; -// [params addObject:[BVStringKeyValuePair -// pairWithKey:@"_appId" -// value:[NSBundle mainBundle].bundleIdentifier]]; -// [params -// addObject:[BVStringKeyValuePair -// pairWithKey:@"_appVersion" -// value:[BVDiagnosticHelpers releaseVersionNumber]]]; -// [params addObject:[BVStringKeyValuePair -// pairWithKey:@"_buildNumber" -// value:[BVDiagnosticHelpers buildVersionNumber]]]; -// [params addObject:[BVStringKeyValuePair pairWithKey:@"_bvIosSdkVersion" -// value:BV_SDK_VERSION]]; + [params addObject:[BVStringKeyValuePair + pairWithKey:@"_appId" + value:[NSBundle mainBundle].bundleIdentifier]]; + [params + addObject:[BVStringKeyValuePair + pairWithKey:@"_appVersion" + value:[BVDiagnosticHelpers releaseVersionNumber]]]; + [params addObject:[BVStringKeyValuePair + pairWithKey:@"_buildNumber" + value:[BVDiagnosticHelpers buildVersionNumber]]]; + [params addObject:[BVStringKeyValuePair pairWithKey:@"_bvIosSdkVersion" + value:BV_SDK_VERSION]]; if (_customQueryParameters) { [params addObjectsFromArray:_customQueryParameters]; @@ -142,42 +142,33 @@ + (nonnull NSString *)commonEndpoint { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; NSInteger statusCode = [httpResponse statusCode]; - if (statusCode == 200) { @try { - NSError *err; - NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data - options:kNilOptions - error:&err]; - if (json) { - -// BVDisplayErrorResponse *errorResponse = -// [[BVDisplayErrorResponse alloc] initWithApiResponse:json]; -// -// BVLogVerbose(([NSString stringWithFormat:@"RESPONSE: %@ (%ld)", json, -// (long)statusCode]), -// BV_PRODUCT_CONVERSATIONS); -// -// if (errorResponse) { -// [self sendErrors:[errorResponse toNSErrors] failureCallback:failure]; -// } else { -// // invoke success callback on main thread - dispatch_async(dispatch_get_main_queue(), ^{ - completion(json); - }); -// } - } else if (err) { - [self sendError:err failureCallback:failure]; - } else { - NSError *parsingError = - [NSError errorWithDomain:BVErrDomain - code:BV_ERROR_PARSING_FAILED - userInfo:@{ - NSLocalizedDescriptionKey : - @"An unknown parsing error occurred." - }]; - [self sendError:parsingError failureCallback:failure]; - } - + NSError *err; + NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:&err]; + + if (statusCode == 200 && json) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(json); + }); + } else if (statusCode) { + BVProductSentimentsErrorResponse *errorResponse = + [[BVProductSentimentsErrorResponse alloc] initWithApiResponse:json statusCode:[@(statusCode) stringValue]]; + BVLogVerbose(([NSString stringWithFormat:@"RESPONSE: %@ (%ld)", json, + (long)statusCode]), + BV_PRODUCT_CONVERSATIONS); + [self sendErrors:[errorResponse toNSErrors] failureCallback:failure]; + } else { + NSString *message = [NSString + stringWithFormat:@"HTTP response status code: %li with error: %@", + (long)statusCode, error.localizedDescription]; + NSError *enhancedError = + [NSError errorWithDomain:BVErrDomain + code:BV_ERROR_NETWORK_FAILED + userInfo:@{NSLocalizedDescriptionKey : message}]; + [self sendError:enhancedError failureCallback:failure]; + } } @catch (NSException *exception) { NSError *err = [NSError errorWithDomain:BVErrDomain @@ -188,16 +179,6 @@ + (nonnull NSString *)commonEndpoint { }]; [self sendError:err failureCallback:failure]; } - } else { - NSString *message = [NSString - stringWithFormat:@"HTTP response status code: %li with error: %@", - (long)statusCode, error.localizedDescription]; - NSError *enhancedError = - [NSError errorWithDomain:BVErrDomain - code:BV_ERROR_NETWORK_FAILED - userInfo:@{NSLocalizedDescriptionKey : message}]; - [self sendError:enhancedError failureCallback:failure]; - } } - (nonnull NSError *)limitError:(NSInteger)limit { @@ -210,17 +191,6 @@ - (nonnull NSError *)limitError:(NSInteger)limit { userInfo:@{NSLocalizedDescriptionKey : message}]; } -- (nonnull NSError *)tooManyProductsError: - (nonnull NSArray *)productIds { - NSString *message = [NSString - stringWithFormat: - @"Too many productIds requested: %lu. Must be between 1 and 100.", - (unsigned long)[productIds count]]; - return [NSError errorWithDomain:BVErrDomain - code:BV_ERROR_TOO_MANY_PRODUCTS - userInfo:@{NSLocalizedDescriptionKey : message}]; -} - - (void)sendError:(nonnull NSError *)error failureCallback:(ProductSentimentsFailureHandler)failure { [self sendErrors:@[ error ] failureCallback:failure]; diff --git a/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsError.h b/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsError.h new file mode 100644 index 00000000..8d5e7bf7 --- /dev/null +++ b/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsError.h @@ -0,0 +1,32 @@ +// +// BVProductSentimentsError.h +// BVSDK +// +// Copyright © 2025 Bazaarvoice. All rights reserved. +// + +#ifndef BVProductSentimentsError_h +#define BVProductSentimentsError_h + +#import + +#define BVKeyPSErrorDomainCode @(999) + +extern NSString *__nonnull const BVKeyPSStatusCode; +extern NSString *__nonnull const BVKeyPSErrorCode; +extern NSString *__nonnull const BVKeyPSErrorMessage; + +@interface BVProductSentimentsError : NSObject + +@property(nonnull) NSString *message; +@property(nonnull) NSString *code; +@property(nonnull) NSString *status; + +- (nonnull id)initWithApiResponse:(nonnull NSDictionary *)apiResponse + statusCode:(nonnull NSString *) statusCode; +- (nonnull NSError *)toNSError; + +@end + + +#endif /* BVProductSentimentsError_h */ diff --git a/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsError.m b/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsError.m new file mode 100644 index 00000000..99a10c58 --- /dev/null +++ b/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsError.m @@ -0,0 +1,45 @@ +// +// BVProductSentimentsError.m +// BVSDK +// +// Copyright © 2025 Bazaarvoice. All rights reserved. +// + +#import + +#import "BVProductSentimentsError.h" +#import "BVCommon.h" +#import "BVNullHelper.h" + +NSString *__nonnull const BVKeyPSStatusCode = @"BVKeyPSStatusCode"; +NSString *__nonnull const BVKeyPSErrorCode = @"BVKeyPSErrorCode"; +NSString *__nonnull const BVKeyPSErrorMessage = @"BVKeyPSErrorMessage"; + +@implementation BVProductSentimentsError + +- (nonnull id)initWithApiResponse:(nonnull NSDictionary *)apiResponse statusCode:(nonnull NSString *)statusCode { + if ((self = [super init])) { + self.status = statusCode; + self.code = @"N/A"; + self.message = @"N/A"; + + SET_IF_NOT_NULL_WITH_ALTERNATE(self.code, apiResponse[@"code"], apiResponse[@"title"]) + SET_IF_NOT_NULL_WITH_ALTERNATE(self.message, apiResponse[@"message"], apiResponse[@"detail"]) + } + return self; +} + +- (nonnull NSError *)toNSError { + NSString *description = + [NSString stringWithFormat:@"%@: %@\n%@", self.status, self.code, self.message]; + return [NSError errorWithDomain:BVErrDomain + code:BVKeyPSErrorDomainCode.integerValue + userInfo:@{ + NSLocalizedDescriptionKey : description, + BVKeyPSStatusCode : self.status, + BVKeyPSErrorCode : self.message, + BVKeyPSErrorMessage : self.code + }]; +} + +@end diff --git a/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsErrorResponse.h b/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsErrorResponse.h index 4a0e720a..0e7be485 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsErrorResponse.h +++ b/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsErrorResponse.h @@ -21,12 +21,8 @@ */ @interface BVProductSentimentsErrorResponse : NSObject -@property(nonnull) NSString *code; -@property(nonnull) NSString *type; -@property(nonnull) NSString *title; -@property(nonnull) NSString *detail; - -- (nullable id)initWithApiResponse:(nonnull NSDictionary *)apiResponse; +- (nullable id)initWithApiResponse:(nonnull NSDictionary *)apiResponse + statusCode:(nonnull NSString *)statusCode; - (nonnull NSArray *)toNSErrors; @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsErrorResponse.m b/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsErrorResponse.m index 3f591601..93996057 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsErrorResponse.m +++ b/BVSDK/BVProductSentiments/Sentiments/Errors/BVProductSentimentsErrorResponse.m @@ -8,6 +8,7 @@ #import #import "BVProductSentimentsErrorResponse.h" +#import "BVProductSentimentsError.h" #import "BVNullHelper.h" #import "BVProductSentimentsErrorCode.h" #import "NSError+BVProductSentimentsErrorCodeParser.h" @@ -15,64 +16,32 @@ @interface BVProductSentimentsErrorResponse () -@property(nonnull) NSArray *errors; +@property(nonnull) NSArray *errors; @end @implementation BVProductSentimentsErrorResponse -- (nullable id)initWithApiResponse:(nonnull NSDictionary *)apiResponse { +- (nullable id)initWithApiResponse:(nonnull NSDictionary *)apiResponse statusCode:(nonnull NSString *)statusCode { if ((self = [super init])) { - self.code = @"N/A"; - self.type = @"N/A"; - self.title = @"N/A"; - self.detail = @"N/A"; - - - SET_IF_NOT_NULL(self.code, apiResponse[@"code"]) - SET_IF_NOT_NULL(self.type, apiResponse[@"type"]) - SET_IF_NOT_NULL(self.title, apiResponse[@"title"]) - SET_IF_NOT_NULL(self.detail, apiResponse[@"detail"]) - - if (![[apiResponse objectForKey:@"Errors"] - isKindOfClass:[NSArray class]]) { - return nil; - } - - NSArray *rawErrors = - (NSArray *)[apiResponse objectForKey:@"Errors"]; - - NSMutableArray *errorsArrayBuilder = [NSMutableArray array]; -// for (NSDictionary *rawError in rawErrors) { -// BVConversationsError *conversationsError = -// [[BVConversationsError alloc] initWithApiResponse:rawError]; -// [errorsArrayBuilder addObject:conversationsError]; -// } - - if (0 == errorsArrayBuilder.count) { - return nil; - } - - self.errors = errorsArrayBuilder; + NSMutableArray *errorsArrayBuilder = [NSMutableArray array]; + BVProductSentimentsError *error = + [[BVProductSentimentsError alloc] initWithApiResponse:apiResponse statusCode:statusCode]; + [errorsArrayBuilder addObject:error]; + self.errors = errorsArrayBuilder; } return self; } - (nonnull NSArray *)toNSErrors { - NSMutableArray *nsErrorsBuilder = [NSMutableArray array]; - -// NSError *err = [[NSError alloc] bvProductSentimentsErrorCode: self.code]; -// -// -// for (BVConversationsError *conversationsError in self.errors) { -// NSError *nsError = [conversationsError toNSError]; -// [nsErrorsBuilder addObject:nsError]; -// } - + NSMutableArray *nsErrorsBuilder = [NSMutableArray array]; - + for (BVProductSentimentsError *error in self.errors) { + NSError *nsError = [error toNSError]; + [nsErrorsBuilder addObject:nsError]; + } - return nsErrorsBuilder; -} + return nsErrorsBuilder; + } @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Errors/NSError+BVProductSentimentsErrorCodeParser.m b/BVSDK/BVProductSentiments/Sentiments/Errors/NSError+BVProductSentimentsErrorCodeParser.m index 0041697c..bffd4987 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Errors/NSError+BVProductSentimentsErrorCodeParser.m +++ b/BVSDK/BVProductSentiments/Sentiments/Errors/NSError+BVProductSentimentsErrorCodeParser.m @@ -6,13 +6,13 @@ // #import -#import "BVFieldError.h" +#import "BVProductSentimentsError.h" #import "NSError+BVProductSentimentsErrorCodeParser.h" @implementation NSError (BVErrorCodeParser) - (BVProductSentimentsErrorCode)bvProductSentimentsErrorCode { - NSString *code = [self userInfo][BVFieldErrorCode]; + NSString *code = [self userInfo][BVKeyPSStatusCode]; if (!code) { return BVProductSentimentsErrorCodeUnknown; } diff --git a/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeature.h b/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeature.h index 12de3d4f..6e892bd8 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeature.h +++ b/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeature.h @@ -7,11 +7,11 @@ #import #import "BVAverageRatingReviews.h" -#import "BVQuote.h" +#import "BVQuotes.h" #import "BVProductSentimentsResult.h" @class BVAverageRatingReviews; -@class BVQuote; +@class BVQuotes; @interface BVProductFeature : BVProductSentimentsResult @@ -21,7 +21,7 @@ @property(nullable) NSString *nativeFeature; @property(nullable) BVAverageRatingReviews *reviewsMentioned; @property(nullable) BVAverageRatingReviews *averageRatingReviews; -@property(nullable) BVQuote *embedded; +@property(nullable) BVQuotes *embedded; - (nullable id)initWithApiResponse:(nullable id)apiResponse; diff --git a/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeature.m b/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeature.m index 417999aa..c20a139a 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeature.m +++ b/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeature.m @@ -23,9 +23,10 @@ - (nullable id)initWithApiResponse:(nullable id)apiResponse { SET_IF_NOT_NULL(self.featureID, apiObject[@"featureId"]) SET_IF_NOT_NULL(self.percentPositive, apiObject[@"percentPositive"]) SET_IF_NOT_NULL(self.nativeFeature, apiObject[@"nativeFeature"]) - SET_IF_NOT_NULL(self.reviewsMentioned, apiObject[@"reviewsMentioned"]) - SET_IF_NOT_NULL(self.averageRatingReviews, apiObject[@"averageRatingReviews"]) - SET_IF_NOT_NULL(self.embedded, apiObject[@"_embedded"]) + self.reviewsMentioned = [[BVAverageRatingReviews alloc] initWithApiResponse:apiResponse[@"reviewsMentioned"]]; + self.averageRatingReviews = [[BVAverageRatingReviews alloc] initWithApiResponse:apiResponse[@"averageRatingReviews"]]; + self.embedded = [[BVQuotes alloc] initWithApiResponse:apiResponse[@"_embedded"]]; + } return self; } diff --git a/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeatures.m b/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeatures.m index 3a316023..53684a3d 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeatures.m +++ b/BVSDK/BVProductSentiments/Sentiments/Model/BVProductFeatures.m @@ -25,8 +25,19 @@ - (nullable id)initWithApiResponse:(nullable id)apiResponse { SET_IF_NOT_NULL(self.detail, apiObject[@"detail"]) SET_IF_NOT_NULL(self.detail, apiObject[@"detail"]) SET_IF_NOT_NULL(self.instance, apiObject[@"instance"]) + self.features = [BVProductFeatures parseProductFeature:apiResponse[@"features"]]; + } return self; } ++ (nonnull NSArray *)parseProductFeature:(nullable id)apiResponse { + NSMutableArray *tempValues = [NSMutableArray array]; + NSArray *apiObject = apiResponse; + for (NSDictionary *object in apiObject) { + [tempValues addObject:[[BVProductFeature alloc] initWithApiResponse:object]]; + } + return tempValues; +} + @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Model/BVQuotes.m b/BVSDK/BVProductSentiments/Sentiments/Model/BVQuotes.m index 75dede1a..4655dd3c 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Model/BVQuotes.m +++ b/BVSDK/BVProductSentiments/Sentiments/Model/BVQuotes.m @@ -7,6 +7,7 @@ #import #import "BVQuotes.h" +#import "BVQuote.h" #import "BVNullHelper.h" @implementation BVQuotes @@ -19,14 +20,24 @@ - (nullable id)initWithApiResponse:(nullable id)apiResponse { NSDictionary *apiObject = (NSDictionary *)apiResponse; - SET_IF_NOT_NULL(self.quotes, apiObject[@"quotes"]) SET_IF_NOT_NULL(self.status, apiObject[@"status"]) SET_IF_NOT_NULL(self.title, apiObject[@"title"]) SET_IF_NOT_NULL(self.detail, apiObject[@"detail"]) SET_IF_NOT_NULL(self.detail, apiObject[@"detail"]) SET_IF_NOT_NULL(self.instance, apiObject[@"instance"]) + self.quotes = [BVQuotes parseQuotes:apiResponse[@"quotes"]]; + } return self; } ++ (nonnull NSArray *)parseQuotes:(nullable id)apiResponse { + NSMutableArray *tempValues = [NSMutableArray array]; + NSArray *apiObject = apiResponse; + for (NSDictionary *object in apiObject) { + [tempValues addObject:[[BVQuote alloc] initWithApiResponse:object]]; + } + return tempValues; +} + @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Model/BVSummarisedFeatures.h b/BVSDK/BVProductSentiments/Sentiments/Model/BVSummarisedFeatures.h index 919ffaa2..6f9b928d 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Model/BVSummarisedFeatures.h +++ b/BVSDK/BVProductSentiments/Sentiments/Model/BVSummarisedFeatures.h @@ -25,9 +25,6 @@ @property(nullable) NSString *type; @property(nullable) NSString *instance; -@property(nullable) BVProductFeature *firstFeatures; -@property(nullable) NSNumber *pp; - - (nullable id)initWithApiResponse:(nullable id)apiResponse; @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Model/BVSummarisedFeatures.m b/BVSDK/BVProductSentiments/Sentiments/Model/BVSummarisedFeatures.m index fa1cae48..eef17668 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Model/BVSummarisedFeatures.m +++ b/BVSDK/BVProductSentiments/Sentiments/Model/BVSummarisedFeatures.m @@ -16,16 +16,26 @@ - (id)initWithApiResponse:(NSDictionary *)apiResponse { } NSDictionary *apiObject = (NSDictionary *)apiResponse; - - SET_IF_NOT_NULL(self.bestFeatures, apiObject[@"bestFeatures"]) - SET_IF_NOT_NULL(self.worstFeatures, apiObject[@"worstFeatures"]) SET_IF_NOT_NULL(self.status, apiObject[@"status"]) SET_IF_NOT_NULL(self.title, apiObject[@"title"]) SET_IF_NOT_NULL(self.detail, apiObject[@"detail"]) SET_IF_NOT_NULL(self.detail, apiObject[@"detail"]) SET_IF_NOT_NULL(self.instance, apiObject[@"instance"]) + + self.bestFeatures = [BVSummarisedFeatures parseFeatures:apiResponse[@"bestFeatures"]]; + self.worstFeatures = [BVSummarisedFeatures parseFeatures:apiResponse[@"worstFeatures"]]; + } return self; } ++ (nonnull NSArray *)parseFeatures:(nullable id)apiResponse { + NSMutableArray *tempValues = [NSMutableArray array]; + NSArray *apiObject = apiResponse; + for (NSDictionary *object in apiObject) { + [tempValues addObject:[[BVProductFeature alloc] initWithApiResponse:object]]; + } + return tempValues; +} + @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Requests/ProductExpressions/BVProductExpressionsRequest.m b/BVSDK/BVProductSentiments/Sentiments/Requests/ProductExpressions/BVProductExpressionsRequest.m index c1eca0df..3224d828 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Requests/ProductExpressions/BVProductExpressionsRequest.m +++ b/BVSDK/BVProductSentiments/Sentiments/Requests/ProductExpressions/BVProductExpressionsRequest.m @@ -54,6 +54,9 @@ - (void)load:(nonnull void (^)(BVProductExpressionsResponse *__nonnull response) // validate request if ([self.productId isEqualToString:@""] || [self.feature isEqualToString:@""] || [self.language isEqualToString:@""]) { [self sendError:[self validationError] failureCallback:failure]; + } else if (1 > self.limit || 100 < self.limit) { + // invalid request + [self sendError:[super limitError:self.limit] failureCallback:failure]; } else { [self loadProductExpressions:self completion:success failure:failure]; } @@ -81,11 +84,22 @@ - (nonnull NSError *)validationError { dispatch_async(dispatch_get_main_queue(), ^{ completion(productExpressionsResponse); }); -// [self sendQuestionsAnalytics:questionsAndAnswersResponse]; + [self sendProductSentimentsAnalytics]; } failure:failure]; } +- (void)sendProductSentimentsAnalytics { + // send usedfeature for product sentiments + BVFeatureUsedEvent *event = [[BVFeatureUsedEvent alloc] + initWithProductId:self.productId + withBrand:nil + withProductType:BVPixelProductTypeProductSentiments + withEventName:BVPixelFeatureUsedEventNameReviewHighlights + withAdditionalParams:nil]; + + [BVPixel trackEvent:event]; +} @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Requests/ProductFeatures/BVProductFeaturesRequest.m b/BVSDK/BVProductSentiments/Sentiments/Requests/ProductFeatures/BVProductFeaturesRequest.m index 65c7e554..308296c3 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Requests/ProductFeatures/BVProductFeaturesRequest.m +++ b/BVSDK/BVProductSentiments/Sentiments/Requests/ProductFeatures/BVProductFeaturesRequest.m @@ -52,6 +52,9 @@ - (void)load:(nonnull void (^)(BVProductFeaturesResponse *__nonnull response))su // validate request if ([self.productId isEqualToString:@""] || [self.language isEqualToString:@""]) { [self sendError:[self validationError] failureCallback:failure]; + } else if (1 > self.limit || 100 < self.limit) { + // invalid request + [self sendError:[super limitError:self.limit] failureCallback:failure]; } else { [self loadProductFeatures:self completion:success failure:failure]; } @@ -79,11 +82,22 @@ - (nonnull NSError *)validationError { dispatch_async(dispatch_get_main_queue(), ^{ completion(productFeaturesResponse); }); -// [self sendQuestionsAnalytics:questionsAndAnswersResponse]; + [self sendProductSentimentsAnalytics]; } failure:failure]; } +- (void)sendProductSentimentsAnalytics { + // send usedfeature for product sentiments + BVFeatureUsedEvent *event = [[BVFeatureUsedEvent alloc] + initWithProductId:self.productId + withBrand:nil + withProductType:BVPixelProductTypeProductSentiments + withEventName:BVPixelFeatureUsedEventNameReviewHighlights + withAdditionalParams:nil]; + + [BVPixel trackEvent:event]; +} @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Requests/ProductQuotes/BVProductQuotesRequest.m b/BVSDK/BVProductSentiments/Sentiments/Requests/ProductQuotes/BVProductQuotesRequest.m index 26d0a66b..7388b586 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Requests/ProductQuotes/BVProductQuotesRequest.m +++ b/BVSDK/BVProductSentiments/Sentiments/Requests/ProductQuotes/BVProductQuotesRequest.m @@ -50,6 +50,9 @@ - (void)load:(nonnull void (^)(BVProductQuotesResponse *__nonnull response))succ // validate request if ([self.productId isEqualToString:@""] || [self.language isEqualToString:@""]) { [self sendError:[self validationError] failureCallback:failure]; + } else if (1 > self.limit || 100 < self.limit) { + // invalid request + [self sendError:[super limitError:self.limit] failureCallback:failure]; } else { [self loadProductQuotes:self completion:success failure:failure]; } @@ -77,11 +80,22 @@ - (nonnull NSError *)validationError { dispatch_async(dispatch_get_main_queue(), ^{ completion(productQuotesResponse); }); -// [self sendQuestionsAnalytics:questionsAndAnswersResponse]; + [self sendProductSentimentsAnalytics]; } failure:failure]; } +- (void)sendProductSentimentsAnalytics { + // send usedfeature for product sentiments + BVFeatureUsedEvent *event = [[BVFeatureUsedEvent alloc] + initWithProductId:self.productId + withBrand:nil + withProductType:BVPixelProductTypeProductSentiments + withEventName:BVPixelFeatureUsedEventNameReviewHighlights + withAdditionalParams:nil]; + + [BVPixel trackEvent:event]; +} @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeatures/BVSummarisedFeaturesRequest.m b/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeatures/BVSummarisedFeaturesRequest.m index 8ac538b4..465f0326 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeatures/BVSummarisedFeaturesRequest.m +++ b/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeatures/BVSummarisedFeaturesRequest.m @@ -78,9 +78,22 @@ - (nonnull NSError *)validationError { dispatch_async(dispatch_get_main_queue(), ^{ completion(summarisedFeaturesResponse); }); -// [self sendQuestionsAnalytics:questionsAndAnswersResponse]; + [self sendProductSentimentsAnalytics]; } failure:failure]; } +- (void)sendProductSentimentsAnalytics { + // send usedfeature for product sentiments + + BVFeatureUsedEvent *event = [[BVFeatureUsedEvent alloc] + initWithProductId:self.productId + withBrand:nil + withProductType:BVPixelProductTypeProductSentiments + withEventName:BVPixelFeatureUsedEventNameReviewHighlights + withAdditionalParams:nil]; + + [BVPixel trackEvent:event]; +} + @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeatures/BVSummarisedFeaturesResponse.m b/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeatures/BVSummarisedFeaturesResponse.m index 979f5f32..cd4205c3 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeatures/BVSummarisedFeaturesResponse.m +++ b/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeatures/BVSummarisedFeaturesResponse.m @@ -19,14 +19,4 @@ - (id)createResult:(NSDictionary *)apiResponse { return [[BVSummarisedFeatures alloc] initWithApiResponse:apiResponse]; } -//- (nonnull instancetype)initWithApiResponse:(nonnull NSDictionary *)apiResponse { -// if ((self = [super init])) { -// NSDictionary *results = apiResponse; -// if (results.count) { -// _result = [self createResult:results]; -// } -// } -// return self; -// } - @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeaturesQuotes/BVSummarisedFeaturesQuotesRequest.m b/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeaturesQuotes/BVSummarisedFeaturesQuotesRequest.m index 11cee17b..273fb0f4 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeaturesQuotes/BVSummarisedFeaturesQuotesRequest.m +++ b/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeaturesQuotes/BVSummarisedFeaturesQuotesRequest.m @@ -54,6 +54,9 @@ - (void)load:(nonnull void (^)(BVSummarisedFeaturesQuotesResponse *__nonnull res // validate request if ([self.productId isEqualToString:@""] || [self.featureId isEqualToString:@""] || [self.language isEqualToString:@""]) { [self sendError:[self validationError] failureCallback:failure]; + } else if (1 > self.limit || 100 < self.limit) { + // invalid request + [self sendError:[super limitError:self.limit] failureCallback:failure]; } else { [self loadSummarisedFeaturesQuotes:self completion:success failure:failure]; } @@ -81,11 +84,22 @@ - (nonnull NSError *)validationError { dispatch_async(dispatch_get_main_queue(), ^{ completion(summarisedFeaturesQuotesResponse); }); -// [self sendQuestionsAnalytics:questionsAndAnswersResponse]; + [self sendProductSentimentsAnalytics]; } failure:failure]; } +- (void)sendProductSentimentsAnalytics { + // send usedfeature for product sentiments + BVFeatureUsedEvent *event = [[BVFeatureUsedEvent alloc] + initWithProductId:self.productId + withBrand:nil + withProductType:BVPixelProductTypeProductSentiments + withEventName:BVPixelFeatureUsedEventNameReviewHighlights + withAdditionalParams:nil]; + + [BVPixel trackEvent:event]; +} @end diff --git a/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeaturesQuotes/BVSummarisedFeaturesQuotesResponse.h b/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeaturesQuotes/BVSummarisedFeaturesQuotesResponse.h index 24856661..be0f43ff 100644 --- a/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeaturesQuotes/BVSummarisedFeaturesQuotesResponse.h +++ b/BVSDK/BVProductSentiments/Sentiments/Requests/SummarisedFeaturesQuotes/BVSummarisedFeaturesQuotesResponse.h @@ -12,11 +12,6 @@ #import "BVQuotes.h" @interface BVSummarisedFeaturesQuotesResponse : BVProductSentimentsResponse - -//@property (nullable) ResultType result; -// -//- (nonnull instancetype)initWithApiResponse:(nonnull NSDictionary *)apiResponse; - @end #endif /* BVSummarisedFeaturesQuotesResponse_h */ diff --git a/BVSDK/Support/Info.plist b/BVSDK/Support/Info.plist index 09962e0a..a7c2e4e1 100644 --- a/BVSDK/Support/Info.plist +++ b/BVSDK/Support/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 8.13.2 + 8.13.3 CFBundleVersion 1 LSApplicationCategoryType diff --git a/BVSDKTests/ConversationsTests/DisplayTests/BVReviewSummaryDisplayTests.swift b/BVSDKTests/ConversationsTests/DisplayTests/BVReviewSummaryDisplayTests.swift index 1b90312a..1457c8b3 100644 --- a/BVSDKTests/ConversationsTests/DisplayTests/BVReviewSummaryDisplayTests.swift +++ b/BVSDKTests/ConversationsTests/DisplayTests/BVReviewSummaryDisplayTests.swift @@ -14,7 +14,7 @@ final class BVReviewSummaryDisplayTests: XCTestCase { super.setUp() let configDict = ["clientId": "bv-beauty", - "apiKeyConversations": BVTestUsers().loadValueForKey(key: .bvBeauty)]; + "apiKeyConversations": BVTestUsers().loadValueForKey(key: .conversationsKeyBVBeauty)]; BVSDKManager.configure(withConfiguration: configDict, configType: .prod) } @@ -25,7 +25,7 @@ final class BVReviewSummaryDisplayTests: XCTestCase { func testReviewSummaryDisplay() { let expectation = self.expectation(description: "testReviewSummaryDisplay") - let request = BVReviewSummaryRequest(productId: "P000036", formatType: BVReviewSummaryFormatType.paragraph) + let request = BVReviewSummaryRequest(productId: "P000036", formatType: BVReviewSummaryFormatType.bullet) // or BVReviewSummaryFormatType.paragraph request.load({ (response) in XCTAssertNotNil(response.summary) diff --git a/BVSDKTests/MockData/testKeys.json b/BVSDKTests/MockData/testKeys.json index 71ba3c82..dbce5a10 100644 --- a/BVSDKTests/MockData/testKeys.json +++ b/BVSDKTests/MockData/testKeys.json @@ -13,8 +13,7 @@ "conversationsKey12": "cauPFGiXDMZYw1QQ11PBmJXt5YdK5oEvirFBMxlyshhlU", "conversationsKey13": "772wfav4cvd8fpw2vdt64pgc", "conversationsKey14": "badkey", - "conversationsKeyProductSentiments": "caKfOxPN9v5xDgUjw2DJMG0xndA1QuGJXP0VzYzsUMtvc", - "bvBeauty": "caKfOxPN9v5xDgUjw2DJMG0xndA1QuGJXP0VzYzsUMtvc", + "conversationsKeyBVBeauty": "caKfOxPN9v5xDgUjw2DJMG0xndA1QuGJXP0VzYzsUMtvc", "answerUserId": "craiggil", "feedbackUserId": "userId3532791931", "feedbackUser": "dea9114258e49d5d95f4db5d4465991f7573657269643d7573657249643335333237393139333126646174653d3230323030353039", diff --git a/BVSDKTests/ProductSentimentsTests/BVProductExpressionsQueryTest.swift b/BVSDKTests/ProductSentimentsTests/BVProductExpressionsQueryTest.swift index 2e41d412..f58f1e1f 100644 --- a/BVSDKTests/ProductSentimentsTests/BVProductExpressionsQueryTest.swift +++ b/BVSDKTests/ProductSentimentsTests/BVProductExpressionsQueryTest.swift @@ -13,7 +13,7 @@ final class BVProductExpressionsQueryTest: XCTestCase { override func setUp() { super.setUp() let configDict = ["clientId": "bv-beauty", - "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyProductSentiments)]; + "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyBVBeauty)]; BVSDKManager.configure(withConfiguration: configDict, configType: .prod) BVSDKManager.shared().setLogLevel(BVLogLevel.verbose) BVSDKManager.shared().urlSessionDelegate = nil; @@ -30,9 +30,11 @@ final class BVProductExpressionsQueryTest: XCTestCase { request.load({ response in XCTAssertNotNil(response.result.expressions) expectation.fulfill() - }) { (error) in - - XCTFail("product display request error: \(error)") + }) { (errors) in + for error in errors { + XCTAssert((error as NSError).bvProductSentimentsErrorCode() == BVProductSentimentsErrorCode.noContent) + XCTFail("product sentiments request error: \(error)") + } expectation.fulfill() } self.waitForExpectations(timeout: 120) { (error) in diff --git a/BVSDKTests/ProductSentimentsTests/BVProductFeaturesQueryTest.swift b/BVSDKTests/ProductSentimentsTests/BVProductFeaturesQueryTest.swift index 130564f4..1d1aba7b 100644 --- a/BVSDKTests/ProductSentimentsTests/BVProductFeaturesQueryTest.swift +++ b/BVSDKTests/ProductSentimentsTests/BVProductFeaturesQueryTest.swift @@ -13,7 +13,7 @@ final class BVProductFeaturesQueryTest: XCTestCase { override func setUp() { super.setUp() let configDict = ["clientId": "bv-beauty", - "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyProductSentiments)]; + "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyBVBeauty)]; BVSDKManager.configure(withConfiguration: configDict, configType: .prod) BVSDKManager.shared().setLogLevel(BVLogLevel.verbose) BVSDKManager.shared().urlSessionDelegate = nil; @@ -30,9 +30,11 @@ final class BVProductFeaturesQueryTest: XCTestCase { request.load({ response in XCTAssertNotNil(response.result.features) expectation.fulfill() - }) { (error) in - - XCTFail("product display request error: \(error)") + }) { (errors) in + for error in errors { + XCTAssert((error as NSError).bvProductSentimentsErrorCode() == BVProductSentimentsErrorCode.noContent) + XCTFail("product sentiments request error: \(error)") + } expectation.fulfill() } self.waitForExpectations(timeout: 120) { (error) in diff --git a/BVSDKTests/ProductSentimentsTests/BVProductQuotesQueryTest.swift b/BVSDKTests/ProductSentimentsTests/BVProductQuotesQueryTest.swift index d86414af..b91397ac 100644 --- a/BVSDKTests/ProductSentimentsTests/BVProductQuotesQueryTest.swift +++ b/BVSDKTests/ProductSentimentsTests/BVProductQuotesQueryTest.swift @@ -13,7 +13,7 @@ final class BVProductQuotesQueryTest: XCTestCase { override func setUp() { super.setUp() let configDict = ["clientId": "bv-beauty", - "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyProductSentiments)]; + "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyBVBeauty)]; BVSDKManager.configure(withConfiguration: configDict, configType: .prod) BVSDKManager.shared().setLogLevel(BVLogLevel.verbose) BVSDKManager.shared().urlSessionDelegate = nil; @@ -30,9 +30,11 @@ final class BVProductQuotesQueryTest: XCTestCase { request.load({ response in XCTAssertNotNil(response.result.quotes) expectation.fulfill() - }) { (error) in - - XCTFail("product display request error: \(error)") + }) { (errors) in + for error in errors { + XCTAssert((error as NSError).bvProductSentimentsErrorCode() == BVProductSentimentsErrorCode.noContent) + XCTFail("product sentiments request error: \(error)") + } expectation.fulfill() } self.waitForExpectations(timeout: 120) { (error) in diff --git a/BVSDKTests/ProductSentimentsTests/BVSummarisedFeaturesQueryTest.swift b/BVSDKTests/ProductSentimentsTests/BVSummarisedFeaturesQueryTest.swift index c0e13b2c..526e5f20 100644 --- a/BVSDKTests/ProductSentimentsTests/BVSummarisedFeaturesQueryTest.swift +++ b/BVSDKTests/ProductSentimentsTests/BVSummarisedFeaturesQueryTest.swift @@ -13,10 +13,10 @@ final class BVSummarisedFeaturesQueryTest: XCTestCase { override func setUp() { super.setUp() let configDict = ["clientId": "bv-beauty", - "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyProductSentiments)]; + "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyBVBeauty)]; BVSDKManager.configure(withConfiguration: configDict, configType: .prod) - BVSDKManager.shared().setLogLevel(BVLogLevel.verbose) - BVSDKManager.shared().urlSessionDelegate = nil; + BVSDKManager.shared().setLogLevel(BVLogLevel.verbose) + BVSDKManager.shared().urlSessionDelegate = nil; } override func tearDown() { @@ -28,21 +28,83 @@ final class BVSummarisedFeaturesQueryTest: XCTestCase { let expectation = self.expectation(description: "testProductSummarisedFeatures") let request = BVSummarisedFeaturesRequest(productId: "P000010", language: "en", embed: "quotes") request.load({ response in - if let bestFeatures = response.result.bestFeatures { - if let first = (bestFeatures.first) { - print(first.feature ?? "") - } + guard let bestFeatures = response.result.bestFeatures, let feature = bestFeatures.first else { + XCTFail("No feature received") + expectation.fulfill() + return } + XCTAssertEqual(feature.nativeFeature, "removal") + XCTAssertNotNil(feature.embedded?.quotes) expectation.fulfill() - }) { (error) in - - XCTFail("product display request error: \(error)") + }) { (errors) in + for error in errors { + XCTAssert((error as NSError).bvProductSentimentsErrorCode() == BVProductSentimentsErrorCode.noContent) + XCTFail("product sentiments request error: \(error)") + } expectation.fulfill() } self.waitForExpectations(timeout: 120) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + } + + func testProductSummarisedFeaturesWithoutQuotes() { + let expectation = self.expectation(description: "testProductSummarisedFeaturesWithoutQuotes") + let request = BVSummarisedFeaturesRequest(productId: "P000010", language: "en", embed: "") + request.load({ response in + guard let bestFeatures = response.result.bestFeatures, let feature = bestFeatures.first else { + XCTFail("No feature received") + expectation.fulfill() + return + } + XCTAssertEqual(feature.nativeFeature, "removal") + XCTAssertNil(feature.embedded?.quotes) + expectation.fulfill() + }) { (errors) in + for error in errors { + XCTAssert((error as NSError).bvProductSentimentsErrorCode() == BVProductSentimentsErrorCode.noContent) + XCTFail("product sentiments request error: \(error)") + } + expectation.fulfill() + } + self.waitForExpectations(timeout: 60) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + } + + func testProductSummarisedFeaturesFailureNoContent() { + let expectation = self.expectation(description: "testProductSummarisedFeaturesFailureNoContent") + let request = BVSummarisedFeaturesRequest(productId: "P00001", language: "en", embed: "quotes") + request.load({ response in + XCTFail("Query should fail") + expectation.fulfill() + }) { (errors) in + for error in errors { + print(error.localizedDescription) + XCTAssert((error as NSError).bvProductSentimentsErrorCode() == BVProductSentimentsErrorCode.noContent) + } + expectation.fulfill() + } + self.waitForExpectations(timeout: 120) { (error) in + XCTAssertNil(error, "Something went horribly wrong, request took too long.") + } + } + + func testProductSummarisedFeaturesFailureInvalidEmbed() { + let expectation = self.expectation(description: "testProductSummarisedFeaturesFailureInvalidEmbed") + let request = BVSummarisedFeaturesRequest(productId: "P000010", language: "en", embed: "quote") + request.load({ response in + XCTFail("Query should fail") + expectation.fulfill() + }) { (errors) in + for error in errors { + print(error.localizedDescription) + XCTAssert((error as NSError).bvProductSentimentsErrorCode() == BVProductSentimentsErrorCode.badRequest) + } + expectation.fulfill() + } + self.waitForExpectations(timeout: 60) { (error) in XCTAssertNil(error, "Something went horribly wrong, request took too long.") } } - - } diff --git a/BVSDKTests/ProductSentimentsTests/BVSummarisedFeaturesQuotesQueryTest.swift b/BVSDKTests/ProductSentimentsTests/BVSummarisedFeaturesQuotesQueryTest.swift index 2ed7d8c6..ecd05f69 100644 --- a/BVSDKTests/ProductSentimentsTests/BVSummarisedFeaturesQuotesQueryTest.swift +++ b/BVSDKTests/ProductSentimentsTests/BVSummarisedFeaturesQuotesQueryTest.swift @@ -13,7 +13,7 @@ final class BVSummarisedFeaturesQuotesQueryTest: XCTestCase { override func setUp() { super.setUp() let configDict = ["clientId": "bv-beauty", - "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyProductSentiments)]; + "apiKeyProductSentiments": BVTestUsers().loadValueForKey(key: .conversationsKeyBVBeauty)]; BVSDKManager.configure(withConfiguration: configDict, configType: .prod) BVSDKManager.shared().setLogLevel(BVLogLevel.verbose) BVSDKManager.shared().urlSessionDelegate = nil; @@ -26,18 +26,27 @@ final class BVSummarisedFeaturesQuotesQueryTest: XCTestCase { func testProductSummarisedFeaturesQuotes() { let expectation = self.expectation(description: "testProductSummarisedFeaturesQuotes") - let request = BVSummarisedFeaturesQuotesRequest(productId: "P000036", featureId: "111701", language: "en", limit: 10) + let request = BVSummarisedFeaturesQuotesRequest(productId: "P000010", featureId: "111715", language: "en", limit: 10) request.load({ response in XCTAssertNotNil(response.result.quotes) - if let quotes = response.result.quotes?.isEmpty { + guard let quotes = response.result.quotes else { XCTFail("No quotes to display") - } else { - + expectation.fulfill() + return } - expectation.fulfill() - }) { (error) in - XCTFail("product display request error: \(error)") + guard let quote = quotes.first else { + XCTFail("No quotes to display") + expectation.fulfill() + return + } + XCTAssertEqual("Easy to remove with regular nail polish remover.", quote.text) + expectation.fulfill() + }) { (errors) in + for error in errors { + XCTAssert((error as NSError).bvProductSentimentsErrorCode() == BVProductSentimentsErrorCode.noContent) + XCTFail("product sentiments request error: \(error)") + } expectation.fulfill() } self.waitForExpectations(timeout: 120) { (error) in diff --git a/BVSDKTests/Support/BVTestUsers.swift b/BVSDKTests/Support/BVTestUsers.swift index f339cf18..cac7bd11 100644 --- a/BVSDKTests/Support/BVTestUsers.swift +++ b/BVSDKTests/Support/BVTestUsers.swift @@ -23,8 +23,7 @@ class BVTestUsers { case conversationsKey12 = "conversationsKey12" case conversationsKey13 = "conversationsKey13" case conversationsKey14 = "conversationsKey14" - case conversationsKeyProductSentiments = "conversationsKeyProductSentiments" - case bvBeauty = "bvBeauty" + case conversationsKeyBVBeauty = "conversationsKeyBVBeauty" case answerUserId = "answerUserId" case feedbackUserId = "feedbackUserId" case feedbackUser = "feedbackUser" diff --git a/catalog-info.yaml b/catalog-info.yaml index 41dd0830..1621be13 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -2,7 +2,10 @@ apiVersion: backstage.io/v1alpha1 kind: Component metadata: name: bv-ios-sdk + github.com/project-slug: bvengineering/bv-ios-sdk-dev description: Bazaarvoice Mobile SDK for iOS which supports Objective-C programming language. + annotations: + github.com/project-slug: bvengineering/bv-ios-sdk-dev links: - url: https://github.com/bvengineering/bv-ios-sdk-dev title: bv-ios-sdk repository