Skip to content

Commit

Permalink
DynamicSubject fixes and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
srdanrasic committed Sep 22, 2016
1 parent 8c879c8 commit 69659aa
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 9 deletions.
6 changes: 3 additions & 3 deletions Bond.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|

s.name = "Bond"
s.version = "5.0.0-beta6"
s.version = "5.0.0-beta7"
s.summary = "A Swift binding framework"

s.description = <<-DESC
Expand All @@ -21,12 +21,12 @@ Pod::Spec.new do |s|
s.ios.deployment_target = "8.0"
s.osx.deployment_target = "10.10"
s.tvos.deployment_target = '9.0'
s.source = { :git => "https://github.com/SwiftBond/Bond.git", :tag => "v5.0.0-beta6" }
s.source = { :git => "https://github.com/SwiftBond/Bond.git", :tag => "v5.0.0-beta7" }
s.source_files = 'Sources/**/*.swift', 'Bond/*.{h,m,swift}'
s.ios.exclude_files = "Sources/AppKit"
s.tvos.exclude_files = "Sources/AppKit"
s.osx.exclude_files = "Sources/UIKit"
s.requires_arc = true

s.dependency 'ReactiveKit', '~> 3.0.0-beta4'
s.dependency 'ReactiveKit', '~> 3.0.0-beta5'
end
10 changes: 9 additions & 1 deletion Bond.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
ECC4BE591D4A2E1600880DEC /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC4BE581D4A2E1600880DEC /* UIButton.swift */; };
ECCF8A521D8FFEF300575DA8 /* ObservableArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECCF8A511D8FFEF300575DA8 /* ObservableArrayTests.swift */; };
ECCF8A581D9007AF00575DA8 /* BondTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECCF8A571D9007AF00575DA8 /* BondTests.swift */; };
ECD5940A1D93EC9700C840C2 /* DynamicSubjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD594091D93EC9700C840C2 /* DynamicSubjectTests.swift */; };
ECD626E91D4DE8800040C7BF /* UIActivityIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD626E81D4DE8800040C7BF /* UIActivityIndicatorView.swift */; };
ECD626EB1D4DE9460040C7BF /* UIBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD626EA1D4DE9460040C7BF /* UIBarItem.swift */; };
ECD626ED1D4DE9BE0040C7BF /* UIBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD626EC1D4DE9BE0040C7BF /* UIBarButtonItem.swift */; };
Expand Down Expand Up @@ -259,6 +260,9 @@
ECC4BE581D4A2E1600880DEC /* UIButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButton.swift; sourceTree = "<group>"; };
ECCF8A511D8FFEF300575DA8 /* ObservableArrayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObservableArrayTests.swift; sourceTree = "<group>"; };
ECCF8A571D9007AF00575DA8 /* BondTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BondTests.swift; sourceTree = "<group>"; };
ECD594091D93EC9700C840C2 /* DynamicSubjectTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicSubjectTests.swift; sourceTree = "<group>"; };
ECD5940B1D93F2E400C840C2 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = "<group>"; };
ECD5940C1D93F2ED00C840C2 /* Bond.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = Bond.podspec; sourceTree = "<group>"; };
ECD626E81D4DE8800040C7BF /* UIActivityIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIActivityIndicatorView.swift; sourceTree = "<group>"; };
ECD626EA1D4DE9460040C7BF /* UIBarItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIBarItem.swift; sourceTree = "<group>"; };
ECD626EC1D4DE9BE0040C7BF /* UIBarButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIBarButtonItem.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -323,6 +327,8 @@
16210A321D3EC474004AEDF3 = {
isa = PBXGroup;
children = (
ECD5940B1D93F2E400C840C2 /* Cartfile */,
ECD5940C1D93F2ED00C840C2 /* Bond.podspec */,
161D6D2D1D6F0D92004CA17D /* README.md */,
EC7890ED1D44F1BF002848EB /* Bond.h */,
EC7890EE1D44F1BF002848EB /* Info.plist */,
Expand Down Expand Up @@ -375,10 +381,11 @@
16210A491D3EC474004AEDF3 /* BondTests */ = {
isa = PBXGroup;
children = (
16210A4A1D3EC474004AEDF3 /* UIKitTests.swift */,
ECCF8A571D9007AF00575DA8 /* BondTests.swift */,
ECD594091D93EC9700C840C2 /* DynamicSubjectTests.swift */,
ECCF8A511D8FFEF300575DA8 /* ObservableArrayTests.swift */,
16887E2F1D74499A00EDA099 /* ProtocolProxyTests.swift */,
16210A4A1D3EC474004AEDF3 /* UIKitTests.swift */,
16887E311D744A1400EDA099 /* Helpers.swift */,
16210A4C1D3EC474004AEDF3 /* Info.plist */,
);
Expand Down Expand Up @@ -774,6 +781,7 @@
files = (
ECCF8A521D8FFEF300575DA8 /* ObservableArrayTests.swift in Sources */,
16887E301D74499A00EDA099 /* ProtocolProxyTests.swift in Sources */,
ECD5940A1D93EC9700C840C2 /* DynamicSubjectTests.swift in Sources */,
ECCF8A581D9007AF00575DA8 /* BondTests.swift in Sources */,
16887E321D744A1400EDA099 /* Helpers.swift in Sources */,
16210A4B1D3EC474004AEDF3 /* UIKitTests.swift in Sources */,
Expand Down
3 changes: 2 additions & 1 deletion Bond.xcodeproj/xcshareddata/xcschemes/Bond-iOS.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
Expand Down
5 changes: 4 additions & 1 deletion BondTests/BondTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ import XCTest
import ReactiveKit
@testable import Bond

class DummyTarget: NSObject {
private class DummyTarget: NSObject {
var recordedElements: [Int] = []
}

class BondTypeTests: XCTestCase {

// Update closure is called on each next element
func testExecutes() {
let target = DummyTarget()
let bond = Bond<DummyTarget, Int>(target: target) { target, element in
Expand All @@ -26,6 +27,8 @@ class BondTypeTests: XCTestCase {
XCTAssert(target.recordedElements == [1, 2, 3])
}

// Target is weakly referenced
// Disposable is disposed when target is deallocated
func testDisposesOnTargetDeallocation() {
var target: DummyTarget! = DummyTarget()
weak var weakTarget = target
Expand Down
78 changes: 78 additions & 0 deletions BondTests/DynamicSubjectTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//
// DynamicSubjectTests.swift
// Bond
//
// Created by Srdan Rasic on 22/09/2016.
// Copyright © 2016 Swift Bond. All rights reserved.
//

import XCTest
import ReactiveKit
@testable import Bond

private class DummyTarget: NSObject {
var value: Int = 5
var recordedElements: [Int] = []
let changes = PublishSubject1<Void>()
}

class DynamicSubjectTests: XCTestCase {

// Starts with current value
// Update signal triggers next event
// Bound signal events are propagated
// Value property is being updated (set closure is called)
func testExecutes() {
let target = DummyTarget()
let subject = DynamicSubject(
target: target,
signal: target.changes.toSignal(),
get: { (target) -> Int in target.value },
set: { (target, new) in target.value = new; target.recordedElements.append(new) }
)

subject.expectNext([5, 6, 7, 1, 2, 3])
target.value = 6
target.changes.next()
XCTAssert(target.value == 6)

subject.on(.next(7))
XCTAssert(target.value == 7)

Signal1.sequence([1, 2, 3]).bind(to: subject)
XCTAssert(target.recordedElements == [7, 1, 2, 3])
XCTAssert(target.value == 3)
}

// Target is weakly referenced
// Disposable is disposed when target is deallocated
// Completed event is sent when target is deallocated
func testDisposesOnTargetDeallocation() {
var target: DummyTarget! = DummyTarget()
weak var weakTarget = target

let subject = DynamicSubject(
target: target,
signal: target.changes.toSignal(),
get: { (target) -> Int in target.value },
set: { (target, new) in target.value = new; target.recordedElements.append(new) }
)

let signal = PublishSubject1<Int>()
let disposable = signal.bind(to: subject)

subject.expect([.next(5), .next(1), .completed], expectation: expectation(description: "completed"))

signal.next(1)
XCTAssert(weakTarget != nil)
XCTAssert(disposable.isDisposed == false)
XCTAssert(target.recordedElements == [1])

target = nil
signal.next(2)
XCTAssert(weakTarget == nil)
XCTAssert(disposable.isDisposed == true)

waitForExpectations(timeout: 1, handler: nil)
}
}
6 changes: 3 additions & 3 deletions Sources/DynamicSubject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import Foundation

public struct DynamicSubject<Target: Deallocatable, Element>: SubjectProtocol, BindableProtocol {

private var target: Target?
private weak var target: Target?
private var signal: Signal<Void, NoError>
private let getter: (Target) -> Element
private let setter: (Target, Element) -> Void
Expand All @@ -53,13 +53,13 @@ public struct DynamicSubject<Target: Deallocatable, Element>: SubjectProtocol, B
public func observe(with observer: @escaping (Event<Element, NoError>) -> Void) -> Disposable {
guard let target = target else { observer(.completed); return NonDisposable.instance }
let getter = self.getter
return signal.merge(with: subject).map { [weak target] () -> Element? in
return signal.start(with: ()).merge(with: subject).map { [weak target] () -> Element? in
if let target = target {
return getter(target)
} else {
return nil
}
}.ignoreNil().observe(with: observer)
}.ignoreNil().take(until: target.bnd_deallocated).observe(with: observer)
}

public func bind(signal: Signal<Element, NoError>) -> Disposable {
Expand Down

0 comments on commit 69659aa

Please sign in to comment.