Skip to content

Commit

Permalink
Add tests, fix declaration error
Browse files Browse the repository at this point in the history
  • Loading branch information
roux buciu committed May 2, 2020
1 parent 686c143 commit 2cb37d6
Show file tree
Hide file tree
Showing 10 changed files with 475 additions and 36 deletions.
Binary file modified Swift Musicology/.DS_Store
Binary file not shown.
18 changes: 17 additions & 1 deletion Swift Musicology/Swift Musicology.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
objects = {

/* Begin PBXBuildFile section */
0BA905CF245DCFA800D83B29 /* PitchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA905CE245DCFA800D83B29 /* PitchTests.swift */; };
0BA905D1245DCFB400D83B29 /* TempoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA905D0245DCFB400D83B29 /* TempoTests.swift */; };
0BA905D3245DCFC300D83B29 /* Scale Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA905D2245DCFC300D83B29 /* Scale Tests.swift */; };
0BA905D5245DCFD100D83B29 /* ChordTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA905D4245DCFD100D83B29 /* ChordTests.swift */; };
0BFB65E1245DBD280019EBCB /* SwiftMusicology_iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BFB65DF245DBD280019EBCB /* SwiftMusicology_iOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
0BFB65EE245DBD380019EBCB /* SwiftMusicology_watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BFB65EC245DBD380019EBCB /* SwiftMusicology_watchOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
0BFB65FB245DBD420019EBCB /* SwiftMusicology_tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BFB65F9245DBD420019EBCB /* SwiftMusicology_tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -75,6 +79,10 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
0BA905CE245DCFA800D83B29 /* PitchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PitchTests.swift; sourceTree = "<group>"; };
0BA905D0245DCFB400D83B29 /* TempoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempoTests.swift; sourceTree = "<group>"; };
0BA905D2245DCFC300D83B29 /* Scale Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Scale Tests.swift"; sourceTree = "<group>"; };
0BA905D4245DCFD100D83B29 /* ChordTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChordTests.swift; sourceTree = "<group>"; };
0BFB65B6245DBC0E0019EBCB /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = "<group>"; };
0BFB65B7245DBC0E0019EBCB /* Info-Mac.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Mac.plist"; sourceTree = "<group>"; };
0BFB65B8245DBC0E0019EBCB /* Info-TV.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-TV.plist"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -258,8 +266,12 @@
1207E0D221AAE05300915CCD /* Swift MusicologyTests */ = {
isa = PBXGroup;
children = (
1207E0D321AAE05300915CCD /* Swift_MusicologyTests.swift */,
1207E0D521AAE05300915CCD /* Info.plist */,
1207E0D321AAE05300915CCD /* Swift_MusicologyTests.swift */,
0BA905CE245DCFA800D83B29 /* PitchTests.swift */,
0BA905D0245DCFB400D83B29 /* TempoTests.swift */,
0BA905D2245DCFC300D83B29 /* Scale Tests.swift */,
0BA905D4245DCFD100D83B29 /* ChordTests.swift */,
);
path = "Swift MusicologyTests";
sourceTree = "<group>";
Expand Down Expand Up @@ -571,7 +583,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0BA905CF245DCFA800D83B29 /* PitchTests.swift in Sources */,
0BA905D1245DCFB400D83B29 /* TempoTests.swift in Sources */,
1207E0D421AAE05300915CCD /* Swift_MusicologyTests.swift in Sources */,
0BA905D3245DCFC300D83B29 /* Scale Tests.swift in Sources */,
0BA905D5245DCFD100D83B29 /* ChordTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,30 @@
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>SwiftMusicology iOS.xcscheme_^#shared#^_</key>
<key>Swift MusicologyTests.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>SwiftMusicology iOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>SwiftMusicology macOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
<integer>3</integer>
</dict>
<key>SwiftMusicology tvOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
<integer>0</integer>
</dict>
<key>SwiftMusicology watchOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
<integer>4</integer>
</dict>
<key>SwiftMusicology.xcscheme_^#shared#^_</key>
<dict>
Expand Down
40 changes: 23 additions & 17 deletions Swift Musicology/Swift Musicology/ChordProgression.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,24 @@
import Foundation

/// A struct for storing custom progressions.
public struct CustomChordProgression: Codable, CustomStringConvertible {
public struct CustomChordProgression: Codable {
/// Name of the progression.
public var name: String
/// Chord progression with `ChordProgresion.custom` type.
public var progression: ChordProgression


// MARK: CustomStringConvertible
}

extension CustomChordProgression: CustomStringConvertible {
public var description: String {
return name
}

}


// MARK: - ChordProgressionNode

/// A node of chord progression in intervals.
public enum ChordProgressionNode: Int, CustomStringConvertible, Codable {
public enum ChordProgressionNode: Int, Codable {
/// First-degree node
case i
/// Second-degree node
Expand Down Expand Up @@ -63,9 +64,9 @@ public enum ChordProgressionNode: Int, CustomStringConvertible, Codable {

/// All nodes.
public static let all: [ChordProgressionNode] = [.i, .ii, .iii, .iv, .v, .vi, .vii]
// MARK: CustomStringConvertible
}

extension ChordProgressionNode: CustomStringConvertible {
/// Returns roman numeric string of the node.
public var description: String {
switch self {
Expand All @@ -80,8 +81,11 @@ public enum ChordProgressionNode: Int, CustomStringConvertible, Codable {
}
}


// MARK: ChordProgression Definition

/// Chord progression enum that you can create hard-coded and custom progressions.
public enum ChordProgression: CustomStringConvertible, Codable {
public struct ChordProgression {
/// All nodes from first to seventh.
public static let allNodes = ChordProgression(nodes: [.i, .ii, .iii, .iv, .v, .vi, .vii])
/// I - V - VI - IV progression.
Expand Down Expand Up @@ -170,19 +174,21 @@ public enum ChordProgression: CustomStringConvertible, Codable {
}
return chords
}
}

// MARK: CustomStringConvertible

extension ChordProgression: CustomStringConvertible {
/// Returns the chord progression name.
public var description: String {
if self == ChordProgression.allNodes {
return "All"
}
return nodes.map({ "\($0)" }).joined(separator: " - ")
}
}

// MARK: Codable

extension ChordProgression: Codable {
/// Codable protocol `CodingKey`s
///
/// - nodes: Coding key for the nodes.
Expand All @@ -208,10 +214,10 @@ public enum ChordProgression: CustomStringConvertible, Codable {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(nodes, forKey: .nodes)
}
}

// MARK: Equatable

extension ChordProgression: Equatable {
public static func == (lhs: ChordProgression, rhs: ChordProgression) -> Bool {
return lhs.nodes == rhs.nodes
return lhs.nodes == rhs.nodes
}
}
149 changes: 149 additions & 0 deletions Swift Musicology/Swift MusicologyTests/ChordTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
//
// ChordTests.swift
// Swift MusicologyTests
//
// Created by roux g. buciu on 2020-05-02.
// Copyright © 2020 roux g. buciu. All rights reserved.
//

import XCTest
@testable import Swift_Musicology

class ChordTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.

}

override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}

func testChords() {
let cmajNotes: [Key] = [Key(type: .c), Key(type: .e), Key(type: .g)]
let cmaj = Chord(type: ChordType(third: .major), key: Key(type: .c))
XCTAssert(cmajNotes == cmaj.keys)

let cminNotes: [Key] = [
Key(type: .c),
Key(type: .e, accidental: .flat),
Key(type: .g),
]
let cmin = Chord(type: ChordType(third: .minor), key: Key(type: .c))
XCTAssert(cminNotes == cmin.keys)

let c13Notes: [Pitch] = [
Pitch(key: Key(type: .c), octave: 1),
Pitch(key: Key(type: .e), octave: 1),
Pitch(key: Key(type: .g), octave: 1),
Pitch(key: Key(type: .b, accidental: .flat), octave: 1),
Pitch(key: Key(type: .d), octave: 2),
Pitch(key: Key(type: .f), octave: 2),
Pitch(key: Key(type: .a), octave: 2),
]
let c13 = Chord(
type: ChordType(
third: .major,
seventh: .dominant,
extensions: [
ChordExtensionType(type: .thirteenth),
]
),
key: Key(type: .c)
)
XCTAssert(c13.pitches(octave: 1) === c13Notes)

let cm13Notes: [Pitch] = [
Pitch(key: Key(type: .c), octave: 1),
Pitch(key: Key(type: .e, accidental: .flat), octave: 1),
Pitch(key: Key(type: .g), octave: 1),
Pitch(key: Key(type: .b, accidental: .flat), octave: 1),
Pitch(key: Key(type: .d), octave: 2),
Pitch(key: Key(type: .f), octave: 2),
Pitch(key: Key(type: .a), octave: 2),
]
let cm13 = Chord(
type: ChordType(
third: .minor,
seventh: .dominant,
extensions: [
ChordExtensionType(type: .thirteenth),
]
),
key: Key(type: .c)
)
XCTAssert(cm13.pitches(octave: 1) === cm13Notes)

let minorIntervals: [Interval] = [.P1, .m3, .P5]
guard let minorChord = ChordType(intervals: minorIntervals.map({ $0 })) else { return XCTFail() }
XCTAssert(minorChord == ChordType(third: .minor))

let majorIntervals: [Interval] = [.P1, .M3, .P5]
guard let majorChord = ChordType(intervals: majorIntervals.map({ $0 })) else { return XCTFail() }
XCTAssert(majorChord == ChordType(third: .major))

let cmadd13Notes: [Pitch] = [
Pitch(key: Key(type: .c), octave: 1),
Pitch(key: Key(type: .e, accidental: .flat), octave: 1),
Pitch(key: Key(type: .g), octave: 1),
Pitch(key: Key(type: .a), octave: 2),
]
let cmadd13 = Chord(
type: ChordType(
third: .minor,
extensions: [ChordExtensionType(type: .thirteenth)]
),
key: Key(type: .c)
)
XCTAssert(cmadd13.pitches(octave: 1) === cmadd13Notes)
}

func testRomanNumerics() {
let cmaj = Scale(type: .major, key: Key(type: .c))
let cmin = Scale(type: .minor, key: Key(type: .c))
let cmajNumerics = ["I", "ii", "iii", "IV", "V", "vi", "vii°"]
let cminNumerics = ["i", "ii°", "III", "iv", "v", "VI", "VII"]
let cmajChords = cmaj.harmonicField(for: .triad)
let cminChords = cmin.harmonicField(for: .triad)
XCTAssertEqual(cmajNumerics, cmajChords.compactMap({ $0?.romanNumeric(for: cmaj) }))
XCTAssertEqual(cminNumerics, cminChords.compactMap({ $0?.romanNumeric(for: cmin) }))
}

func testInversions() {
let c7 = Chord(
type: ChordType(third: .major, seventh: .dominant),
key: Key(type: .c)
)
let c7Inversions = [
[
Pitch(key: Key(type: .c), octave: 1),
Pitch(key: Key(type: .e), octave: 1),
Pitch(key: Key(type: .g), octave: 1),
Pitch(key: Key(type: .b, accidental: .flat), octave: 1),
],
[
Pitch(key: Key(type: .e), octave: 1),
Pitch(key: Key(type: .g), octave: 1),
Pitch(key: Key(type: .b, accidental: .flat), octave: 1),
Pitch(key: Key(type: .c), octave: 2),
],
[
Pitch(key: Key(type: .g), octave: 1),
Pitch(key: Key(type: .b, accidental: .flat), octave: 1),
Pitch(key: Key(type: .c), octave: 2),
Pitch(key: Key(type: .e), octave: 2),
],
[
Pitch(key: Key(type: .b, accidental: .flat), octave: 1),
Pitch(key: Key(type: .c), octave: 2),
Pitch(key: Key(type: .e), octave: 2),
Pitch(key: Key(type: .g), octave: 2),
],
]
for (index, chord) in c7.inversions.enumerated() {
XCTAssert(chord.pitches(octave: 1) === c7Inversions[index])
}
}
}
Loading

0 comments on commit 2cb37d6

Please sign in to comment.