Add merge status tests (#1604)

* Add merge status tests

* Introduce containsAll and containsNone

* Rename containsAll to containsOnly
This commit is contained in:
Bas Broek
2018-03-05 03:36:25 +01:00
committed by Ryan Nystrom
parent 45335eb4a0
commit ddddb6363f
7 changed files with 250 additions and 26 deletions

View File

@@ -73,7 +73,7 @@ MergeButtonDelegate {
if object.contexts.count > 0 {
let states = object.contexts.map { $0.state }
let (state, stateDescription) = combinedMergeStatus(for: states)
let (state, stateDescription) = MergeHelper.combinedMergeStatus(for: states)
viewModels.append(IssueMergeSummaryModel(title: stateDescription, state: state))
}
@@ -184,28 +184,4 @@ MergeButtonDelegate {
viewController?.present(alert, animated: trueUnlessReduceMotionEnabled)
}
// MARK: Private
private func combinedMergeStatus(for states: [StatusState]) -> (IssueMergeSummaryModel.State, String) {
let state: IssueMergeSummaryModel.State
let stateDescription: String
let failureDescription = NSLocalizedString("Some checks failed", comment: "")
switch states {
case let states where states.contains(.failure) || states.contains(.error):
state = .failure
stateDescription = failureDescription
case let states where states.contains(.pending):
state = .pending
stateDescription = NSLocalizedString("Merge status pending", comment: "")
case let states where states.reduce(true, { $0 && $1 == .success }):
state = .success
stateDescription = NSLocalizedString("All checks passed", comment: "")
default:
assert(false, "This should only occur when any of the `states` are of type `.expected`, which we have no clue of when it is used. The documentation (https://developer.github.com/v4/enum/statusstate/) doesn't answer that question either.")
state = .failure
stateDescription = failureDescription
}
return (state, stateDescription)
}
}

View File

@@ -0,0 +1,35 @@
//
// MergeHelper.swift
// FreetimeTests
//
// Created by Bas Broek on 03/03/2018.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
enum MergeHelper {
static func combinedMergeStatus(for states: [StatusState]) -> (state: IssueMergeSummaryModel.State, description: String) {
assert(!states.isEmpty, "Should only check merge status when there is at least one state")
let state: IssueMergeSummaryModel.State
let stateDescription: String
let failureDescription = NSLocalizedString("Some checks failed", comment: "")
switch states {
case let states where states.contains(.failure) || states.contains(.error):
state = .failure
stateDescription = failureDescription
case let states where states.contains(.pending):
state = .pending
stateDescription = NSLocalizedString("Merge status pending", comment: "")
case let states where states.containsOnly(.success):
state = .success
stateDescription = NSLocalizedString("All checks passed", comment: "")
default:
assert(false, "This should only occur when any of the `states` are of type `.expected`, which we have no clue of when it is used. The documentation (https://developer.github.com/v4/enum/statusstate/) doesn't answer that question either.")
state = .failure
stateDescription = failureDescription
}
return (state, stateDescription)
}
}

View File

@@ -0,0 +1,57 @@
//
// Sequence+Contains.swift
// Freetime
//
// Created by Bas Broek on 03/03/2018.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
extension Sequence where Element: Equatable {
/// Returns a Boolean value indicating whether every element of the sequence
/// is equal to the given element.
func containsOnly(_ element: Element) -> Bool {
var iterator = self.makeIterator()
guard iterator.next() != nil else { return false }
return first(where: { $0 != element }) == nil
}
/// Returns a Boolean value indicating whether every element of the sequence
/// does not equal to the given element.
func containsNone(_ element: Element) -> Bool {
return first(where: { $0 == element }) == nil
}
}
extension Sequence {
/// Returns a Boolean value indicating whether every element of the sequence
/// satisfies the given predicate.
func containsOnly(where predicate: (Element) throws -> Bool) rethrows -> Bool {
var iterator = self.makeIterator()
var isNotEmpty = false
while let element = iterator.next() {
isNotEmpty = true
if try !predicate(element) {
return false
}
}
return isNotEmpty
}
/// Returns a Boolean value indicating whether every element of the sequence
/// does not satisfies the given predicate.
func containsNone(where predicate: (Element) throws -> Bool) rethrows -> Bool {
var iterator = self.makeIterator()
while let element = iterator.next() {
if try predicate(element) {
return false
}
}
return true
}
}

View File

@@ -20,7 +20,7 @@ extension UIViewController {
}
// dismiss if all text entries are empty
let canDismissNow = texts.reduce(true) { $0 && ($1 == nil || $1!.isEmpty) }
let canDismissNow = texts.containsOnly { $0 == nil || $0!.isEmpty }
if canDismissNow {
dismissBlock()
} else {

View File

@@ -360,7 +360,11 @@
3E79A2FF1F8A7DA700E1126B /* ShortcutHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E79A2FE1F8A7DA700E1126B /* ShortcutHandler.swift */; };
45A9D03A1F9D3D9600FD5AEF /* AttributedStringViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A9D0391F9D3D9600FD5AEF /* AttributedStringViewTests.swift */; };
4920F1A81F72E27200131E9D /* UIViewController+UserActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4920F1A71F72E27200131E9D /* UIViewController+UserActivity.swift */; };
49AF91B1204B416500DFF325 /* MergeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49AF91B0204B416500DFF325 /* MergeTests.swift */; };
49AF91B4204B4B6A00DFF325 /* MergeHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49AF91B2204B4A6000DFF325 /* MergeHelper.swift */; };
49D029001F91D90C00E39094 /* ReactionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D028FF1F91D90C00E39094 /* ReactionTests.swift */; };
49FE18FD204B5D32001681E8 /* Sequence+Contains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FE18FC204B5D32001681E8 /* Sequence+Contains.swift */; };
49FE18FF204B6508001681E8 /* SequenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FE18FE204B6508001681E8 /* SequenceTests.swift */; };
49FFF4341F9FC83200335568 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FFF4331F9FC83200335568 /* HapticFeedback.swift */; };
54AD5E8E1F24D953004A4BD6 /* FeedSelectionProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54AD5E8D1F24D953004A4BD6 /* FeedSelectionProviding.swift */; };
5DB4DD471FC5C10000DF7ABF /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB4DD461FC5C10000DF7ABF /* Accessibility.swift */; };
@@ -801,7 +805,11 @@
3E79A2FE1F8A7DA700E1126B /* ShortcutHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutHandler.swift; sourceTree = "<group>"; };
45A9D0391F9D3D9600FD5AEF /* AttributedStringViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedStringViewTests.swift; sourceTree = "<group>"; };
4920F1A71F72E27200131E9D /* UIViewController+UserActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+UserActivity.swift"; sourceTree = "<group>"; };
49AF91B0204B416500DFF325 /* MergeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MergeTests.swift; sourceTree = "<group>"; };
49AF91B2204B4A6000DFF325 /* MergeHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MergeHelper.swift; sourceTree = "<group>"; };
49D028FF1F91D90C00E39094 /* ReactionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionTests.swift; sourceTree = "<group>"; };
49FE18FC204B5D32001681E8 /* Sequence+Contains.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sequence+Contains.swift"; sourceTree = "<group>"; };
49FE18FE204B6508001681E8 /* SequenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SequenceTests.swift; sourceTree = "<group>"; };
49FFF4331F9FC83200335568 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticFeedback.swift; sourceTree = "<group>"; };
516CF27F9258BBD3E034F09D /* Pods_FreetimeTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FreetimeTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
54AD5E8D1F24D953004A4BD6 /* FeedSelectionProviding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedSelectionProviding.swift; sourceTree = "<group>"; };
@@ -1340,6 +1348,8 @@
DC60C6D21F983BB900241271 /* SignatureTests.swift */,
45A9D0381F9D3D6A00FD5AEF /* Snapshot Tests */,
29EDFE7B1F65C580005BCCEB /* SplitViewTests.swift */,
49AF91B0204B416500DFF325 /* MergeTests.swift */,
49FE18FE204B6508001681E8 /* SequenceTests.swift */,
295F52A61EF1B9D2000B53CF /* Test.md */,
);
path = FreetimeTests;
@@ -1599,6 +1609,7 @@
2999972720310F3100995FFD /* IssueMergeContextModel.swift */,
2999972520310E9700995FFD /* IssueMergeModel.swift */,
2999972920311B3800995FFD /* IssueMergeSectionController.swift */,
49AF91B2204B4A6000DFF325 /* MergeHelper.swift */,
2999972B20311DD700995FFD /* IssueMergeSummaryCell.swift */,
299997312031242500995FFD /* IssueMergeSummaryModel.swift */,
299997372031DEB300995FFD /* IssueMergeType.swift */,
@@ -1818,6 +1829,7 @@
754488B01F7ADF8D0032D08C /* UIAlertController+Action.swift */,
98835BCD1F1965E2005BA24F /* UIDevice+Model.swift */,
98B5A0851F6D0FFE000617D6 /* UINavigationController+Replace.swift */,
49FE18FC204B5D32001681E8 /* Sequence+Contains.swift */,
);
path = Utility;
sourceTree = "<group>";
@@ -2324,6 +2336,7 @@
291929551F3FAADF0012067B /* FeedRefresh.swift in Sources */,
2993046F1FBA9D31007B9737 /* IssueManagingActionCell.swift in Sources */,
54AD5E8E1F24D953004A4BD6 /* FeedSelectionProviding.swift in Sources */,
49FE18FD204B5D32001681E8 /* Sequence+Contains.swift in Sources */,
291929421F3EA8CD0012067B /* File.swift in Sources */,
299E86491EFD9DBB00E5FE70 /* FlexController.m in Sources */,
29EB1EEF1F425E5100A200B4 /* ForegroundHandler.swift in Sources */,
@@ -2617,6 +2630,7 @@
29B94E6F1FCB743900715D7E /* RepositoryFileCell.swift in Sources */,
29459A711FE7153500034A04 /* LogEnvironmentInformation.swift in Sources */,
295B51441FC26C5400C3993B /* PeopleViewController.swift in Sources */,
49AF91B4204B4B6A00DFF325 /* MergeHelper.swift in Sources */,
2930F2731F8A27750082BA26 /* WidthCache.swift in Sources */,
2971722B1F069E6B005E43AC /* SpinnerSectionController.swift in Sources */,
2999972E203120E300995FFD /* IssueMergeButtonCell.swift in Sources */,
@@ -2681,6 +2695,7 @@
293A45771F296B7E00DD1006 /* ListKitTestCase.swift in Sources */,
DC5C02C51F9C6E3500E80B9F /* SearchQueryTests.swift in Sources */,
293A457E1F296BD500DD1006 /* API.swift in Sources */,
49AF91B1204B416500DFF325 /* MergeTests.swift in Sources */,
2986B35F1FD462B300E3CFC6 /* FilePath.swift in Sources */,
293A45781F296B7E00DD1006 /* ListTestKit.swift in Sources */,
296B4E341F7C80B800C16887 /* GraphQLIDDecodeTests.swift in Sources */,
@@ -2688,6 +2703,7 @@
DC60C6D31F983BB900241271 /* SignatureTests.swift in Sources */,
293A45791F296B7E00DD1006 /* MMMarkdownASTTests.swift in Sources */,
DC60C6D51F983DF800241271 /* IssueLabelCellTests.swift in Sources */,
49FE18FF204B6508001681E8 /* SequenceTests.swift in Sources */,
DC5C02C31F9C6D0B00E80B9F /* SearchRecentStoreTests.swift in Sources */,
9870B9081FC74E300009719C /* SecretsTests.swift in Sources */,
29EDFE7C1F65C580005BCCEB /* SplitViewTests.swift in Sources */,

View File

@@ -0,0 +1,76 @@
//
// MergeTests.swift
// FreetimeTests
//
// Created by Bas Broek on 03/03/2018.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import XCTest
@testable import Freetime
class MergeTests: XCTestCase {
func test_mergeStatuses_containsOnlyError() {
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.error, .error, .error]).state,
.failure)
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.error]).state,
.failure)
}
func test_mergeStatuses_containsError() {
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.error, .failure]).state,
.failure)
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.error, .pending]).state,
.failure)
}
func test_mergeStatuses_containsOnlyFailure() {
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.failure, .failure, .failure]).state,
.failure)
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.failure]).state,
.failure)
}
func test_mergeStatuses_containsFailure() {
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.failure, .success]).state,
.failure)
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.failure, .pending]).state,
.failure)
}
func test_mergeStatuses_containsFailure_andError() {
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.error, .failure]).state,
.failure)
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.failure, .error]).state,
.failure)
}
func test_mergeStatuses_containsPending_butNoErrorOrFailure() {
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.pending, .pending, .pending]).state,
.pending)
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.pending, .success]).state,
.pending)
}
func test_mergeStatuses_containsOnlySuccess() {
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.success, .success]).state,
.success)
XCTAssertEqual(
MergeHelper.combinedMergeStatus(for: [.success]).state,
.success)
}
}

View File

@@ -0,0 +1,64 @@
//
// SequenceTests.swift
// FreetimeTests
//
// Created by Bas Broek on 04/03/2018.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import XCTest
@testable import Freetime
class SequenceTests: XCTestCase {
func test_containsAll() {
XCTAssertTrue(["a", "a", "a"].containsOnly("a"))
XCTAssertFalse(["b", "a", "a"].containsOnly("a"))
XCTAssertFalse(["a", "a", "a"].containsOnly("b"))
XCTAssertTrue(["a", "a", "a"].containsOnly { $0 == "a" })
XCTAssertFalse(["b", "a", "a"].containsOnly { $0 == "a" })
XCTAssertFalse(["a", "a", "a"].containsOnly { $0 == "b" })
XCTAssertTrue([1, 1, 1].containsOnly(1))
XCTAssertFalse([2, 1, 1].containsOnly(1))
XCTAssertFalse([1, 1, 1].containsOnly(2))
XCTAssertTrue([1, 1, 1].containsOnly { $0 == 1 })
XCTAssertFalse([2, 1, 1].containsOnly { $0 == 1 })
XCTAssertFalse([1, 1, 1].containsOnly { $0 == 2 })
}
func test_containsNone() {
XCTAssertFalse(["a", "a", "a"].containsNone("a"))
XCTAssertFalse(["b", "a", "a"].containsNone("a"))
XCTAssertTrue(["a", "a", "a"].containsNone("b"))
XCTAssertFalse(["a", "a", "a"].containsNone { $0 == "a" })
XCTAssertFalse(["b", "a", "a"].containsNone { $0 == "a" })
XCTAssertTrue(["a", "a", "a"].containsNone { $0 == "b" })
XCTAssertFalse([1, 1, 1].containsNone(1))
XCTAssertFalse([2, 1, 1].containsNone(1))
XCTAssertTrue([1, 1, 1].containsNone(2))
XCTAssertFalse([1, 1, 1].containsNone { $0 == 1 })
XCTAssertFalse([2, 1, 1].containsNone { $0 == 1 })
XCTAssertTrue([1, 1, 1].containsNone { $0 == 2 })
}
func test_emptySequence() {
let emptyStrings: [String] = []
let emptyInts: [Int] = []
XCTAssertTrue(emptyStrings.containsNone("a"))
XCTAssertTrue(emptyStrings.containsNone { $0 == "a" })
XCTAssertFalse(emptyStrings.containsOnly("a"))
XCTAssertFalse(emptyStrings.containsOnly { $0 == "a" })
XCTAssertTrue(emptyInts.containsNone(1))
XCTAssertTrue(emptyInts.containsNone { $0 == 1 })
XCTAssertFalse(emptyInts.containsOnly(1))
XCTAssertFalse(emptyInts.containsOnly { $0 == 1 })
}
}