From 213234f57e76f32bf65a2c35260fb786a8bae13e Mon Sep 17 00:00:00 2001 From: Danny Moesch Date: Sun, 17 Jun 2018 16:41:14 +0200 Subject: [PATCH] Add unit tests for "key: value" syntax in Password class --- pass.xcodeproj/project.pbxproj | 4 + passKitTests/PasswordTests.swift | 271 +++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 passKitTests/PasswordTests.swift diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index dbb9a6f..23f9f07 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 18F19A67B0C07F13C17169E0 /* Pods_pass.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A5620D17DF5E86B61761D0E /* Pods_pass.framework */; }; 23B82F0228254275DBA609E7 /* Pods_passExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B975797E0F0B7476CADD6A7D /* Pods_passExtension.framework */; }; 3012B06D2039D6E400BE1793 /* Yams.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3012B06C2039D6E400BE1793 /* Yams.framework */; }; + 30B04860209A5141001013CA /* PasswordTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30B0485F209A5141001013CA /* PasswordTests.swift */; }; 61326CDA7A73757FB68DCB04 /* Pods_passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB3F5541E51ADC8C6B56642 /* Pods_passKit.framework */; }; A20691F41F2A3D0E0096483D /* SecurePasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20691F31F2A3D0E0096483D /* SecurePasteboard.swift */; }; A2168A7F1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2168A7E1EFD40D5005EA873 /* OnePasswordExtensionConstants.swift */; }; @@ -160,6 +161,7 @@ /* Begin PBXFileReference section */ 3012B06C2039D6E400BE1793 /* Yams.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Yams.framework; path = Carthage/Build/iOS/Yams.framework; sourceTree = ""; }; + 30B0485F209A5141001013CA /* PasswordTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordTests.swift; sourceTree = ""; }; 31C3033E8868D05B2C55C8B1 /* Pods-passExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-passExtension/Pods-passExtension.debug.xcconfig"; sourceTree = ""; }; 3A5620D17DF5E86B61761D0E /* Pods_pass.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_pass.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 666769E0B255666D02945C15 /* Pods-passKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-passKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-passKitTests/Pods-passKitTests.release.xcconfig"; sourceTree = ""; }; @@ -364,6 +366,7 @@ children = ( A26075871EEC6F34005DB03E /* passKitTests.swift */, A26075891EEC6F34005DB03E /* Info.plist */, + 30B0485F209A5141001013CA /* PasswordTests.swift */, ); path = passKitTests; sourceTree = ""; @@ -993,6 +996,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 30B04860209A5141001013CA /* PasswordTests.swift in Sources */, A26075881EEC6F34005DB03E /* passKitTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/passKitTests/PasswordTests.swift b/passKitTests/PasswordTests.swift new file mode 100644 index 0000000..47801e8 --- /dev/null +++ b/passKitTests/PasswordTests.swift @@ -0,0 +1,271 @@ +// +// PasswordTests.swift +// passKitTests +// +// Created by Danny Mösch on 02.05.18. +// Copyright © 2018 Bob Sun. All rights reserved. +// + +import XCTest +@testable import passKit + +class PasswordTest: XCTestCase { + static let EMPTY_STRING = "" + static let PASSWORD_NAME = "password" + static let PASSWORD_PATH = "/path/to/\(PASSWORD_NAME)" + static let PASSWORD_URL = URL(fileURLWithPath: PASSWORD_PATH) + static let PASSWORD_STRING = "abcd1234" + static let OTP_TOKEN = "otpauth://totp/email@email.com?secret=abcd1234" + + static let SECURE_URL_FIELD = AdditionField(title: "url", content: "https://secure.com") + static let INSECURE_URL_FIELD = AdditionField(title: "url", content: "http://insecure.com") + static let LOGIN_FIELD = AdditionField(title: "login", content: "login name") + static let USERNAME_FIELD = AdditionField(title: "username", content: "some username") + static let NOTE_FIELD = AdditionField(title: "note", content: "A NOTE") + + func testUrl() { + let password1 = getPasswordObjectWith(content: PasswordTest.EMPTY_STRING) + XCTAssertEqual(password1.namePath, PasswordTest.PASSWORD_PATH) + + let password2 = getPasswordObjectWith(content: PasswordTest.EMPTY_STRING, url: nil) + XCTAssertEqual(password2.namePath, PasswordTest.EMPTY_STRING) + } + + func testLooksLikeOTP() { + XCTAssertTrue(Password.LooksLikeOTP(line: PasswordTest.OTP_TOKEN)) + XCTAssertFalse(Password.LooksLikeOTP(line: "no_auth://totp/blabla")) + } + + func testEmptyFile() { + let fileContent = PasswordTest.EMPTY_STRING + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, PasswordTest.EMPTY_STRING) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + + XCTAssertEqual(password.getAdditionsPlainText(), PasswordTest.EMPTY_STRING) + XCTAssertTrue(password.getFilteredAdditions().isEmpty) + + XCTAssertNil(password.getUsername()) + XCTAssertNil(password.getURLString()) + XCTAssertNil(password.getLogin()) + } + + func testOneEmptyLine() { + let fileContent = """ + + """ + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, PasswordTest.EMPTY_STRING) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + + XCTAssertEqual(password.getAdditionsPlainText(), PasswordTest.EMPTY_STRING) + XCTAssertTrue(password.getFilteredAdditions().isEmpty) + + XCTAssertNil(password.getUsername()) + XCTAssertNil(password.getURLString()) + XCTAssertNil(password.getLogin()) + } + + func testSimplePasswordFile() { + let passwordString = PasswordTest.PASSWORD_STRING + let urlField = PasswordTest.SECURE_URL_FIELD + let loginField = PasswordTest.LOGIN_FIELD + let usernameField = PasswordTest.USERNAME_FIELD + let noteField = PasswordTest.NOTE_FIELD + let fileContent = """ + \(passwordString) + \(urlField.asString) + \(loginField.asString) + \(usernameField.asString) + \(noteField.asString) + """ + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, passwordString) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + + XCTAssertEqual(password.getAdditionsPlainText(), asPlainText(urlField, loginField, usernameField, noteField)) + XCTAssertTrue(does(password: password, contain: urlField)) + XCTAssertFalse(does(password: password, contain: loginField)) + XCTAssertFalse(does(password: password, contain: usernameField)) + XCTAssertTrue(does(password: password, contain: noteField)) + + XCTAssertEqual(password.getURLString(), urlField.content) + XCTAssertEqual(password.getLogin(), loginField.content) + XCTAssertEqual(password.getUsername(), usernameField.content) + } + + func testTwoPasswords() { + let firstPasswordString = PasswordTest.PASSWORD_STRING + let secondPasswordString = "efgh5678" + let urlField = PasswordTest.INSECURE_URL_FIELD + let fileContent = """ + \(firstPasswordString) + \(secondPasswordString) + \(urlField.asString) + """ + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, firstPasswordString) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + XCTAssertEqual(password.getAdditionsPlainText(), asPlainText(secondPasswordString, urlField.asString)) + + XCTAssertTrue(does(password: password, contain: urlField)) + XCTAssertTrue(does(password: password, contain: AdditionField(title: "unknown 1", content: secondPasswordString))) + + XCTAssertNil(password.getUsername()) + XCTAssertEqual(password.getURLString(), urlField.content) + XCTAssertNil(password.getLogin()) + } + + func testNoPassword() { + let urlField = PasswordTest.SECURE_URL_FIELD + let noteField = PasswordTest.NOTE_FIELD + let fileContent = """ + \(urlField.asString) + \(noteField.asString) + """ + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, urlField.asString) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + + XCTAssertEqual(password.getAdditionsPlainText(), asPlainText(noteField)) + XCTAssertTrue(does(password: password, contain: noteField)) + + XCTAssertNil(password.getUsername()) + XCTAssertNil(password.getURLString()) + XCTAssertNil(password.getLogin()) + } + + func testDuplicateKeys() { + let passwordString = PasswordTest.PASSWORD_STRING + let urlField1 = PasswordTest.SECURE_URL_FIELD + let urlField2 = PasswordTest.INSECURE_URL_FIELD + let fileContent = """ + \(passwordString) + \(urlField1.asString) + \(urlField2.asString) + """ + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, passwordString) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + + XCTAssertEqual(password.getAdditionsPlainText(), asPlainText(urlField1, urlField2)) + XCTAssertTrue(does(password: password, contain: urlField1)) + XCTAssertTrue(does(password: password, contain: urlField2)) + + XCTAssertNil(password.getUsername()) + XCTAssertEqual(password.getURLString(), urlField1.content) + XCTAssertNil(password.getLogin()) + } + + func testUnknownKeys() { + let passwordString = PasswordTest.PASSWORD_STRING + let value1 = "value 1" + let value2 = "value 2" + let value3 = "value 3" + let value4 = "value 4" + let noteField = PasswordTest.NOTE_FIELD + let urlField = PasswordTest.SECURE_URL_FIELD + let fileContent = """ + \(passwordString) + \(value1) + \(noteField.asString) + \(value2) + \(value3) + \(urlField.asString) + \(value4) + """ + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, passwordString) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + + XCTAssertEqual(password.getAdditionsPlainText(), asPlainText(value1, noteField.asString, value2, value3, urlField.asString, value4)) + XCTAssertTrue(does(password: password, contain: AdditionField(title: "unknown 1", content: value1))) + XCTAssertTrue(does(password: password, contain: noteField)) + XCTAssertTrue(does(password: password, contain: AdditionField(title: "unknown 2", content: value2))) + XCTAssertTrue(does(password: password, contain: AdditionField(title: "unknown 3", content: value3))) + XCTAssertTrue(does(password: password, contain: urlField)) + XCTAssertTrue(does(password: password, contain: AdditionField(title: "unknown 4", content: value4))) + + XCTAssertNil(password.getUsername()) + XCTAssertEqual(password.getURLString(), urlField.content) + XCTAssertNil(password.getLogin()) + } + + func testPasswordFileWithOtpToken() { + let passwordString = PasswordTest.PASSWORD_STRING + let noteField = PasswordTest.NOTE_FIELD + let otpToken = PasswordTest.OTP_TOKEN + let fileContent = """ + \(passwordString) + \(noteField.asString) + \(otpToken) + """ + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, passwordString) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + + XCTAssertEqual(password.getAdditionsPlainText(), asPlainText(noteField.asString, otpToken)) + + XCTAssertEqual(password.otpType, Password.OtpType.totp) + XCTAssertNotNil(password.getOtp()) + } + + func testFirstLineIsOtpToken() { + let otpToken = PasswordTest.OTP_TOKEN + let fileContent = """ + \(otpToken) + """ + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, otpToken) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + + XCTAssertEqual(password.getAdditionsPlainText(), PasswordTest.EMPTY_STRING) + + XCTAssertNil(password.getUsername()) + XCTAssertNil(password.getURLString()) + XCTAssertNil(password.getLogin()) + + XCTAssertEqual(password.otpType, Password.OtpType.totp) + XCTAssertNotNil(password.getOtp()) + } + + func testWrongOtpToken() { + let otpToken = "otpauth://htop/blabla" + let fileContent = """ + \(otpToken) + """ + let password = getPasswordObjectWith(content: fileContent) + + XCTAssertEqual(password.password, otpToken) + XCTAssertEqual(password.getPlainData(), fileContent.data(using: .utf8)) + + XCTAssertEqual(password.getAdditionsPlainText(), PasswordTest.EMPTY_STRING) + + XCTAssertEqual(password.otpType, Password.OtpType.none) + XCTAssertNil(password.getOtp()) + } + + private func getPasswordObjectWith(content: String, url: URL? = PasswordTest.PASSWORD_URL) -> Password { + return Password(name: PasswordTest.PASSWORD_NAME, url: url, plainText: content) + } + + private func does(password: Password, contain field: AdditionField) -> Bool { + return password.getFilteredAdditions().contains(field) + } + + private func asPlainText(_ strings: String...) -> String { + return strings.joined(separator: "\n") + } + private func asPlainText(_ fields: AdditionField...) -> String { + return fields.map { $0.asString }.joined(separator: "\n") + } +}