LunarSouthNode and Sidereal Cusps

- Refactors Coordinate for the addition of .tropical and sidereal properties
- Adds .tropical and sidereal properties to Cusp
- Updates README.md
- Adds LunarSouthNode
This commit is contained in:
Vincent Smithers 2022-06-12 09:47:49 -07:00 committed by GitHub
parent 27b5a1de31
commit 20a97e6c33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 546 additions and 513 deletions

View File

@ -56,6 +56,15 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<CodeCoverageTargets>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "SwissEphemeris"
BuildableName = "SwissEphemeris"
BlueprintName = "SwissEphemeris"
ReferencedContainer = "container:">
</BuildableReference>
</CodeCoverageTargets>
<Testables>
<TestableReference
skipped = "NO">

View File

@ -59,7 +59,7 @@ moonCoordinate.speedLatitude
// The speed in distance (AU/day).
moonCoordinate.speedDistance
```
Astrological information about the tropical zodiacal location of a celestial body is also available from the same `Coordinate` type.
Astrological information about the tropical and sidereal zodiacal locations of a celestial body is also available from the same `Coordinate` type through the `tropical` and `sidereal` properties.
```swift
// Date for 12.14.2019 13:39 UT/GMT
@ -67,11 +67,11 @@ let date = Date(timeIntervalSince1970: 598023482.487818)
// Astronomical and astrological information for the sun on December 14th 2019.
let sunCoordinate = Coordinate<Planet>(planet: .sun, date: date)
// This will return 21 Degrees Sagittarius ♐︎ 46' 49''.
sunCoordinate.formatted
sunCoordinate.tropical.formatted
// It is also possible to get the degree, minute and second as properties of the Coordinate.
let degree = sunCoordinate.degree
let minute = sunCoordinate.minute
let second = sunCoordinate.second
let degree = sunCoordinate.tropical.degree
let minute = sunCoordinate.tropical.minute
let second = sunCoordinate.tropical.second
```
#### Astrological Aspect
@ -79,30 +79,30 @@ To create an aspect between two `CelestialBody` types use `Aspect`. `Transit`
```swift
// Create a pair of celestial bodies.
let moonTrueNode = Pair<Planet, LunarNode>(a: .moon, b: .trueNode)
let moonTrueNode = Pair<Planet, LunarNorthNode>(a: .moon, b: .trueNode)
// Transit contains start and end date properties.
let transit = Transit(pair: moonTrueNode, date: Date(), orb: 8.0)
```
#### Astrological Houses
To get the house layout for a date, location, and house system create a `HouseCusps`. The `HouseSystem` determines the type of astrological house system that is set. All house `Cusp` properties can be used to create an `Aspect` with a `CelestialBody`.
To get the house layout for a date, location, and house system create a `HouseCusps`. The `HouseSystem` determines the type of astrological house system that is set. All house `Cusp` properties can be used to create an `Aspect` with a `CelestialBody`. Zodiacal information for each cusp is available through the `tropical` and `sidereal` properties.
```swift
/// Create a date and location
// Create a date and location
let now = Date()
let latitude: Double = 37.5081153
let longitude: Double = -122.2854528
/// All house cusps, Ascendent, and MC are properties on `houses`.
// All house cusps, Ascendent, and MC are properties on `houses`.
let houses = HouseCusps(date: date, latitude: latitude, longitude: longitude, houseSystem: .placidus)
/// Get the formatted astrological position.
let ascendentFormatted = houses.ascendent.formatted
/// Or the precise degree
let degree = houses.ascendent.degree
// Get the formatted sidereal astrological position.
let ascendentFormatted = houses.ascendent.sidereal.formatted
// Or the precise degree for the sidereal zodiac.
let degree = houses.ascendent.sidereal.degree
```
#### IPL Numbering
The `enum` types for `Planet`, `Asteroid`, and `LunarNode` correspond to IPL numbers in the ephemeris. Other celestial bodies such as stars as fictitious points still need to be added. The type numbering is not comprehensive, but can be easily extended to match the celestial body that is not available in the package. All of the types conform to the `CelestialBody` protocol which makes it so different categories of celestial points can be mapped to the tropical zodiac both in aspect and position.
The `enum` types for `Planet`, `Asteroid`, and `LunarNorthNode` correspond to IPL numbers in the ephemeris. Other celestial bodies such as stars as fictitious points still need to be added. The type numbering is not comprehensive, but can be easily extended to match the celestial body that is not available in the package. All of the types conform to the `CelestialBody` protocol which makes it so different categories of celestial points can be mapped to the tropical zodiac both in aspect and position.
#### Batch Calculations

View File

@ -29,7 +29,7 @@ public enum Aspect: Equatable, Hashable, Codable {
public init?<T, U>(pair: Pair<T, U>, date: Date, orb: Double = 10.0) {
let degreeA = Coordinate(body: pair.a, date: date)
let degreeB = Coordinate(body: pair.b, date: date)
self.init(a: degreeA.value, b: degreeB.value, orb: orb)
self.init(a: degreeA.longitude, b: degreeB.longitude, orb: orb)
}
/// Creates an optional `Aspect` between two degrees. If there is no aspect within the orb, then this initializer will return `nil`.

View File

@ -10,7 +10,7 @@ import CSwissEphemeris
/// Models a `CelestialBody` point in the sky.
public struct Coordinate<T: CelestialBody> {
public struct Coordinate<T: CelestialBody>: ZodiacMappable {
/// The type of `CelestialBody`.
public let body: T
@ -33,24 +33,31 @@ public struct Coordinate<T: CelestialBody> {
/// The pointer for the fixed star name.
private var charPointer = UnsafeMutablePointer<CChar>.allocate(capacity: 1)
// MARK: - ZodiacMappable Properties
public let tropical: ZodiacCoordinate
public let sidereal: ZodiacCoordinate
// MARK: - Initializers
/// Creates a `Coordinate`.
/// - Parameters:
/// - body: The `CelestialBody` for the placement.
/// - date: The date for the location of the coordinate.
public init(body: T, date: Date) {
defer {
pointer.deinitialize(count: 6)
pointer.deallocate()
if let star = body as? FixedStar {
charPointer.deinitialize(count: star.rawValue.count)
charPointer.deallocate()
}
}
defer {
pointer.deinitialize(count: 6)
pointer.deallocate()
if let star = body as? FixedStar {
charPointer.deinitialize(count: star.rawValue.count)
charPointer.deallocate()
}
}
self.body = body
self.date = date
switch body.value {
case let value as Int32:
pointer.initialize(repeating: 0, count: 6)
pointer.initialize(repeating: 0, count: 6)
swe_calc_ut(date.julianDate(), value, SEFLG_SPEED, pointer, nil)
case let value as String:
charPointer.initialize(from: value, count: value.count)
@ -65,51 +72,53 @@ public struct Coordinate<T: CelestialBody> {
speedLongitude = pointer[3]
speedLatitude = pointer[4]
speedDistance = pointer[5]
tropical = ZodiacCoordinate(value: longitude)
sidereal = ZodiacCoordinate(value: longitude, offset: Ayanamsha()(for: date))
}
}
// MARK: - ZodiacCoordinate Conformance
extension Coordinate: ZodiacCoordinate {
public var value: Double { longitude }
}
// MARK: - Codable Conformance
extension Coordinate: Codable {
public enum CodingKeys: CodingKey {
case body
case date
case longitude
case latitude
case distance
case speedLongitude
case speedLatitude
case speedDistance
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
body = try container.decode(T.self, forKey: .body)
date = try container.decode(Date.self, forKey: .date)
longitude = try container.decode(Double.self, forKey: .longitude)
latitude = try container.decode(Double.self, forKey: .latitude)
distance = try container.decode(Double.self, forKey: .distance)
speedLongitude = try container.decode(Double.self, forKey: .speedLongitude)
speedLatitude = try container.decode(Double.self, forKey: .speedLatitude)
speedDistance = try container.decode(Double.self, forKey: .speedDistance)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(body, forKey: .body)
try container.encode(date, forKey: .date)
try container.encode(longitude, forKey: .longitude)
try container.encode(latitude, forKey: .latitude)
try container.encode(distance, forKey: .distance)
try container.encode(speedLongitude, forKey: .speedLongitude)
try container.encode(speedLatitude, forKey: .speedLatitude)
try container.encode(speedDistance, forKey: .speedDistance)
}
public enum CodingKeys: CodingKey {
case body
case date
case longitude
case latitude
case distance
case speedLongitude
case speedLatitude
case speedDistance
case tropicalCoordinate
case siderealCoordinate
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
body = try container.decode(T.self, forKey: .body)
date = try container.decode(Date.self, forKey: .date)
longitude = try container.decode(Double.self, forKey: .longitude)
latitude = try container.decode(Double.self, forKey: .latitude)
distance = try container.decode(Double.self, forKey: .distance)
speedLongitude = try container.decode(Double.self, forKey: .speedLongitude)
speedLatitude = try container.decode(Double.self, forKey: .speedLatitude)
speedDistance = try container.decode(Double.self, forKey: .speedDistance)
tropical = try container.decode(ZodiacCoordinate.self, forKey: .tropicalCoordinate)
sidereal = try container.decode(ZodiacCoordinate.self, forKey: .siderealCoordinate)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(body, forKey: .body)
try container.encode(date, forKey: .date)
try container.encode(longitude, forKey: .longitude)
try container.encode(latitude, forKey: .latitude)
try container.encode(distance, forKey: .distance)
try container.encode(speedLongitude, forKey: .speedLongitude)
try container.encode(speedLatitude, forKey: .speedLatitude)
try container.encode(speedDistance, forKey: .speedDistance)
try container.encode(tropical, forKey: .tropicalCoordinate)
try container.encode(sidereal, forKey: .siderealCoordinate)
}
}

View File

@ -8,18 +8,16 @@
import Foundation
/// Models the point between two houses
public struct Cusp {
public struct Cusp: ZodiacMappable {
/// The degree of the coordinate
public let value: Double
public let tropical: ZodiacCoordinate
public let sidereal: ZodiacCoordinate
/// Creates a `Cusp`.
/// - Parameter value: The latitudinal degree to set.
public init(value: Double) {
self.value = value
/// - Parameter date: The `Date` needed to map to the zodiacs.
public init(value: Double, date: Date) {
tropical = ZodiacCoordinate(value: value)
sidereal = ZodiacCoordinate(value: value, offset: Ayanamsha()(for: date))
}
}
// MARK: - ZodiacCoordinate Conformance
extension Cusp: ZodiacCoordinate {}

View File

@ -65,19 +65,19 @@ public struct HouseCusps {
}
self.date = date
swe_houses(date.julianDate(), latitude, longitude, houseSystem.rawValue, cuspPointer, ascendentPointer);
ascendent = Cusp(value: ascendentPointer[0])
midHeaven = Cusp(value: ascendentPointer[1])
first = Cusp(value: cuspPointer[1])
second = Cusp(value: cuspPointer[2])
third = Cusp(value: cuspPointer[3])
fourth = Cusp(value: cuspPointer[4])
fifth = Cusp(value: cuspPointer[5])
sixth = Cusp(value: cuspPointer[6])
seventh = Cusp(value: cuspPointer[7])
eighth = Cusp(value: cuspPointer[8])
ninth = Cusp(value: cuspPointer[9])
tenth = Cusp(value: cuspPointer[10])
eleventh = Cusp(value: cuspPointer[11])
twelfth = Cusp(value: cuspPointer[12])
ascendent = Cusp(value: ascendentPointer[0], date: date)
midHeaven = Cusp(value: ascendentPointer[1], date: date)
first = Cusp(value: cuspPointer[1], date: date)
second = Cusp(value: cuspPointer[2], date: date)
third = Cusp(value: cuspPointer[3], date: date)
fourth = Cusp(value: cuspPointer[4], date: date)
fifth = Cusp(value: cuspPointer[5], date: date)
sixth = Cusp(value: cuspPointer[6], date: date)
seventh = Cusp(value: cuspPointer[7], date: date)
eighth = Cusp(value: cuspPointer[8], date: date)
ninth = Cusp(value: cuspPointer[9], date: date)
tenth = Cusp(value: cuspPointer[10], date: date)
eleventh = Cusp(value: cuspPointer[11], date: date)
twelfth = Cusp(value: cuspPointer[12], date: date)
}
}

View File

@ -1,5 +1,5 @@
//
// LunarNode.swift
// LunarNorthNode.swift
//
//
// Created by Vincent Smithers on 15.02.21.
@ -9,14 +9,14 @@ import Foundation
/// Models the lunar nodes.
/// The the raw `Int32` values map to the IPL bodies.
public enum LunarNode: Int32 {
public enum LunarNorthNode: Int32 {
case meanNode = 10
case trueNode
}
// MARK: - CelestialBody Conformance
extension LunarNode: CelestialBody {
extension LunarNorthNode: CelestialBody {
public var value: Int32 {
rawValue
}

View File

@ -0,0 +1,22 @@
//
// LunarSouthNode.swift
//
//
// Created by Vincent Smithers on 6/4/22.
//
import Foundation
/// Maps the Moon's south node to the zodiacs.
public struct LunarSouthNode: ZodiacMappable {
public let tropical: ZodiacCoordinate
public let sidereal: ZodiacCoordinate
/// Creates a `LunarSouthNode`.
/// - Parameter nodeCoordinate: The north lunar node coordinate.
public init(nodeCoordinate: Coordinate<LunarNorthNode>) {
tropical = ZodiacCoordinate(value: nodeCoordinate.longitude, offset: 180.0)
sidereal = ZodiacCoordinate(value: nodeCoordinate.longitude, offset: 180.0 + Ayanamsha()(for: nodeCoordinate.date))
}
}

View File

@ -1,42 +0,0 @@
//
// SiderealCoordinate.swift
//
//
// Created by Vincent Smithers on 16.03.21.
//
import Foundation
/// Models a sidereal coordinate on the Zodiac.
public struct SiderealCoordinate<T: CelestialBody> {
///
public let date: Date
/// The coordinate to set
private let coordinate: Coordinate<T>
/// The ayanamsha value that determines the sidereal position
private let ayanamshaValue: Double
/// Creates a `SiderealCoordinate`.
/// - Parameter coordinate: The coordinate to set.
/// - Parameter ayanamshaValue: The ayanamsha value that determines the sidereal position.
public init(coordinate: Coordinate<T>, ayanamshaValue: Double = Ayanamsha.current) {
self.date = coordinate.date
self.coordinate = coordinate
self.ayanamshaValue = ayanamshaValue
}
}
// MARK: - ZodiacCoordinate Conformance
extension SiderealCoordinate: ZodiacCoordinate {
public var value: Double {
// If in the first degrees of Aries
if coordinate.longitude - ayanamshaValue < 0 {
return 360 - abs(coordinate.longitude - ayanamshaValue)
} else {
return coordinate.longitude - ayanamshaValue
}
}
}

View File

@ -1,48 +0,0 @@
//
// ZodiacCoordinate.swift
//
//
// Created by Vincent Smithers on 11.02.21.
//
import Foundation
/// Models a degree along the twelve signs of the tropical zodiac.
/// https://www.astro.com/astrowiki/en/Tropical_Zodiac
public protocol ZodiacCoordinate {
/// The degree to of zodiac. Between 0 - 360.
var value: Double { get }
/// The sign that houses the degree.
var sign: Zodiac { get }
///
var lunarMansion: LunarMansion { get }
/// The degree within the sign. Between 0 - 30.
var degree: Double { get }
/// The minute value for the degree.
var minute: Double { get}
/// The second value for the degree.
var second: Double { get }
}
public extension ZodiacCoordinate {
var sign: Zodiac { Zodiac(rawValue: Int(value / 30))! }
var lunarMansion: LunarMansion { LunarMansion(rawValue: Int(value / 12.857142857142857)) ?? .batnAlHut }
var degree: Double { value.truncatingRemainder(dividingBy: 30) }
var minute: Double { value.truncatingRemainder(dividingBy: 1) * 60 }
var second: Double { minute.truncatingRemainder(dividingBy: 1) * 60 }
}
public extension ZodiacCoordinate {
/// A readable `String` formatting the degree, sign, minute and second
var formatted: String {
"\(Int(degree)) Degrees " +
"\(sign.formatted) " +
"\(Int(minute))' " +
"\(Int(second))''"
}
}

View File

@ -0,0 +1,16 @@
//
// ZodiacMappable.swift
//
//
// Created by Vincent Smithers on 6/5/22.
//
import Foundation
/// Interface for both mapping both zodiacs to coordinates.
public protocol ZodiacMappable {
/// The coordinate for the tropical zodiac.
var tropical: ZodiacCoordinate { get }
/// The coordinate for the sidereal zodiac.
var sidereal: ZodiacCoordinate { get }
}

View File

@ -23,7 +23,7 @@ public enum Station<T: CelestialBody>: Equatable {
/// - Parameter timeInterval: The interval of time to compare the coordinate longitude. The default is 24 hours.
public init(coordinate: Coordinate<T>, timeInterval: Double = 60 * 60 * 24) {
let modDate = coordinate.date.addingTimeInterval(timeInterval)
switch coordinate.value - Coordinate(body: coordinate.body, date: modDate).value {
switch coordinate.longitude - Coordinate(body: coordinate.body, date: modDate).longitude {
case let x where x < 0:
self = .direct
case let x where x > 0:

View File

@ -0,0 +1,48 @@
//
// ZodiacCoordinate.swift
//
//
// Created by Vincent Smithers on 11.02.21.
//
import Foundation
/// Models a degree along the twelve signs of the zodiac.
public struct ZodiacCoordinate: Codable {
/// The degree to of zodiac. Between 0 - 360.
public let value: Double
/// The sign that houses the degree.
public var sign: Zodiac { Zodiac(rawValue: Int(value / 30))! }
///
public var lunarMansion: LunarMansion { LunarMansion(rawValue: Int(value / 12.857142857142857)) ?? .batnAlHut }
/// The degree within the sign. Between 0 - 30.
public var degree: Double { value.truncatingRemainder(dividingBy: 30) }
/// The minute value for the degree.
public var minute: Double { value.truncatingRemainder(dividingBy: 1) * 60 }
/// The second value for the degree.
public var second: Double { minute.truncatingRemainder(dividingBy: 1) * 60 }
/// An internal initializer for creating a `ZodiacCoordinate`.
/// - Parameter value: Must be between 0-360.
init(value: Double) {
self.value = value
}
/// An internal initializer for creating a `ZodiacCoordinate` with an offset.
/// - Parameters:
/// - value: Must be between 0-360.
/// - offset: The offset to set.
init(value: Double, offset: Double) {
self.value = value - offset >= 0 ? value - offset : 360.0 + value - offset
}
}
public extension ZodiacCoordinate {
/// A readable `String` formatting the degree, sign, minute and second
var formatted: String {
"\(Int(degree)) Degrees " +
"\(sign.formatted) " +
"\(Int(minute))' " +
"\(Int(second))''"
}
}

View File

@ -6,209 +6,228 @@ final class CelestialBodyTests: XCTestCase {
override func setUpWithError() throws {
JPLFileManager.setEphemerisPath()
}
func testSunZodiacCoordinate() {
// 12.14.2019 13:39 UT/GMT
let date = Date(timeIntervalSince1970: 598023482.487818)
let sunCoordinate = Coordinate<Planet>(body: .sun, date: date)
XCTAssertEqual(sunCoordinate.value, 261.7804948994796)
XCTAssertEqual(sunCoordinate.sign, .sagittarius)
XCTAssertEqual(sunCoordinate.formatted, "21 Degrees Sagittarius ♐︎ 46' 49''")
XCTAssertEqual(Int(sunCoordinate.degree), 21)
XCTAssertEqual(Int(sunCoordinate.minute), 46)
XCTAssertEqual(Int(sunCoordinate.second), 49)
}
func testSunZodiacCoordinate() {
// 12.14.2019 13:39 UT/GMT
let date = Date(timeIntervalSince1970: 598023482.487818)
let sunCoordinate = Coordinate<Planet>(body: .sun, date: date)
XCTAssertEqual(sunCoordinate.longitude, 261.7804948994796)
XCTAssertEqual(sunCoordinate.tropical.sign, .sagittarius)
XCTAssertEqual(sunCoordinate.tropical.formatted, "21 Degrees Sagittarius ♐︎ 46' 49''")
XCTAssertEqual(Int(sunCoordinate.tropical.degree), 21)
XCTAssertEqual(Int(sunCoordinate.tropical.minute), 46)
XCTAssertEqual(Int(sunCoordinate.tropical.second), 49)
}
func testMoonSiderealCoordinate() {
let moonCoordinate = SiderealCoordinate(coordinate: Coordinate<Planet>(body: .moon, date: Mock.date),
ayanamshaValue: Ayanamsha()(for: Mock.date))
XCTAssertEqual(Int(moonCoordinate.value), 295)
XCTAssertEqual(moonCoordinate.sign, .capricorn)
XCTAssertEqual(moonCoordinate.formatted, "25 Degrees Capricorn ♑︎ 3' 16''")
XCTAssertEqual(Int(moonCoordinate.degree), 25)
XCTAssertEqual(Int(moonCoordinate.minute), 3)
XCTAssertEqual(Int(moonCoordinate.second), 16)
let moonCoordinate = Coordinate<Planet>(body: .moon, date: Mock.date)
XCTAssertEqual(Int(moonCoordinate.sidereal.value), 295)
XCTAssertEqual(moonCoordinate.sidereal.sign, .capricorn)
XCTAssertEqual(moonCoordinate.sidereal.formatted, "25 Degrees Capricorn ♑︎ 3' 16''")
XCTAssertEqual(Int(moonCoordinate.sidereal.degree), 25)
XCTAssertEqual(Int(moonCoordinate.sidereal.minute), 3)
XCTAssertEqual(Int(moonCoordinate.sidereal.second), 16)
}
func testAsteroids() throws {
let date = try XCTUnwrap(Mock.date(from: "2021-03-01T12:31:00-0800"))
let chiron = Coordinate<Asteroid>(body: .chiron, date: date)
XCTAssertEqual(Int(chiron.degree), 7)
XCTAssertEqual(chiron.sign, .aries)
XCTAssertEqual(Int(chiron.tropical.degree), 7)
XCTAssertEqual(chiron.tropical.sign, .aries)
let pholus = Coordinate<Asteroid>(body: .pholus, date: date)
XCTAssertEqual(Int(pholus.degree), 5)
XCTAssertEqual(pholus.sign, .capricorn)
XCTAssertEqual(Int(pholus.tropical.degree), 5)
XCTAssertEqual(pholus.tropical.sign, .capricorn)
let ceres = Coordinate<Asteroid>(body: .ceres, date: date)
XCTAssertEqual(Int(ceres.degree), 3)
XCTAssertEqual(ceres.sign, .aries)
XCTAssertEqual(Int(ceres.tropical.degree), 3)
XCTAssertEqual(ceres.tropical.sign, .aries)
let pallas = Coordinate<Asteroid>(body: .pallas, date: date)
XCTAssertEqual(Int(pallas.degree), 28)
XCTAssertEqual(pallas.sign, .aquarius)
XCTAssertEqual(Int(pallas.tropical.degree), 28)
XCTAssertEqual(pallas.tropical.sign, .aquarius)
let juno = Coordinate<Asteroid>(body: .juno, date: date)
XCTAssertEqual(Int(juno.degree), 19)
XCTAssertEqual(juno.sign, .sagittarius)
XCTAssertEqual(Int(juno.tropical.degree), 19)
XCTAssertEqual(juno.tropical.sign, .sagittarius)
let vesta = Coordinate<Asteroid>(body: .vesta, date: date)
XCTAssertEqual(Int(vesta.degree), 15)
XCTAssertEqual(vesta.sign, .virgo)
XCTAssertEqual(Int(vesta.tropical.degree), 15)
XCTAssertEqual(vesta.tropical.sign, .virgo)
}
func testLunarNodes() throws {
func testLunarNorthNodes() throws {
let date = try XCTUnwrap(Mock.date(year: 2121, month: 1, day: 1, hour: 1, minute: 1, second: 1))
let trueNode = Coordinate<LunarNode>(body: .trueNode, date: date)
XCTAssertEqual(Int(trueNode.degree), 3)
XCTAssertEqual(trueNode.sign, .aquarius)
let meanNode = Coordinate<LunarNode>(body: .meanNode, date: date)
XCTAssertEqual(Int(meanNode.degree), 4)
XCTAssertEqual(meanNode.sign, .aquarius)
let trueNode = Coordinate<LunarNorthNode>(body: .trueNode, date: date)
XCTAssertEqual(Int(trueNode.tropical.degree), 3)
XCTAssertEqual(trueNode.tropical.sign, .aquarius)
let meanNode = Coordinate<LunarNorthNode>(body: .meanNode, date: date)
XCTAssertEqual(Int(meanNode.tropical.degree), 4)
XCTAssertEqual(meanNode.tropical.sign, .aquarius)
}
func testPlanets() {
for (index, planet) in Planet.allCases.enumerated() {
switch index {
case 0:
XCTAssertEqual(planet.formatted, "☉ Sun")
func testLunarSouthNodes() throws {
let date = try XCTUnwrap(Mock.date(year: 2121, month: 1, day: 1, hour: 1, minute: 1, second: 1))
let trueNode = Coordinate<LunarNorthNode>(body: .trueNode, date: date)
let trueSouthNode = LunarSouthNode(nodeCoordinate: trueNode)
XCTAssertEqual(trueSouthNode.tropical.value + 180, trueNode.tropical.value)
XCTAssertEqual(trueSouthNode.tropical.value - Ayanamsha().callAsFunction(for: date), trueSouthNode.sidereal.value)
let meanNode = Coordinate<LunarNorthNode>(body: .meanNode, date: date)
let meanSouthNode = LunarSouthNode(nodeCoordinate: meanNode)
XCTAssertEqual(meanSouthNode.tropical.value + 180, meanNode.tropical.value)
XCTAssertEqual(meanSouthNode.tropical.value - Ayanamsha().callAsFunction(for: date), meanSouthNode.sidereal.value)
}
func testLunarSouthNodeOffset() {
for n in 0...360 {
let north = ZodiacCoordinate(value:Double(n))
let south = ZodiacCoordinate(value: north.value, offset: 180.0)
XCTAssertEqual(abs(north.value - south.value), 180.0)
}
}
func testPlanets() {
for (index, planet) in Planet.allCases.enumerated() {
switch index {
case 0:
XCTAssertEqual(planet.formatted, "☉ Sun")
XCTAssertEqual(planet.symbol, "")
case 1:
XCTAssertEqual(planet.formatted, "☾ Moon")
case 1:
XCTAssertEqual(planet.formatted, "☾ Moon")
XCTAssertEqual(planet.symbol, "")
case 2:
XCTAssertEqual(planet.formatted, "☿ Mercury")
case 2:
XCTAssertEqual(planet.formatted, "☿ Mercury")
XCTAssertEqual(planet.symbol, "")
case 3:
XCTAssertEqual(planet.formatted, "♀ Venus")
case 3:
XCTAssertEqual(planet.formatted, "♀ Venus")
XCTAssertEqual(planet.symbol, "")
case 4:
XCTAssertEqual(planet.formatted, "Mars")
case 4:
XCTAssertEqual(planet.formatted, "Mars")
XCTAssertEqual(planet.symbol, "♂︎")
case 5:
XCTAssertEqual(planet.formatted, "♃ Jupiter")
case 5:
XCTAssertEqual(planet.formatted, "♃ Jupiter")
XCTAssertEqual(planet.symbol, "")
case 6:
XCTAssertEqual(planet.formatted, "♄ Saturn")
case 6:
XCTAssertEqual(planet.formatted, "♄ Saturn")
XCTAssertEqual(planet.symbol, "")
case 7:
XCTAssertEqual(planet.formatted, "♅ Uranus")
case 7:
XCTAssertEqual(planet.formatted, "♅ Uranus")
XCTAssertEqual(planet.symbol, "")
case 8:
XCTAssertEqual(planet.formatted, "♆ Neptune")
case 8:
XCTAssertEqual(planet.formatted, "♆ Neptune")
XCTAssertEqual(planet.symbol, "")
case 9:
XCTAssertEqual(planet.formatted, "♇ Pluto")
case 9:
XCTAssertEqual(planet.formatted, "♇ Pluto")
XCTAssertEqual(planet.symbol, "")
default:
XCTFail("Failed because there are planets that not tested")
}
}
}
func testZodiac() {
for (index, sign) in Zodiac.allCases.enumerated() {
switch index {
case 0:
XCTAssertEqual(sign.formatted, "Aries ♈︎")
default:
XCTFail("Failed because there are planets that not tested")
}
}
}
func testZodiac() {
for (index, sign) in Zodiac.allCases.enumerated() {
switch index {
case 0:
XCTAssertEqual(sign.formatted, "Aries ♈︎")
XCTAssertEqual(sign.symbol, "♈︎")
case 1:
XCTAssertEqual(sign.formatted, "Taurus ♉︎")
case 1:
XCTAssertEqual(sign.formatted, "Taurus ♉︎")
XCTAssertEqual(sign.symbol, "♉︎")
case 2:
XCTAssertEqual(sign.formatted, "Gemini ♊︎")
case 2:
XCTAssertEqual(sign.formatted, "Gemini ♊︎")
XCTAssertEqual(sign.symbol, "♊︎")
case 3:
XCTAssertEqual(sign.formatted, "Cancer ♋︎")
case 3:
XCTAssertEqual(sign.formatted, "Cancer ♋︎")
XCTAssertEqual(sign.symbol, "♋︎")
case 4:
XCTAssertEqual(sign.formatted, "Leo ♌︎")
case 4:
XCTAssertEqual(sign.formatted, "Leo ♌︎")
XCTAssertEqual(sign.symbol, "♌︎")
case 5:
XCTAssertEqual(sign.formatted, "Virgo ♍︎")
case 5:
XCTAssertEqual(sign.formatted, "Virgo ♍︎")
XCTAssertEqual(sign.symbol, "♍︎")
case 6:
XCTAssertEqual(sign.formatted, "Libra ♎︎")
case 6:
XCTAssertEqual(sign.formatted, "Libra ♎︎")
XCTAssertEqual(sign.symbol, "♎︎")
case 7:
XCTAssertEqual(sign.formatted, "Scorpio ♏︎")
case 7:
XCTAssertEqual(sign.formatted, "Scorpio ♏︎")
XCTAssertEqual(sign.symbol, "♏︎")
case 8:
XCTAssertEqual(sign.formatted, "Sagittarius ♐︎")
case 8:
XCTAssertEqual(sign.formatted, "Sagittarius ♐︎")
XCTAssertEqual(sign.symbol, "♐︎")
case 9:
XCTAssertEqual(sign.formatted, "Capricorn ♑︎")
case 9:
XCTAssertEqual(sign.formatted, "Capricorn ♑︎")
XCTAssertEqual(sign.symbol, "♑︎")
case 10:
XCTAssertEqual(sign.formatted, "Aquarius ♒︎")
case 10:
XCTAssertEqual(sign.formatted, "Aquarius ♒︎")
XCTAssertEqual(sign.symbol, "♒︎")
case 11:
XCTAssertEqual(sign.formatted, "Pisces ♓︎")
case 11:
XCTAssertEqual(sign.formatted, "Pisces ♓︎")
XCTAssertEqual(sign.symbol, "♓︎")
default:
XCTFail("Failed because there are signs that are not tested")
}
}
XCTAssertNil(Zodiac(rawValue: 12))
}
func testAscendent() {
let houseSystem = Mock.makeHouses()
// Ascendent
let ascCoordinate = houseSystem.ascendent
XCTAssertEqual(ascCoordinate.sign, Zodiac.sagittarius)
XCTAssertEqual(ascCoordinate.formatted, "2 Degrees Sagittarius ♐︎ 1' 49''")
// MC
let mc = houseSystem.midHeaven
XCTAssertEqual(mc.sign, Zodiac.virgo)
}
func testHouses() {
let houseSystem = Mock.makeHouses()
/// House Cusps
XCTAssertEqual(houseSystem.first.sign, Zodiac.sagittarius)
XCTAssertEqual(houseSystem.second.sign, Zodiac.capricorn)
XCTAssertEqual(houseSystem.third.sign, Zodiac.aquarius)
XCTAssertEqual(houseSystem.fourth.sign, Zodiac.pisces)
XCTAssertEqual(houseSystem.fifth.sign, Zodiac.aries)
XCTAssertEqual(houseSystem.sixth.sign, Zodiac.taurus)
XCTAssertEqual(houseSystem.seventh.sign, Zodiac.gemini)
XCTAssertEqual(houseSystem.eighth.sign, Zodiac.cancer)
XCTAssertEqual(houseSystem.ninth.sign, Zodiac.leo)
XCTAssertEqual(houseSystem.tenth.sign, Zodiac.virgo)
XCTAssertEqual(houseSystem.eleventh.sign, Zodiac.libra)
XCTAssertEqual(houseSystem.twelfth.sign, Zodiac.scorpio)
}
func testAspects() {
// Expect 64.0 relationship sextile
default:
XCTFail("Failed because there are signs that are not tested")
}
}
XCTAssertNil(Zodiac(rawValue: 12))
}
func testAscendent() {
let houseSystem = Mock.makeHouses()
// Ascendent
let ascCoordinate = houseSystem.ascendent
XCTAssertEqual(ascCoordinate.tropical.sign, Zodiac.sagittarius)
XCTAssertEqual(ascCoordinate.tropical.formatted, "2 Degrees Sagittarius ♐︎ 1' 49''")
// MC
let mc = houseSystem.midHeaven
XCTAssertEqual(mc.tropical.sign, Zodiac.virgo)
}
func testHouses() {
let houseSystem = Mock.makeHouses()
/// House Cusps
XCTAssertEqual(houseSystem.first.tropical.sign, Zodiac.sagittarius)
XCTAssertEqual(houseSystem.second.tropical.sign, Zodiac.capricorn)
XCTAssertEqual(houseSystem.third.tropical.sign, Zodiac.aquarius)
XCTAssertEqual(houseSystem.fourth.tropical.sign, Zodiac.pisces)
XCTAssertEqual(houseSystem.fifth.tropical.sign, Zodiac.aries)
XCTAssertEqual(houseSystem.sixth.tropical.sign, Zodiac.taurus)
XCTAssertEqual(houseSystem.seventh.tropical.sign, Zodiac.gemini)
XCTAssertEqual(houseSystem.eighth.tropical.sign, Zodiac.cancer)
XCTAssertEqual(houseSystem.ninth.tropical.sign, Zodiac.leo)
XCTAssertEqual(houseSystem.tenth.tropical.sign, Zodiac.virgo)
XCTAssertEqual(houseSystem.eleventh.tropical.sign, Zodiac.libra)
XCTAssertEqual(houseSystem.twelfth.tropical.sign, Zodiac.scorpio)
}
func testAspects() {
// Expect 64.0 relationship sextile
var aspect = Aspect(pair: Pair<Planet, Planet>(a: .jupiter, b: .moon), date: Mock.date, orb: 8.0)
XCTAssertEqual(aspect?.remainder, 3.45)
XCTAssertEqual(aspect, .sextile(3.45))
XCTAssertEqual(aspect?.symbol, "")
// Expect reverse to be 64.0 sextile
XCTAssertEqual(aspect, .sextile(3.45))
XCTAssertEqual(aspect?.symbol, "")
// Expect reverse to be 64.0 sextile
aspect = Aspect(pair: Pair<Planet, Planet>(a: .moon, b: .jupiter), date: Mock.date, orb: 8.0)
XCTAssertEqual(aspect?.remainder, 3.45)
XCTAssertEqual(aspect, .sextile(3.45))
// Expect 3.0 relationship conjunction
XCTAssertEqual(aspect?.remainder, 3.45)
XCTAssertEqual(aspect, .sextile(3.45))
// Expect 3.0 relationship conjunction
aspect = Aspect(pair: Pair<Planet, Planet>(a: .sun, b: .pluto), date: Mock.date, orb: 8.0)
XCTAssertEqual(aspect?.remainder, 3.05)
XCTAssertEqual(aspect, .conjunction(3.05))
XCTAssertEqual(aspect?.symbol, "")
// Expect 171.0 relationship opposition
XCTAssertEqual(aspect?.remainder, 3.05)
XCTAssertEqual(aspect, .conjunction(3.05))
XCTAssertEqual(aspect?.symbol, "")
// Expect 171.0 relationship opposition
aspect = Aspect(pair: Pair<Planet, Planet>(a: .mars, b: .jupiter), date: Mock.date, orb: 10)
XCTAssertEqual(aspect?.remainder, -8.96)
XCTAssertEqual(aspect, .opposition(-8.96))
XCTAssertEqual(aspect?.symbol, "")
// Expect 124.0 relationship trine
XCTAssertEqual(aspect?.remainder, -8.96)
XCTAssertEqual(aspect, .opposition(-8.96))
XCTAssertEqual(aspect?.symbol, "")
// Expect 124.0 relationship trine
aspect = Aspect(pair: Pair<Planet, Planet>(a: .saturn, b: .jupiter), date: Mock.date, orb: 10)
XCTAssertEqual(aspect?.remainder, 4.65)
XCTAssertEqual(aspect, .trine(4.65))
XCTAssertEqual(aspect?.symbol, "")
// Expect 84.0 relationship square
XCTAssertEqual(aspect?.remainder, 4.65)
XCTAssertEqual(aspect, .trine(4.65))
XCTAssertEqual(aspect?.symbol, "")
// Expect 84.0 relationship square
aspect = Aspect(pair: Pair<Planet, Planet>(a: .venus, b: .moon), date: Mock.date, orb: 10)
XCTAssertEqual(aspect?.remainder, -5.07)
XCTAssertEqual(aspect, .square(-5.07))
XCTAssertEqual(aspect?.symbol, "◾️")
// Expect no aspect
XCTAssertNil(Aspect(pair: Pair<Planet, Planet>(a: .venus, b: .mars), date: Mock.date, orb: 5))
}
XCTAssertEqual(aspect?.remainder, -5.07)
XCTAssertEqual(aspect, .square(-5.07))
XCTAssertEqual(aspect?.symbol, "◾️")
// Expect no aspect
XCTAssertNil(Aspect(pair: Pair<Planet, Planet>(a: .venus, b: .mars), date: Mock.date, orb: 5))
}
func testAspectCount() {
let sunAspects = Planet.allCases.compactMap {
Aspect(pair: Pair<Planet, Planet>(a: .sun, b: $0),date: Mock.date, orb: 10)
@ -224,23 +243,23 @@ final class CelestialBodyTests: XCTestCase {
XCTAssertEqual(mercuryAspects.count, 4)
}
func testPlanetsOnAscendent() {
let houseSystem = Mock.makeHouses()
let ascendent = houseSystem.ascendent
let aspects = Planet.allCases.compactMap {
Aspect(a: ascendent.value,
b: Coordinate<Planet>(body: $0, date: Mock.date).value,
func testPlanetsOnAscendent() {
let houseSystem = Mock.makeHouses()
let ascendent = houseSystem.ascendent
let aspects = Planet.allCases.compactMap {
Aspect(a: ascendent.tropical.value,
b: Coordinate<Planet>(body: $0, date: Mock.date).tropical.value,
orb: 10)
}
XCTAssertEqual(aspects.compactMap { $0 }.count, 1)
}
func testPlanetaryStation() {
XCTAssertEqual(Station<Planet>(coordinate: Coordinate(body: .sun, date: Mock.date)), .direct)
XCTAssertEqual(Station<Planet>(coordinate: Coordinate(body: .mars, date: Mock.date)), .direct)
XCTAssertEqual(Station<Planet>(coordinate: Coordinate(body: .mercury, date: Mock.date)), .retrograde)
XCTAssertEqual(Station<Planet>(coordinate: Coordinate(body: .jupiter, date: Mock.date)), .retrograde)
}
}
XCTAssertEqual(aspects.compactMap { $0 }.count, 1)
}
func testPlanetaryStation() {
XCTAssertEqual(Station<Planet>(coordinate: Coordinate(body: .sun, date: Mock.date)), .direct)
XCTAssertEqual(Station<Planet>(coordinate: Coordinate(body: .mars, date: Mock.date)), .direct)
XCTAssertEqual(Station<Planet>(coordinate: Coordinate(body: .mercury, date: Mock.date)), .retrograde)
XCTAssertEqual(Station<Planet>(coordinate: Coordinate(body: .jupiter, date: Mock.date)), .retrograde)
}
func testAyanamsha() throws {
let date = try XCTUnwrap(Mock.date(from: "2021-03-09T12:31:00-0800"))
@ -268,11 +287,11 @@ final class CelestialBodyTests: XCTestCase {
altitude: 0)
XCTAssertEqual(moonRiseNYC.date?.description, "2021-03-15 12:25:55 +0000")
}
func testPlanetSettingTime() throws {
func testPlanetSettingTime() throws {
let timestamp = "2021-03-15"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let date = try XCTUnwrap(dateFormatter.date(from: timestamp))
let moonSet = SetTime<Planet>(date: date,
body: .moon,
@ -280,12 +299,12 @@ final class CelestialBodyTests: XCTestCase {
latitude: 52.52437)
XCTAssertEqual(moonSet.date?.description, "2021-03-15 19:25:58 +0000")
let dateB = try XCTUnwrap(dateFormatter.date(from: "2021-03-16"))
let sunsetTokyo = SetTime<Planet>(date: dateB,
body: .sun,
longitude: 139.69171,
latitude: 35.6895)
XCTAssertEqual(sunsetTokyo.date?.description, "2021-03-16 08:49:34 +0000")
}
let sunsetTokyo = SetTime<Planet>(date: dateB,
body: .sun,
longitude: 139.69171,
latitude: 35.6895)
XCTAssertEqual(sunsetTokyo.date?.description, "2021-03-16 08:49:34 +0000")
}
func testLunarPhase() throws {
let date = try Mock.date(from: "2021-03-21T11:11:00-0000")
@ -310,37 +329,39 @@ final class CelestialBodyTests: XCTestCase {
// Count from full to new
XCTAssertEqual(count, 29)
}
func testLunarMansion() throws {
var date = try Mock.date(from: "2021-04-12T01:11:00-0001")
let interval: TimeInterval = 60 * 60 * 12
var formatted = Set<String>()
for _ in 0...56 {
let moon = Coordinate<Planet>(body: .moon, date: date)
formatted.insert(moon.lunarMansion.formatted)
if #available(iOS 13.0, *) {
date = date.advanced(by: interval)
}
formatted.insert(moon.tropical.lunarMansion.formatted)
if #available(iOS 13.0, *) {
date = date.advanced(by: interval)
}
}
// Expect a unique description for each mansion.
XCTAssertEqual(formatted.count, 28)
}
func testSiderealCoordinateEarlyAries() throws {
let date = try Mock.date(from: "2021-03-25T01:11:00-0001")
let sun = Coordinate<Planet>(body: .sun, date: date)
XCTAssertEqual(sun.sign, .aries)
let siderealSun = SiderealCoordinate(coordinate: sun)
XCTAssertEqual(sun.tropical.sign, .aries)
let siderealSun = sun.sidereal
XCTAssertEqual(siderealSun.sign, .pisces)
}
static var allTests = [
("testSunZodiacCoordinate",testSunZodiacCoordinate,
"testMoonSiderealCoordinate", testMoonSiderealCoordinate,
"testPlanets", testPlanets,
"testAsteroids", testAsteroids,
"testZodiac", testZodiac,
"testLunarNodes", testLunarNodes,
"testLunarNorthNodes", testLunarNorthNodes,
"testLunarSouthNodes", testLunarSouthNodes,
"testLunarSouthNodeOffset", testLunarSouthNodeOffset,
"testAscendent", testAscendent,
"testHouses", testHouses,
"testAspects", testAspects,

View File

@ -9,77 +9,77 @@ final class FixedStarsTests: XCTestCase {
func testGalacticCenter() {
let galacticCenter = Coordinate<FixedStar>(body: .galacticCenter, date: Mock.date)
XCTAssertEqual(galacticCenter.formatted, "26 Degrees Sagittarius ♐︎ 40' 39''")
XCTAssertEqual(galacticCenter.tropical.formatted, "26 Degrees Sagittarius ♐︎ 40' 39''")
}
func testAldebaran() {
let aldebaran = Coordinate<FixedStar>(body: .aldebaran, date: Mock.date)
XCTAssertEqual(aldebaran.formatted, "9 Degrees Gemini ♊︎ 37' 24''")
XCTAssertEqual(aldebaran.tropical.formatted, "9 Degrees Gemini ♊︎ 37' 24''")
}
func testAntares() {
let antares = Coordinate<FixedStar>(body: .antares, date: Mock.date)
XCTAssertEqual(antares.formatted, "9 Degrees Sagittarius ♐︎ 35' 13''")
XCTAssertEqual(antares.tropical.formatted, "9 Degrees Sagittarius ♐︎ 35' 13''")
}
func testRegulus() {
let regulus = Coordinate<FixedStar>(body: .regulus, date: Mock.date)
XCTAssertEqual(regulus.formatted, "29 Degrees Leo ♌︎ 39' 26''")
XCTAssertEqual(regulus.tropical.formatted, "29 Degrees Leo ♌︎ 39' 26''")
}
func testSirius() {
let sirius = Coordinate<FixedStar>(body: .sirius, date: Mock.date)
XCTAssertEqual(sirius.formatted, "13 Degrees Cancer ♋︎ 55' 0''")
XCTAssertEqual(sirius.tropical.formatted, "13 Degrees Cancer ♋︎ 55' 0''")
}
func testSpica() {
let spica = Coordinate<FixedStar>(body: .spica, date: Mock.date)
XCTAssertEqual(spica.formatted, "23 Degrees Libra ♎︎ 39' 56''")
XCTAssertEqual(spica.tropical.formatted, "23 Degrees Libra ♎︎ 39' 56''")
}
func testAlgol() {
let algol = Coordinate<FixedStar>(body: .algol, date: Mock.date)
XCTAssertEqual(algol.formatted, "26 Degrees Taurus ♉︎ 0' 12''")
XCTAssertEqual(algol.tropical.formatted, "26 Degrees Taurus ♉︎ 0' 12''")
}
func testRigel() {
let rigel = Coordinate<FixedStar>(body: .rigel, date: Mock.date)
XCTAssertEqual(rigel.formatted, "16 Degrees Gemini ♊︎ 39' 51''")
XCTAssertEqual(rigel.tropical.formatted, "16 Degrees Gemini ♊︎ 39' 51''")
}
func testAltair() {
let altair = Coordinate<FixedStar>(body: .altair, date: Mock.date)
XCTAssertEqual(altair.formatted, "1 Degrees Aquarius ♒︎ 36' 12''")
XCTAssertEqual(altair.tropical.formatted, "1 Degrees Aquarius ♒︎ 36' 12''")
}
func testCapella() {
let capella = Coordinate<FixedStar>(body: .capella, date: Mock.date)
XCTAssertEqual(capella.formatted, "21 Degrees Gemini ♊︎ 41' 30''")
XCTAssertEqual(capella.tropical.formatted, "21 Degrees Gemini ♊︎ 41' 30''")
}
func testArcturus() {
let arcturus = Coordinate<FixedStar>(body: .arcturus, date: Mock.date)
XCTAssertEqual(arcturus.formatted, "24 Degrees Libra ♎︎ 3' 24''")
XCTAssertEqual(arcturus.tropical.formatted, "24 Degrees Libra ♎︎ 3' 24''")
}
func testProcyon() {
let procyon = Coordinate<FixedStar>(body: .procyon, date: Mock.date)
XCTAssertEqual(procyon.formatted, "25 Degrees Cancer ♋︎ 37' 6''")
XCTAssertEqual(procyon.tropical.formatted, "25 Degrees Cancer ♋︎ 37' 6''")
}
func testCastor() {
let castor = Coordinate<FixedStar>(body: .castor, date: Mock.date)
XCTAssertEqual(castor.formatted, "20 Degrees Cancer ♋︎ 4' 19''")
XCTAssertEqual(castor.tropical.formatted, "20 Degrees Cancer ♋︎ 4' 19''")
}
func testPollux() {
let pollux = Coordinate<FixedStar>(body: .pollux, date: Mock.date)
XCTAssertEqual(pollux.formatted, "23 Degrees Cancer ♋︎ 2' 55''")
XCTAssertEqual(pollux.tropical.formatted, "23 Degrees Cancer ♋︎ 2' 55''")
}
func testBetelgeuse() {
let betelgeuse = Coordinate<FixedStar>(body: .betelgeuse, date: Mock.date)
XCTAssertEqual(betelgeuse.formatted, "28 Degrees Gemini ♊︎ 35' 16''")
XCTAssertEqual(betelgeuse.tropical.formatted, "28 Degrees Gemini ♊︎ 35' 16''")
}
static var allTests = [

View File

@ -2,126 +2,126 @@ import XCTest
@testable import SwissEphemeris
final class PerformanceTests: XCTestCase {
private var date: Date!
private let latitude: Double = 37.5081153
private let longitude: Double = -122.2854528
override func setUpWithError() throws {
date = try Mock.date(from: "2021-06-21T01:11:00-0001")
JPLFileManager.setEphemerisPath()
}
func testCoordinatePerformance() throws {
measure {
for day in 0...1065 {
Planet.allCases.forEach {
XCTAssertNotNil(Coordinate<Planet>(body: $0, date: date))
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
}
}
}
}
}
func testHouseCuspsPerformance() {
measure {
for day in 0...365 {
HouseSystem.allCases.forEach {
XCTAssertNotNil(HouseCusps(date: date,
latitude: latitude,
longitude: longitude,
houseSystem: $0))
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
} else {
// Fallback on earlier versions
}
}
}
}
}
func testRiseTimePerfomance() {
measure {
for day in 0...730 {
XCTAssertNotNil(
RiseTime<Planet>(date: date,
body: .moon,
longitude: longitude,
latitude: latitude)
)
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
} else {
// Fallback on earlier versions
}
}
}
}
func testSetTimePerformance() {
measure {
for day in 0...730 {
XCTAssertNotNil(
SetTime<Planet>(date: date,
body: .moon,
longitude: longitude,
latitude: latitude)
)
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
} else {
// Fallback on earlier versions
}
}
}
}
func testLunationPerformance() {
measure {
for day in 0...730 {
XCTAssertNotNil(Lunation(date: date))
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
}
}
}
}
func testAspectPerformance() {
let PlanetPairs = PlanetPairs()
measure {
for day in 0...1365 {
PlanetPairs.pairs.forEach {
let _ = Aspect(pair: $0, date: date)
}
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
}
}
}
}
func testSpringEquinoxDatePerformance() {
measure {
var coordinate = Coordinate<Planet>(body: .sun, date: date)
while coordinate.value > 1.0 {
coordinate = Coordinate(body: .sun, date: coordinate.date.addingTimeInterval(60 * 60 * 12))
}
}
}
func testAutumnalEquinoxDatePerformance() {
measure {
var coordinate = Coordinate<Planet>(body: .sun, date: date)
while Int(coordinate.value) != 180 {
coordinate = Coordinate(body: .sun, date: coordinate.date.addingTimeInterval(60 * 60 * 12))
}
}
}
private var date: Date!
private let latitude: Double = 37.5081153
private let longitude: Double = -122.2854528
override func setUpWithError() throws {
date = try Mock.date(from: "2021-06-21T01:11:00-0001")
JPLFileManager.setEphemerisPath()
}
func testCoordinatePerformance() throws {
measure {
for day in 0...1065 {
Planet.allCases.forEach {
XCTAssertNotNil(Coordinate<Planet>(body: $0, date: date))
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
}
}
}
}
}
func testHouseCuspsPerformance() {
measure {
for day in 0...365 {
HouseSystem.allCases.forEach {
XCTAssertNotNil(HouseCusps(date: date,
latitude: latitude,
longitude: longitude,
houseSystem: $0))
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
} else {
// Fallback on earlier versions
}
}
}
}
}
func testRiseTimePerfomance() {
measure {
for day in 0...730 {
XCTAssertNotNil(
RiseTime<Planet>(date: date,
body: .moon,
longitude: longitude,
latitude: latitude)
)
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
} else {
// Fallback on earlier versions
}
}
}
}
func testSetTimePerformance() {
measure {
for day in 0...730 {
XCTAssertNotNil(
SetTime<Planet>(date: date,
body: .moon,
longitude: longitude,
latitude: latitude)
)
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
} else {
// Fallback on earlier versions
}
}
}
}
func testLunationPerformance() {
measure {
for day in 0...730 {
XCTAssertNotNil(Lunation(date: date))
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
}
}
}
}
func testAspectPerformance() {
let PlanetPairs = PlanetPairs()
measure {
for day in 0...1365 {
PlanetPairs.pairs.forEach {
let _ = Aspect(pair: $0, date: date)
}
if #available(iOS 13.0, *) {
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
}
}
}
}
func testSpringEquinoxDatePerformance() {
measure {
var coordinate = Coordinate<Planet>(body: .sun, date: date)
while coordinate.longitude > 1.0 {
coordinate = Coordinate(body: .sun, date: coordinate.date.addingTimeInterval(60 * 60 * 12))
}
}
}
func testAutumnalEquinoxDatePerformance() {
measure {
var coordinate = Coordinate<Planet>(body: .sun, date: date)
while Int(coordinate.tropical.value) != 180 {
coordinate = Coordinate(body: .sun, date: coordinate.date.addingTimeInterval(60 * 60 * 12))
}
}
}
func testBatchRequestPlanetCoordinatesDeprecated() {
measure {
PlanetsRequest(body: .moon).fetch(start: date, end: date.addingTimeInterval(60 * 60 * 24 * 30)) {
@ -135,7 +135,7 @@ final class PerformanceTests: XCTestCase {
let batch = await PlanetsRequest(body: .moon).fetch(start: date, end: date.addingTimeInterval(60 * 60 * 24 * 30))
XCTAssertEqual(batch.count, 43200)
}
static var allTests = [
("testCoordinatePerformance",testCoordinatePerformance,
"testHouseCuspsPerformance", testHouseCuspsPerformance,