You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
447 lines
21 KiB
447 lines
21 KiB
// Copyright © 2015 Abhishek Banthia |
|
|
|
import CoreModelKit |
|
|
|
@testable import Clocker |
|
import XCTest |
|
|
|
class ClockerUnitTests: XCTestCase { |
|
private let california = ["customLabel": "Test", |
|
"formattedAddress": "San Francisco", |
|
"place_id": "TestIdentifier", |
|
"timezoneID": "America/Los_Angeles", |
|
"nextUpdate": "", |
|
"latitude": "37.7749295", |
|
"longitude": "-122.4194155"] |
|
|
|
private let mumbai = ["customLabel": "Ghar", |
|
"formattedAddress": "Mumbai", |
|
"place_id": "ChIJwe1EZjDG5zsRaYxkjY_tpF0", |
|
"timezoneID": "Asia/Calcutta", |
|
"nextUpdate": "", |
|
"latitude": "19.0759837", |
|
"longitude": "72.8776559"] |
|
|
|
private let auckland = ["customLabel": "Auckland", |
|
"formattedAddress": "New Zealand", |
|
"place_id": "ChIJh5Z3Fw4gLG0RM0dqdeIY1rE", |
|
"timezoneID": "Pacific/Auckland", |
|
"nextUpdate": "", |
|
"latitude": "-40.900557", |
|
"longitude": "174.885971"] |
|
|
|
private let florida = ["customLabel": "Gainesville", |
|
"formattedAddress": "Florida", |
|
"place_id": "ChIJvypWkWV2wYgR0E7HW9MTLvc", |
|
"timezoneID": "America/New_York", |
|
"nextUpdate": "", |
|
"latitude": "27.664827", |
|
"longitude": "-81.5157535"] |
|
|
|
private let onlyTimezone: [String: Any] = ["timezoneID": "Africa/Algiers", |
|
"formattedAddress": "Africa/Algiers", |
|
"place_id": "", |
|
"customLabel": "", |
|
"latitude": "", |
|
"longitude": ""] |
|
|
|
private let omaha: [String: Any] = ["timezoneID": "America/Chicago", |
|
"formattedAddress": "Omaha", |
|
"place_id": "ChIJ7fwMtciNk4cRBLY3rk9NQkY", |
|
"customLabel": "", |
|
"latitude": "41.2565369", |
|
"longitude": "-95.9345034"] |
|
|
|
private var operations: TimezoneDataOperations { |
|
return TimezoneDataOperations(with: TimezoneData(with: mumbai), store: DataStore.shared()) |
|
} |
|
|
|
private var californiaOperations: TimezoneDataOperations { |
|
return TimezoneDataOperations(with: TimezoneData(with: california), store: DataStore.shared()) |
|
} |
|
|
|
private var floridaOperations: TimezoneDataOperations { |
|
return TimezoneDataOperations(with: TimezoneData(with: florida), store: DataStore.shared()) |
|
} |
|
|
|
private var aucklandOperations: TimezoneDataOperations { |
|
return TimezoneDataOperations(with: TimezoneData(with: auckland), store: DataStore.shared()) |
|
} |
|
|
|
private var omahaOperations: TimezoneDataOperations { |
|
return TimezoneDataOperations(with: TimezoneData(with: omaha), store: DataStore.shared()) |
|
} |
|
|
|
func testOverridingSecondsComponent_shouldHideSeconds() { |
|
let dummyDefaults = UserDefaults.standard |
|
dummyDefaults.set(NSNumber(value: 4), forKey: CLSelectedTimeZoneFormatKey) // 4 is 12 hour with seconds |
|
|
|
let timezoneObjects = [TimezoneData(with: mumbai), |
|
TimezoneData(with: auckland), |
|
TimezoneData(with: california)] |
|
|
|
timezoneObjects.forEach { |
|
let operationsObject = TimezoneDataOperations(with: $0, store: DataStore.shared()) |
|
let currentTime = operationsObject.time(with: 0) |
|
XCTAssert(currentTime.count == 8) // 8 includes 2 colons |
|
|
|
$0.setShouldOverrideGlobalTimeFormat(1) |
|
|
|
let newTime = operationsObject.time(with: 0) |
|
XCTAssert(newTime.count >= 7) // 5 includes colon |
|
} |
|
} |
|
|
|
func testAddingATimezoneToDefaults() { |
|
let timezoneData = TimezoneData(with: california) |
|
let currentFavourites = DataStore.shared().timezones() |
|
let oldCount = currentFavourites.count |
|
|
|
let operationsObject = TimezoneDataOperations(with: timezoneData, store: DataStore.shared()) |
|
operationsObject.saveObject() |
|
|
|
let newDefaults = DataStore.shared().timezones() |
|
|
|
XCTAssert(newDefaults.isEmpty == false) |
|
XCTAssert(newDefaults.count == oldCount + 1) |
|
} |
|
|
|
func testDecoding() { |
|
let timezone1 = TimezoneData.customObject(from: nil) |
|
XCTAssertNotNil(timezone1) |
|
|
|
let data = Data() |
|
let timezone2 = TimezoneData.customObject(from: data) |
|
XCTAssertNil(timezone2) |
|
} |
|
|
|
func testDescription() { |
|
let timezoneData = TimezoneData(with: california) |
|
XCTAssertFalse(timezoneData.description.isEmpty) |
|
XCTAssertFalse(timezoneData.debugDescription.isEmpty) |
|
} |
|
|
|
func testHashing() { |
|
let timezoneData = TimezoneData(with: california) |
|
XCTAssert(timezoneData.hash != -1) |
|
|
|
timezoneData.placeID = nil |
|
timezoneData.timezoneID = nil |
|
XCTAssert(timezoneData.hash == -1) |
|
} |
|
|
|
func testBadInputDictionaryForInitialization() { |
|
let badInput: [String: Any] = ["customLabel": "", |
|
"latitude": "41.2565369", |
|
"longitude": "-95.9345034"] |
|
let badTimezoneData = TimezoneData(with: badInput) |
|
XCTAssertEqual(badTimezoneData.placeID, "Error") |
|
XCTAssertEqual(badTimezoneData.timezoneID, "Error") |
|
XCTAssertEqual(badTimezoneData.formattedAddress, "Error") |
|
} |
|
|
|
func testDeletingATimezone() { |
|
var currentFavourites = DataStore.shared().timezones() |
|
// Check if timezone with test identifier is present. |
|
let filteredCount = currentFavourites.filter { |
|
let timezone = TimezoneData.customObject(from: $0) |
|
return timezone?.placeID == "TestIdentifier" |
|
} |
|
|
|
// California is absent. Add it! |
|
if filteredCount.count == 0 { |
|
let timezoneData = TimezoneData(with: california) |
|
let operationsObject = TimezoneDataOperations(with: timezoneData, store: DataStore.shared()) |
|
operationsObject.saveObject() |
|
} |
|
|
|
let oldCount = DataStore.shared().timezones().count |
|
|
|
currentFavourites = currentFavourites.filter { |
|
let timezone = TimezoneData.customObject(from: $0) |
|
return timezone?.placeID != "TestIdentifier" |
|
} |
|
|
|
DataStore.shared().setTimezones(currentFavourites) |
|
|
|
XCTAssertTrue(currentFavourites.count == oldCount - 1, "Current Favourites Count \(currentFavourites.count) and Old Count \(oldCount - 1) don't line up.") |
|
} |
|
|
|
// The below test might fail outside California or if DST is active! |
|
// CI is calibrated to be on LA timezone! |
|
func testTimeDifference() { |
|
let observingDaylightSavings = TimeZone.autoupdatingCurrent.isDaylightSavingTime(for: Date()) |
|
let expectedDifference = observingDaylightSavings ? ", +9h 30m" : ", +10h 30m" |
|
let expectedDifferenceForAuckland = observingDaylightSavings ? ", +16h " : ", +18h " |
|
|
|
XCTAssertTrue(operations.timeDifference() == expectedDifference, "Difference was unexpectedly: \(operations.timeDifference())") |
|
XCTAssertTrue(californiaOperations.timeDifference() == ", -3h ", "Difference was unexpectedly: \(californiaOperations.timeDifference())") |
|
XCTAssertTrue(floridaOperations.timeDifference() == "", "Difference was unexpectedly: \(floridaOperations.timeDifference())") |
|
XCTAssertTrue(aucklandOperations.timeDifference() == expectedDifferenceForAuckland, "Difference was unexpectedly: \(aucklandOperations.timeDifference())") |
|
XCTAssertTrue(omahaOperations.timeDifference() == ", -1h ", "Difference was unexpectedly: \(omahaOperations.timeDifference())") |
|
} |
|
|
|
func testSunriseSunset() { |
|
let dataObject = TimezoneData(with: mumbai) |
|
let operations = TimezoneDataOperations(with: dataObject, store: DataStore.shared()) |
|
|
|
XCTAssertNotNil(operations.formattedSunriseTime(with: 0)) |
|
XCTAssertNotNil(dataObject.sunriseTime) |
|
XCTAssertNotNil(dataObject.sunriseTime) |
|
|
|
let timezoneObject = TimezoneData(with: onlyTimezone) |
|
timezoneObject.selectionType = .timezone |
|
let timezoneOperations = TimezoneDataOperations(with: timezoneObject, store: DataStore.shared()) |
|
|
|
XCTAssertTrue(timezoneOperations.formattedSunriseTime(with: 0) == "") |
|
XCTAssertNil(timezoneObject.sunriseTime) |
|
XCTAssertNil(timezoneObject.sunsetTime) |
|
} |
|
|
|
func testDateWithSliderValue() { |
|
let dataObject = TimezoneData(with: mumbai) |
|
let operations = TimezoneDataOperations(with: dataObject, store: DataStore.shared()) |
|
|
|
XCTAssertNotNil(operations.date(with: 0, displayType: .menu)) |
|
} |
|
|
|
func testTimezoneFormat() { |
|
let dataObject = TimezoneData(with: mumbai) |
|
UserDefaults.standard.set(NSNumber(value: 0), forKey: CLSelectedTimeZoneFormatKey) // Set to 12 hour format |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(0) // Respect Global Preference |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "h:mm a") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(1) // 12-Hour Format |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "h:mm a") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(2) // 24-Hour format |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "HH:mm") |
|
|
|
// Skip 3 since it's a placeholder |
|
dataObject.setShouldOverrideGlobalTimeFormat(4) // 12-Hour with seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "h:mm:ss a") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(5) // 24-Hour format with seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "HH:mm:ss") |
|
|
|
// Skip 6 since it's a placeholder |
|
dataObject.setShouldOverrideGlobalTimeFormat(7) // 12-hour with preceding zero and no seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm a") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(8) // 12-hour with preceding zero and seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm:ss a") |
|
|
|
// Skip 9 since it's a placeholder |
|
dataObject.setShouldOverrideGlobalTimeFormat(10) // 12-hour without am/pm and seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(11) // 12-hour with preceding zero and seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm:ss") |
|
|
|
// Wrong input |
|
dataObject.setShouldOverrideGlobalTimeFormat(0) // 12-hour with preceding zero and seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(88) == "h:mm a") |
|
} |
|
|
|
func testTimezoneFormatWithDefaultSetAs24HourFormat() { |
|
let dataObject = TimezoneData(with: california) |
|
UserDefaults.standard.set(NSNumber(value: 1), forKey: CLSelectedTimeZoneFormatKey) // Set to 24-Hour Format |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(0) |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "HH:mm", |
|
"Unexpected format returned: \(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()))") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(1) // 12-Hour Format |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "h:mm a") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(2) // 24-Hour format |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "HH:mm") |
|
|
|
// Skip 3 since it's a placeholder |
|
dataObject.setShouldOverrideGlobalTimeFormat(4) // 12-Hour with seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "h:mm:ss a") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(5) // 24-Hour format with seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "HH:mm:ss") |
|
|
|
// Skip 6 since it's a placeholder |
|
dataObject.setShouldOverrideGlobalTimeFormat(7) // 12-hour with preceding zero and no seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm a") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(8) // 12-hour with preceding zero and seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm:ss a") |
|
|
|
// Skip 9 since it's a placeholder |
|
dataObject.setShouldOverrideGlobalTimeFormat(10) // 12-hour without am/pm and seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(11) // 12-hour with preceding zero and seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "hh:mm:ss") |
|
|
|
dataObject.setShouldOverrideGlobalTimeFormat(12) // 12-hour with preceding zero and seconds |
|
XCTAssertTrue(dataObject.timezoneFormat(DataStore.shared().timezoneFormat()) == "epoch") |
|
} |
|
|
|
func testSecondsDisplayForOverridenTimezone() { |
|
let dataObject = TimezoneData(with: california) |
|
UserDefaults.standard.set(NSNumber(value: 1), forKey: CLSelectedTimeZoneFormatKey) // Set to 24-Hour Format |
|
|
|
// Test default behaviour |
|
let timezoneWithSecondsKeys = [4, 5, 8, 11] |
|
for timezoneKey in timezoneWithSecondsKeys { |
|
dataObject.setShouldOverrideGlobalTimeFormat(timezoneKey) |
|
XCTAssertTrue(dataObject.shouldShowSeconds(DataStore.shared().timezoneFormat())) |
|
} |
|
|
|
let timezoneWithoutSecondsKeys = [1, 2, 7, 10] |
|
for timezoneKey in timezoneWithoutSecondsKeys { |
|
dataObject.setShouldOverrideGlobalTimeFormat(timezoneKey) |
|
XCTAssertFalse(dataObject.shouldShowSeconds(DataStore.shared().timezoneFormat())) |
|
} |
|
|
|
// Test wrong override timezone key |
|
let wrongTimezoneKey = 88 |
|
dataObject.setShouldOverrideGlobalTimeFormat(wrongTimezoneKey) |
|
XCTAssertFalse(dataObject.shouldShowSeconds(DataStore.shared().timezoneFormat())) |
|
|
|
// Test wrong global preference key |
|
dataObject.setShouldOverrideGlobalTimeFormat(0) |
|
XCTAssertFalse(dataObject.shouldShowSeconds(88)) |
|
} |
|
|
|
func testTimezoneRetrieval() { |
|
let dataObject = TimezoneData(with: mumbai) |
|
let autoupdatingTimezone = TimeZone.autoupdatingCurrent.identifier |
|
XCTAssertEqual(dataObject.timezone(), "Asia/Calcutta") |
|
|
|
// Unlikely |
|
dataObject.timezoneID = nil |
|
XCTAssertEqual(dataObject.timezone(), autoupdatingTimezone) |
|
|
|
dataObject.isSystemTimezone = true |
|
XCTAssertEqual(dataObject.timezone(), autoupdatingTimezone) |
|
} |
|
|
|
func testFormattedLabel() { |
|
let dataObject = TimezoneData(with: mumbai) |
|
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Ghar", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())") |
|
|
|
dataObject.setLabel("") |
|
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Mumbai", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())") |
|
|
|
dataObject.formattedAddress = nil |
|
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Asia", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())") |
|
|
|
dataObject.setLabel("Jogeshwari") |
|
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Jogeshwari", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())") |
|
|
|
// Unlikely scenario |
|
dataObject.setLabel("") |
|
dataObject.timezoneID = "GMT" |
|
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "GMT", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())") |
|
|
|
// Another unlikely scenario |
|
dataObject.setLabel("") |
|
dataObject.timezoneID = nil |
|
XCTAssertTrue(dataObject.formattedTimezoneLabel() == "Error", "Incorrect custom label returned by model \(dataObject.formattedTimezoneLabel())") |
|
} |
|
|
|
func testEquality() { |
|
let dataObject1 = TimezoneData(with: mumbai) |
|
let dataObject2 = TimezoneData(with: auckland) |
|
|
|
XCTAssertFalse(dataObject1 == dataObject2) |
|
XCTAssertFalse(dataObject1.isEqual(dataObject2)) |
|
|
|
let dataObject3 = TimezoneData(with: mumbai) |
|
XCTAssertTrue(dataObject1 == dataObject3) |
|
XCTAssertTrue(dataObject1.isEqual(dataObject3)) |
|
|
|
XCTAssertFalse(dataObject1.isEqual(nil)) |
|
} |
|
|
|
func testWithAllLocales() { |
|
let dataObject1 = TimezoneData(with: mumbai) |
|
let operations = TimezoneDataOperations(with: dataObject1, store: DataStore.shared()) |
|
|
|
for locale in Locale.availableIdentifiers { |
|
let currentLocale = Locale(identifier: locale) |
|
let localizedDate = operations.todaysDate(with: 0, locale: currentLocale) |
|
XCTAssertNotNil(localizedDate) |
|
} |
|
} |
|
|
|
func testTimeWithAllLocales() { |
|
let dataObject = TimezoneData(with: mumbai) |
|
|
|
let cal = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian) |
|
|
|
guard let newDate = cal?.date(byAdding: .minute, |
|
value: 0, |
|
to: Date(), |
|
options: .matchFirst) |
|
else { |
|
XCTFail("Unable to add dates!") |
|
return |
|
} |
|
|
|
for locale in Locale.availableIdentifiers { |
|
let currentLocale = Locale(identifier: locale) |
|
let dateFormatter = DateFormatterManager.dateFormatterWithFormat(with: .none, |
|
format: dataObject.timezoneFormat(DataStore.shared().timezoneFormat()), |
|
timezoneIdentifier: dataObject.timezone(), |
|
locale: currentLocale) |
|
let convertedDate = dateFormatter.string(from: newDate) |
|
XCTAssertNotNil(convertedDate) |
|
} |
|
} |
|
|
|
func testStringFiltering() { |
|
let stringWithComma = "Mumbai, Maharashtra" |
|
let stringWithoutComma = "Mumbai" |
|
let emptyString = "" |
|
|
|
XCTAssertEqual(stringWithComma.filteredName(), "Mumbai") |
|
XCTAssertEqual(stringWithoutComma.filteredName(), "Mumbai") |
|
XCTAssertEqual(emptyString.filteredName(), "") |
|
} |
|
|
|
func testToasty() { |
|
let view = NSView(frame: CGRect.zero) |
|
view.makeToast("Hello, this is a toast") |
|
XCTAssertEqual(view.subviews.first?.accessibilityIdentifier(), "ToastView") |
|
let toastExpectation = expectation(description: "Toast View should hide after 1 second") |
|
let result = XCTWaiter.wait(for: [toastExpectation], timeout: 1.5) // Set 1.5 seconds here for a little leeway |
|
if result == XCTWaiter.Result.timedOut { |
|
XCTAssertTrue(view.subviews.isEmpty) |
|
} |
|
} |
|
|
|
func testPointingHandButton() { |
|
let sampleRect = CGRect(x: 0, y: 0, width: 200, height: 200) |
|
let pointingHandCursorButton = PointingHandCursorButton(frame: CGRect.zero) |
|
pointingHandCursorButton.draw(sampleRect) |
|
pointingHandCursorButton.resetCursorRects() |
|
XCTAssertEqual(pointingHandCursorButton.pointingHandCursor, NSCursor.pointingHand) |
|
} |
|
|
|
func testNoTimezoneView() { |
|
let sampleRect = CGRect(x: 0, y: 0, width: 200, height: 200) |
|
let subject = NoTimezoneView(frame: sampleRect) |
|
// Perform a layout to add subviews |
|
subject.layout() |
|
XCTAssertEqual(subject.subviews.count, 2) // Two textfields |
|
XCTAssertEqual(subject.subviews.first?.layer?.animationKeys(), ["notimezone.emoji"]) |
|
} |
|
|
|
func testDefaultsWiping() { |
|
let defaultsDict: [String: Any] = ["test1": "testString", "test2": 24] |
|
let domainName = "com.test.clocker" |
|
let defaults = UserDefaults(suiteName: domainName) |
|
defaults?.setPersistentDomain(defaultsDict, forName: domainName) |
|
defaults?.wipe(for: domainName) |
|
XCTAssertNil(defaults?.object(forKey: "test1")) |
|
XCTAssertNil(defaults?.object(forKey: "test2")) |
|
} |
|
}
|
|
|