Skip to content

Commit

Permalink
TimePeriodChain – update append method implementation, add prepend me…
Browse files Browse the repository at this point in the history
…thod, add shift to method
  • Loading branch information
AsioOtus committed Mar 20, 2021
1 parent 8cfed3b commit d74cd6b
Show file tree
Hide file tree
Showing 2 changed files with 267 additions and 29 deletions.
105 changes: 76 additions & 29 deletions Sources/SwiftDate/TimePeriod/Groups/TimePeriodChain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,48 +28,71 @@ open class TimePeriodChain: TimePeriodGroup {
}

// MARK: - Chain Existence Manipulation

/**
* Append a TimePeriodProtocol to the periods array and update the Chain's
* beginning and end.
* Adds a period of equivalent length to the end of the chain, regardless of
* whether the period intersects with the chain or not.
*
* - parameter period: TimePeriodProtocol to add to the collection
*/
public func append(_ period: TimePeriodProtocol) {
let beginning = (periods.count > 0) ? periods.last!.end! : period.start

let newPeriod = TimePeriod(start: beginning!, duration: period.duration)
periods.append(newPeriod)

//Update updateExtremes
if periods.count == 1 {
start = period.start
end = period.end
} else {
end = end?.addingTimeInterval(period.duration)
guard isPeriodHasExtremes(period) else {
print("All TimePeriods in a TimePeriodChain must contain a defined start and end date")
return;
}

if let startDate = periods.last?.end! ?? period.start {
let newPeriod = TimePeriod(start: startDate, duration: period.duration)
periods.append(newPeriod)

updateExtremes()
}
}

/**
* Append a TimePeriodProtocol array to the periods array and update the Chain's
* beginning and end.
* Adds a periods of equivalent length of group to the end of the chain, regardless of
* whether the period intersects with the chain or not.
*
* - parameter periodArray: TimePeriodProtocol list to add to the collection
*/
public func append<G: TimePeriodGroup>(contentsOf group: G) {
for period in group.periods {
let beginning = (periods.count > 0) ? periods.last!.end! : period.start

let newPeriod = TimePeriod(start: beginning!, duration: period.duration)
periods.append(newPeriod)

//Update updateExtremes
if periods.count == 1 {
start = period.start
end = period.end
} else {
end = end?.addingTimeInterval(period.duration)
}
append(period)
}
}

/**
* Adds a period of equivalent length to the start of the chain, regardless of
* whether the period intersects with the chain or not.
*
* - parameter period: TimePeriodProtocol to add to the collection
*/
public func prepend(_ period: TimePeriodProtocol) {
guard isPeriodHasExtremes(period) else {
print("All TimePeriods in a TimePeriodChain must contain a defined start and end date")
return;
}

if let endDate = periods.first?.start! ?? period.end {
let startDate = endDate.addingTimeInterval(-period.duration)

let newPeriod = TimePeriod(start: startDate, duration: period.duration)
periods.insert(newPeriod, at: periods.startIndex)

updateExtremes()
}
}

/**
* Adds a periods of equivalent length of group to the start of the chain, regardless of
* whether the period intersects with the chain or not.
*
* - parameter periodArray: TimePeriodProtocol list to add to the collection
*/

public func prepend<G: TimePeriodGroup>(contentsOf group: G) {
for period in group.periods {
prepend(period)
}
}

Expand Down Expand Up @@ -138,6 +161,26 @@ open class TimePeriodChain: TimePeriodGroup {
start = start?.addingTimeInterval(duration)
end = end?.addingTimeInterval(duration)
}

/// Shifts chain's start date and all chain's periods to the given date
///
/// - Parameter date: The date to which the period's start is shifted
public func shiftStart(to date: DateInRegion) {
if let firstPeriodStart = periods.first?.start! {
let difference = date - firstPeriodStart
shift(by: difference)
}
}

/// Shifts chain's end date and all chain's periods to the given date
///
/// - Parameter date: The date to which the period's end is shifted
public func shiftEnd(to date: DateInRegion) {
if let firstPeriodEnd = periods.last?.end! {
let difference = date - firstPeriodEnd
shift(by: difference)
}
}

public override func map<T>(_ transform: (TimePeriodProtocol) throws -> T) rethrows -> [T] {
return try periods.map(transform)
Expand All @@ -163,5 +206,9 @@ open class TimePeriodChain: TimePeriodGroup {
start = periods.first?.start
end = periods.last?.end
}

internal func isPeriodHasExtremes (_ period: TimePeriodProtocol) -> Bool {
period.start != nil && period.end != nil
}

}
191 changes: 191 additions & 0 deletions Tests/SwiftDateTests/TestTimePeriodChain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,195 @@ class TestTimePeriodChain: XCTestCase {
XCTAssert(chain.end == periods.last!.end, "TimePeriodChain initial end not equals to source period end")
}

func testPrependPeriod () {
let period = TimePeriod(start: .init(year: 2020, month: 1, day: 1), end: .init(year: 2020, month: 1, day: 20))
let chain = TimePeriodChain(periods)

chain.prepend(period)

XCTAssert(
chain[0].start == DateInRegion(year: 2020, month: 1, day: 13),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[0].start!) – Expected: \(DateInRegion(year: 2020, month: 1, day: 13))"
)

XCTAssert(
chain[1].start == DateInRegion(year: 2020, month: 2, day: 1),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[1].start!) – Expected: \(DateInRegion(year: 2020, month: 2, day: 1))"
)

XCTAssert(
chain[2].start == DateInRegion(year: 2020, month: 3, day: 1),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[2].start!) – Expected: \(DateInRegion(year: 2020, month: 3, day: 1))"
)

XCTAssert(
chain[3].start == DateInRegion(year: 2020, month: 4, day: 1),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[3].start!) – Expected: \(DateInRegion(year: 2020, month: 4, day: 1))"
)

XCTAssert(
chain[4].start == DateInRegion(year: 2020, month: 5, day: 1),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[4].start!) – Expected: \(DateInRegion(year: 2020, month: 5, day: 1))"
)
}

func testPrependGroup () {
let testPeriods = [
TimePeriod(start: .init(year: 2019, month: 10, day: 1), end: .init(year: 2019, month: 10, day: 31)),
TimePeriod(start: .init(year: 2019, month: 11, day: 1), end: .init(year: 2019, month: 11, day: 30)),
TimePeriod(start: .init(year: 2019, month: 12, day: 1), end: .init(year: 2019, month: 12, day: 31)),
]
let group = TimePeriodGroup(testPeriods)
let chain = TimePeriodChain(periods)

chain.prepend(contentsOf: group)

XCTAssert(
chain[0].start == DateInRegion(year: 2019, month: 11, day: 4),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[0].start!) – Expected: \(DateInRegion(year: 2019, month: 11, day: 1))"
)

XCTAssert(
chain[1].start == DateInRegion(year: 2019, month: 12, day: 4),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[1].start!) – Expected: \(DateInRegion(year: 2019, month: 12, day: 4))"
)

XCTAssert(
chain[2].start == DateInRegion(year: 2020, month: 1, day: 2),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[2].start!) – Expected: \(DateInRegion(year: 2020, month: 1, day: 2))"
)

XCTAssert(
chain[3].start == DateInRegion(year: 2020, month: 2, day: 1),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[3].start!) – Expected: \(DateInRegion(year: 2020, month: 2, day: 1))"
)

XCTAssert(
chain[4].start == DateInRegion(year: 2020, month: 3, day: 1),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[4].start!) – Expected: \(DateInRegion(year: 2020, month: 3, day: 1))"
)

XCTAssert(
chain[5].start == DateInRegion(year: 2020, month: 4, day: 1),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[5].start!) – Expected: \(DateInRegion(year: 2020, month: 4, day: 1))"
)

XCTAssert(
chain[6].start == DateInRegion(year: 2020, month: 5, day: 1),
"Prepended TimePeriodChain contains unexpected period start date – Actual: \(chain[6].start!) – Expected: \(DateInRegion(year: 2020, month: 5, day: 1))"
)
}

func testAppendPeriod () {
let period = TimePeriod(start: .init(year: 2020, month: 1, day: 1), end: .init(year: 2020, month: 1, day: 20))
let chain = TimePeriodChain(periods)

chain.append(period)

XCTAssert(
chain[0].end == DateInRegion(year: 2020, month: 2, day: 28),
"Appended TimePeriodChain contains unexpected period end date – Actual: \(chain[0].end!) – Expected: \(DateInRegion(year: 2020, month: 2, day: 28))"
)

XCTAssert(
chain[1].end == DateInRegion(year: 2020, month: 3, day: 31),
"Appended TimePeriodChain contains unexpected period end date – Actual: \(chain[1].end!) – Expected: \(DateInRegion(year: 2020, month: 3, day: 31))"
)

XCTAssert(
chain[2].end == DateInRegion(year: 2020, month: 4, day: 30),
"Appended TimePeriodChain contains unexpected period end date – Actual: \(chain[2].end!) – Expected: \(DateInRegion(year: 2020, month: 4, day: 30))"
)

XCTAssert(
chain[3].end == DateInRegion(year: 2020, month: 5, day: 31),
"Appended TimePeriodChain contains unexpected period end date – Actual: \(chain[3].end!) – Expected: \(DateInRegion(year: 2020, month: 5, day: 31))"
)

XCTAssert(
chain[4].end == DateInRegion(year: 2020, month: 6, day: 19),
"Appended TimePeriodChain contains unexpected period end date – Actual: \(chain[4].end!) – Expected: \(DateInRegion(year: 2020, month: 6, day: 19))"
)
}

func testAppendGroup () {
let testPeriods = [
TimePeriod(start: .init(year: 2019, month: 10, day: 1), end: .init(year: 2019, month: 10, day: 31)),
TimePeriod(start: .init(year: 2019, month: 11, day: 1), end: .init(year: 2019, month: 11, day: 30)),
TimePeriod(start: .init(year: 2019, month: 12, day: 1), end: .init(year: 2019, month: 12, day: 31)),
]
let group = TimePeriodGroup(testPeriods)
let chain = TimePeriodChain(periods)

chain.append(contentsOf: group)

XCTAssert(
chain[0].end == DateInRegion(year: 2020, month: 2, day: 28),
"Prepended TimePeriodChain contains unexpected period end date – Actual: \(chain[0].end!) – Expected: \(DateInRegion(year: 2020, month: 2, day: 28))"
)

XCTAssert(
chain[1].end == DateInRegion(year: 2020, month: 3, day: 31),
"Prepended TimePeriodChain contains unexpected period end date – Actual: \(chain[1].end!) – Expected: \(DateInRegion(year: 2020, month: 3, day: 31))"
)

XCTAssert(
chain[2].end == DateInRegion(year: 2020, month: 4, day: 30),
"Prepended TimePeriodChain contains unexpected period end date – Actual: \(chain[2].end!) – Expected: \(DateInRegion(year: 2020, month: 4, day: 30))"
)

XCTAssert(
chain[3].end == DateInRegion(year: 2020, month: 5, day: 31),
"Prepended TimePeriodChain contains unexpected period end date – Actual: \(chain[3].end!) – Expected: \(DateInRegion(year: 2020, month: 5, day: 31))"
)

XCTAssert(
chain[4].end == DateInRegion(year: 2020, month: 6, day: 30),
"Prepended TimePeriodChain contains unexpected period end date – Actual: \(chain[4].end!) – Expected: \(DateInRegion(year: 2020, month: 6, day: 30))"
)

XCTAssert(
chain[5].end == DateInRegion(year: 2020, month: 7, day: 29),
"Prepended TimePeriodChain contains unexpected period end date – Actual: \(chain[5].end!) – Expected: \(DateInRegion(year: 2020, month: 7, day: 29))"
)

XCTAssert(
chain[6].end == DateInRegion(year: 2020, month: 8, day: 28),
"Prepended TimePeriodChain contains unexpected period end date – Actual: \(chain[6].end!) – Expected: \(DateInRegion(year: 2020, month: 8, day: 28))"
)
}

func testShiftStartToDate () {
let date = DateInRegion(year: 2020, month: 1, day: 1)
let chain = TimePeriodChain(periods)

chain.shiftStart(to: date)

XCTAssert(
chain.start == DateInRegion(year: 2020, month: 1, day: 1),
"Shifted TimePeriodChain has unexpected start date – Actual: \(chain.start!) – Expected: \(DateInRegion(year: 2020, month: 1, day: 1))"
)

XCTAssert(
chain.end == DateInRegion(year: 2020, month: 4, day: 30),
"Shifted TimePeriodChain has unexpected end date – Actual: \(chain.end!) – Expected: \(DateInRegion(year: 2020, month: 4, day: 30))"
)
}

func testShiftEndToDate () {
let date = DateInRegion(year: 2020, month: 1, day: 1)
let chain = TimePeriodChain(periods)

chain.shiftEnd(to: date)

XCTAssert(
chain.start == DateInRegion(year: 2019, month: 9, day: 3),
"Shifted TimePeriodChain has unexpected start date – Actual: \(chain.start!) – Expected: \(DateInRegion(year: 2019, month: 9, day: 3))"
)

XCTAssert(
chain.end == DateInRegion(year: 2020, month: 1, day: 1),
"Shifted TimePeriodChain has unexpected end date – Actual: \(chain.end!) – Expected: \(DateInRegion(year: 2020, month: 1, day: 1))"
)
}
}

0 comments on commit d74cd6b

Please sign in to comment.