Skip to content

Commit

Permalink
Merge pull request #180 from launchdarkly/gw/remove-lduser-dict-init
Browse files Browse the repository at this point in the history
  • Loading branch information
gwhelanLD authored Mar 11, 2022
2 parents a98286f + 99256d5 commit ec8c2cd
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 149 deletions.
26 changes: 0 additions & 26 deletions LaunchDarkly/LaunchDarkly/Models/LDUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,32 +101,6 @@ public struct LDUser {
Log.debug(typeName(and: #function) + "user: \(self)")
}

/**
Initializer that takes a [String: Any] and creates a LDUser from the contents. Uses any keys present to define corresponding attribute values. Initializes attributes not present in the dictionary to their default value. Attempts to set `device` and `operatingSystem` from corresponding values embedded in `custom`.
- parameter userDictionary: Dictionary with LDUser attribute keys and values.
*/
public init(userDictionary: [String: Any]) {
key = userDictionary[CodingKeys.key.rawValue] as? String ?? LDUser.defaultKey(environmentReporter: EnvironmentReporter())
secondary = userDictionary[CodingKeys.secondary.rawValue] as? String
isAnonymous = userDictionary[CodingKeys.isAnonymous.rawValue] as? Bool ?? false

name = userDictionary[CodingKeys.name.rawValue] as? String
firstName = userDictionary[CodingKeys.firstName.rawValue] as? String
lastName = userDictionary[CodingKeys.lastName.rawValue] as? String
country = userDictionary[CodingKeys.country.rawValue] as? String
ipAddress = userDictionary[CodingKeys.ipAddress.rawValue] as? String
email = userDictionary[CodingKeys.email.rawValue] as? String
avatar = userDictionary[CodingKeys.avatar.rawValue] as? String
if let privateAttrs = (userDictionary[CodingKeys.privateAttributes.rawValue] as? [String]) {
privateAttributes = privateAttrs.map { UserAttribute.forName($0) }
} else {
privateAttributes = []
}
custom = userDictionary[CodingKeys.custom.rawValue] as? [String: Any] ?? [:]

Log.debug(typeName(and: #function) + "user: \(self)")
}

/**
Internal initializer that accepts an environment reporter, used for testing
*/
Expand Down
9 changes: 0 additions & 9 deletions LaunchDarkly/LaunchDarkly/ObjectiveC/ObjcLDUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,6 @@ public final class ObjcLDUser: NSObject {
self.user = user
}

/**
Initializer that takes a NSDictionary and creates a LDUser from the contents. Uses any keys present to define corresponding attribute values. Initializes attributes not present in the dictionary to their default value. The initializer attempts to set `device` and `operatingSystem` from corresponding values embedded in `custom`. The initializer attempts to set feature flags from values set in `config`.

- parameter userDictionary: NSDictionary with LDUser attribute keys and values.
*/
@objc public init(userDictionary: [String: Any]) {
self.user = LDUser(userDictionary: userDictionary)
}

/// Compares users by comparing their user keys only, to allow the client app to collect user information over time
@objc public func isEqual(object: Any) -> Bool {
guard let otherUser = object as? ObjcLDUser
Expand Down
22 changes: 8 additions & 14 deletions LaunchDarkly/LaunchDarklyTests/Models/EventSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ final class EventSpec: QuickSpec {
}
it("creates a dictionary with the user key only") {
expect(eventDictionary.eventUserKey) == user.key
expect(eventDictionary.eventUser).to(beNil())
expect(eventDictionary.eventUserDictionary).to(beNil())
}
}
context("inlining user and without reason") {
Expand Down Expand Up @@ -370,7 +370,7 @@ final class EventSpec: QuickSpec {
expect(AnyComparer.isEqual(eventDictionary.eventValue, to: true)).to(beTrue())
expect(AnyComparer.isEqual(eventDictionary.eventDefaultValue, to: false)).to(beTrue())
expect(eventDictionary.eventUserKey) == user.key
expect(eventDictionary.eventUser).to(beNil())
expect(eventDictionary.eventUserDictionary).to(beNil())
expect(eventDictionary.eventVariation) == featureFlag.variation
expect(eventDictionary.eventVersion) == featureFlag.version
expect(eventDictionary.eventData).to(beNil())
Expand All @@ -389,7 +389,7 @@ final class EventSpec: QuickSpec {
expect(AnyComparer.isEqual(eventDictionary.eventValue, to: true)).to(beTrue())
expect(AnyComparer.isEqual(eventDictionary.eventDefaultValue, to: false)).to(beTrue())
expect(eventDictionary.eventUserKey) == user.key
expect(eventDictionary.eventUser).to(beNil())
expect(eventDictionary.eventUserDictionary).to(beNil())
expect(eventDictionary.eventVariation) == featureFlag.variation
expect(eventDictionary.eventVersion).to(beNil())
expect(eventDictionary.eventData).to(beNil())
Expand All @@ -413,7 +413,7 @@ final class EventSpec: QuickSpec {
}
it("creates a dictionary with the user key only") {
expect(eventDictionary.eventUserKey) == user.key
expect(eventDictionary.eventUser).to(beNil())
expect(eventDictionary.eventUserDictionary).to(beNil())
}
}
it("creates a dictionary with contextKind for anonymous user") {
Expand Down Expand Up @@ -519,7 +519,7 @@ final class EventSpec: QuickSpec {
expect(eventDictionary.eventDefaultValue).to(beNil())
expect(eventDictionary.eventVariation).to(beNil())
expect(eventDictionary.eventUserKey) == user.key
expect(eventDictionary.eventUser).to(beNil())
expect(eventDictionary.eventUserDictionary).to(beNil())
expect(eventDictionary.eventMetricValue) == metricValue
}
}
Expand All @@ -544,7 +544,7 @@ final class EventSpec: QuickSpec {
expect(eventDictionary.eventDefaultValue).to(beNil())
expect(eventDictionary.eventVariation).to(beNil())
expect(eventDictionary.eventUserKey) == user.key
expect(eventDictionary.eventUser).to(beNil())
expect(eventDictionary.eventUserDictionary).to(beNil())
}
}
context("without inlining user") {
Expand All @@ -570,7 +570,7 @@ final class EventSpec: QuickSpec {
}
it("creates a dictionary with the user key only") {
expect(eventDictionary.eventUserKey) == user.key
expect(eventDictionary.eventUser).to(beNil())
expect(eventDictionary.eventUserDictionary).to(beNil())
}
}
context("inlining user") {
Expand Down Expand Up @@ -746,7 +746,7 @@ final class EventSpec: QuickSpec {

expect(eventDictionary.eventKey).to(beNil())
expect(eventDictionary.eventCreationDate).to(beNil())
expect(eventDictionary.eventUser).to(beNil())
expect(eventDictionary.eventUserDictionary).to(beNil())
expect(eventDictionary.eventUserKey).to(beNil())
expect(eventDictionary.eventValue).to(beNil())
expect(eventDictionary.eventDefaultValue).to(beNil())
Expand Down Expand Up @@ -842,12 +842,6 @@ extension Dictionary where Key == String, Value == Any {
var eventUserKey: String? {
self[Event.CodingKeys.userKey.rawValue] as? String
}
fileprivate var eventUser: LDUser? {
if let userDictionary = eventUserDictionary {
return LDUser(userDictionary: userDictionary)
}
return nil
}
fileprivate var eventUserDictionary: [String: Any]? {
self[Event.CodingKeys.user.rawValue] as? [String: Any]
}
Expand Down
75 changes: 0 additions & 75 deletions LaunchDarkly/LaunchDarklyTests/Models/User/LDUserSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ final class LDUserSpec: QuickSpec {

private func initSpec() {
initSubSpec()
initFromDictionarySpec()
initWithEnvironmentReporterSpec()
}

Expand Down Expand Up @@ -88,80 +87,6 @@ final class LDUserSpec: QuickSpec {
}
}

private func initFromDictionarySpec() {
describe("init from dictionary") {
var user: LDUser!
var originalUser: LDUser!
context("and optional elements") {
beforeEach {
originalUser = LDUser.stub()
var userDictionary = originalUser.dictionaryValue(includePrivateAttributes: true, config: LDConfig.stub)
userDictionary[LDUser.CodingKeys.privateAttributes.rawValue] = LDUser.optionalAttributes.map { $0.name }
user = LDUser(userDictionary: userDictionary)
}
it("creates a user with optional elements and feature flags") {
expect(user.key) == originalUser.key
expect(user.secondary) == originalUser.secondary
expect(user.name) == originalUser.name
expect(user.firstName) == originalUser.firstName
expect(user.lastName) == originalUser.lastName
expect(user.isAnonymous) == originalUser.isAnonymous
expect(user.country) == originalUser.country
expect(user.ipAddress) == originalUser.ipAddress
expect(user.email) == originalUser.email
expect(user.avatar) == originalUser.avatar
expect(user.custom == originalUser.custom).to(beTrue())
expect(user.privateAttributes) == LDUser.optionalAttributes
}
}
context("without optional elements") {
beforeEach {
originalUser = LDUser(isAnonymous: true)
var userDictionary = originalUser.dictionaryValue(includePrivateAttributes: true, config: LDConfig.stub)
userDictionary[LDUser.CodingKeys.privateAttributes.rawValue] = originalUser.privateAttributes
user = LDUser(userDictionary: userDictionary)
}
it("creates a user without optional elements") {
expect(user.key) == originalUser.key
expect(user.isAnonymous) == originalUser.isAnonymous

expect(user.name).to(beNil())
expect(user.firstName).to(beNil())
expect(user.lastName).to(beNil())
expect(user.country).to(beNil())
expect(user.ipAddress).to(beNil())
expect(user.email).to(beNil())
expect(user.avatar).to(beNil())
expect(user.secondary).to(beNil())

expect(user.custom.count) == 2
expect(user.custom[LDUser.CodingKeys.device.rawValue] as? String) == EnvironmentReporter().deviceModel
expect(user.custom[LDUser.CodingKeys.operatingSystem.rawValue] as? String) == EnvironmentReporter().systemVersion
expect(user.privateAttributes).to(beEmpty())
}
}
context("with empty dictionary") {
it("creates a user without optional elements or feature flags") {
user = LDUser(userDictionary: [:])
expect(user.key).toNot(beNil())
expect(user.key.isEmpty).to(beFalse())
expect(user.isAnonymous) == false

expect(user.secondary).to(beNil())
expect(user.name).to(beNil())
expect(user.firstName).to(beNil())
expect(user.lastName).to(beNil())
expect(user.country).to(beNil())
expect(user.ipAddress).to(beNil())
expect(user.email).to(beNil())
expect(user.avatar).to(beNil())
expect(user.custom).to(beEmpty())
expect(user.privateAttributes).to(beEmpty())
}
}
}
}

private func initWithEnvironmentReporterSpec() {
describe("initWithEnvironmentReporter") {
var user: LDUser!
Expand Down
37 changes: 12 additions & 25 deletions LaunchDarkly/LaunchDarklyTests/Networking/DarklyServiceSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,8 @@ final class DarklyServiceSpec: QuickSpec {
expect(urlRequest?.url?.host) == testContext.config.baseUrl.host
if let path = urlRequest?.url?.path {
expect(path.hasPrefix("/\(DarklyService.FlagRequestPath.get)")).to(beTrue())
if let encodedUserString = urlRequest?.url?.lastPathComponent,
let decodedUser = LDUser(base64urlEncodedString: encodedUserString) {
expect(decodedUser.isEqual(to: testContext.user)) == true
} else {
fail("encoded user string did not create a user")
}
let expectedUser = testContext.user.dictionaryValue(includePrivateAttributes: true, config: testContext.config)
expect(AnyComparer.isEqual(urlRequest?.url?.lastPathComponent.jsonDictionary, to: expectedUser)) == true
} else {
fail("request path is missing")
}
Expand Down Expand Up @@ -176,12 +172,8 @@ final class DarklyServiceSpec: QuickSpec {
expect(urlRequest?.url?.host) == testContext.config.baseUrl.host
if let path = urlRequest?.url?.path {
expect(path.hasPrefix("/\(DarklyService.FlagRequestPath.get)")).to(beTrue())
if let encodedUserString = urlRequest?.url?.lastPathComponent,
let decodedUser = LDUser(base64urlEncodedString: encodedUserString) {
expect(decodedUser.isEqual(to: testContext.user)) == true
} else {
fail("encoded user string did not create a user")
}
let expectedUser = testContext.user.dictionaryValue(includePrivateAttributes: true, config: testContext.config)
expect(AnyComparer.isEqual(urlRequest?.url?.lastPathComponent.jsonDictionary, to: expectedUser)) == true
} else {
fail("request path is missing")
}
Expand Down Expand Up @@ -555,7 +547,8 @@ final class DarklyServiceSpec: QuickSpec {
let receivedArguments = testContext.serviceFactoryMock.makeStreamingProviderReceivedArguments
expect(receivedArguments!.url.host) == testContext.config.streamUrl.host
expect(receivedArguments!.url.pathComponents.contains(DarklyService.StreamRequestPath.meval)).to(beTrue())
expect(LDUser(base64urlEncodedString: receivedArguments!.url.lastPathComponent)?.isEqual(to: testContext.user)) == true
let expectedUser = testContext.user.dictionaryValue(includePrivateAttributes: true, config: testContext.config)
expect(AnyComparer.isEqual(receivedArguments!.url.lastPathComponent.jsonDictionary, to: expectedUser)) == true
expect(receivedArguments!.httpHeaders).toNot(beEmpty())
expect(receivedArguments!.connectMethod).to(be("GET"))
expect(receivedArguments!.connectBody).to(beNil())
Expand All @@ -575,7 +568,8 @@ final class DarklyServiceSpec: QuickSpec {
expect(receivedArguments!.url.lastPathComponent) == DarklyService.StreamRequestPath.meval
expect(receivedArguments!.httpHeaders).toNot(beEmpty())
expect(receivedArguments!.connectMethod) == DarklyService.HTTPRequestMethod.report
expect(LDUser(data: receivedArguments!.connectBody)?.isEqual(to: testContext.user)) == true
let expectedUser = testContext.user.dictionaryValue(includePrivateAttributes: true, config: testContext.config)
expect(AnyComparer.isEqual(receivedArguments!.connectBody?.jsonDictionary, to: expectedUser)) == true
}
}
}
Expand Down Expand Up @@ -796,16 +790,9 @@ private extension Data {
}
}

extension LDUser {
init?(base64urlEncodedString: String) {
let base64encodedString = base64urlEncodedString.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
self.init(data: Data(base64Encoded: base64encodedString))
}

init?(data: Data?) {
guard let data = data,
let userDictionary = try? JSONSerialization.jsonDictionary(with: data)
else { return nil }
self.init(userDictionary: userDictionary)
private extension String {
var jsonDictionary: [String: Any]? {
let base64encodedString = self.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/")
return Data(base64Encoded: base64encodedString)?.jsonDictionary
}
}

0 comments on commit ec8c2cd

Please sign in to comment.