# Path: camp/core/note.py
# def note(st):
#     """
#     note('Db3') -> Note(name='Db', octave=3)
#     """
#     if type(st) == Note:
#         return st
#     match = NOTE_SHORTCUT_REGEX.match(st)
#     if not match:
#         raise Exception("cannot form note from: %s" % st)
#     name = match.group(1)
#     octave = match.group(2)
#     if octave == '' or octave is None:
#         octave = 4
#     octave = int(octave)
#     return Note(name=name, octave=octave)
# 
# Path: camp/core/chord.py
# class Chord(object):
# 
#     def __init__(self, notes=None, root=None, typ=None):
# 
#         """
#         Constructs a chord, in different ways:
# 
#         notes = [ note('C4'), note('E4'), note('G4') ]
# 	chord = Chord(notes=notes)
# 
#         OR:
# 
#         chord = Chord(root=note('C4'), type='major')
# 
# 	OR:
# 
# 	chord = Chord(root='C4', type='major')
#         """
# 
#         self.notes = []
# 
#         if notes and root:
#             raise Exception("notes= and root= are mutually exclusive")
#         if notes is None and root is None:
#             raise Exception("specify either notes= or root=")
#         if root and typ is None:
#             raise Exception("typ= is required when using root=")
#         if typ and typ not in CHORD_TYPES:
#             raise Exception("unknown chord type: %s, expecting one of: %s" % (typ, CHORD_TYPES))
#         if isinstance(root, str):
#             root = note(root)
# 
#         if notes is not None:
#             for x in notes:
#                 assert type(x) == Note
#             self.notes = notes
# 
#         else:
#             self.typ = typ
#             self.root = root
#             self.notes = self._chordify()
# 
#     def copy(self):
#         notes = [ n.copy() for n in self.notes ]
#         return Chord(notes=notes)
# 
#     def _chordify(self):
#         """
#         Internal method.
#         Once self.root is set to a note, and self.typ is a chord type, like 'major', return the notes in the chord.
#         """
#         offsets = CHORD_TYPES[self.typ]
#         notes = []
#         notes.append(self.root)
#         for offset in offsets:
#             notes.append(self.root.transpose(semitones=offset))
#         return notes
# 
#     def __repr__(self):
#         """
#         A chord prints like:
#         Chord<C4,E4,G4>
#         """
#         note_list = ",".join([ n.short_name() for n in sorted(self.notes) ])
#         return "Chord<%s>" % note_list
# 
#     def __eq__(self, other):
#         """
#         Chords are equal if they contain the same notes.
#         """
#         return sorted(self.notes) == sorted(other.notes)
# 
#     def transpose(self, steps=None, semitones=None, octaves=None):
#         """
# 	Transposing a chord is returns a new chord with all of the notes transposed.
# 	"""
#         notes = [ note.transpose(steps=steps, octaves=octaves, semitones=None) for note in self.notes ]
#         return Chord(notes=notes)
# 
#     def invert(self, amount=1, octaves=1):
#         """
#         Inverts a chord.
#         ex: chord("c4 major").invert() -> chord(["E4","G4","C5"])
#         """
#         new_chord = self.copy()
#         if amount >= 1:
#             new_chord.notes[0] = new_chord.notes[0].transpose(octaves=octaves)
#         if amount >= 2:
#             new_chord.notes[1] = new_chord.notes[1].transpose(octaves=octaves)
#         if amount >= 3:
#             new_chord.notes[2] = new_chord.notes[2].transpose(octaves=octaves)
#         return new_chord
# 
# def chord(input):
#     """
#     Shortcut: chord(['C5', 'E5', 'G5') -> Chord object
#     Shortcut: chord('C5 dim') -> Chord object
#     """
#     if type(input) == list:
#         notes = [ note(n) for n in input ]
#         return Chord(notes)
#     else:
#         tokens = input.split()
#         assert len(tokens) == 2, "invalid chord expression: %s" % input
#         return Chord(root=note(tokens[0]), typ=tokens[1])


from camp.core.note import note
from camp.core.chord import Chord, chord
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""


class TestChord(object):

   def test_basics(self):

       notes = [ note('C4'), note('E4'), note('G4')]

       chord1 = Chord(notes=notes)
       assert chord1.notes[0] == note('C4')
       assert chord1.notes[1] == note('E4')
       assert chord1.notes[2] == note('G4')
       assert str(chord1) == 'Chord<C4,E4,G4>'

       chord2 = chord(['G4','C4','E4'])
       assert str(chord2) == 'Chord<C4,E4,G4>'
       assert chord1 == chord2

       assert chord(['C4','E4','G4']) != chord(['C4'])
       assert chord(['C4','E4','G4']) != chord(['C4', 'E4', 'G4', 'C5'])

   def test_chord_types_and_shortcuts(self):

       assert Chord(root=note('C4'), typ='major') == chord(['C4', 'E4', 'G4'])

# Path: camp/core/note.py
# def note(st):
#     """
#     note('Db3') -> Note(name='Db', octave=3)
#     """
#     if type(st) == Note:
#         return st
#     match = NOTE_SHORTCUT_REGEX.match(st)
#     if not match:
#         raise Exception("cannot form note from: %s" % st)
#     name = match.group(1)
#     octave = match.group(2)
#     if octave == '' or octave is None:
#         octave = 4
#     octave = int(octave)
#     return Note(name=name, octave=octave)
# 
# Path: camp/core/chord.py
# class Chord(object):
# 
#     def __init__(self, notes=None, root=None, typ=None):
# 
#         """
#         Constructs a chord, in different ways:
# 
#         notes = [ note('C4'), note('E4'), note('G4') ]
# 	chord = Chord(notes=notes)
# 
#         OR:
# 
#         chord = Chord(root=note('C4'), type='major')
# 
# 	OR:
# 
# 	chord = Chord(root='C4', type='major')
#         """
# 
#         self.notes = []
# 
#         if notes and root:
#             raise Exception("notes= and root= are mutually exclusive")
#         if notes is None and root is None:
#             raise Exception("specify either notes= or root=")
#         if root and typ is None:
#             raise Exception("typ= is required when using root=")
#         if typ and typ not in CHORD_TYPES:
#             raise Exception("unknown chord type: %s, expecting one of: %s" % (typ, CHORD_TYPES))
#         if isinstance(root, str):
#             root = note(root)
# 
#         if notes is not None:
#             for x in notes:
#                 assert type(x) == Note
#             self.notes = notes
# 
#         else:
#             self.typ = typ
#             self.root = root
#             self.notes = self._chordify()
# 
#     def copy(self):
#         notes = [ n.copy() for n in self.notes ]
#         return Chord(notes=notes)
# 
#     def _chordify(self):
#         """
#         Internal method.
#         Once self.root is set to a note, and self.typ is a chord type, like 'major', return the notes in the chord.
#         """
#         offsets = CHORD_TYPES[self.typ]
#         notes = []
#         notes.append(self.root)
#         for offset in offsets:
#             notes.append(self.root.transpose(semitones=offset))
#         return notes
# 
#     def __repr__(self):
#         """
#         A chord prints like:
#         Chord<C4,E4,G4>
#         """
#         note_list = ",".join([ n.short_name() for n in sorted(self.notes) ])
#         return "Chord<%s>" % note_list
# 
#     def __eq__(self, other):
#         """
#         Chords are equal if they contain the same notes.
#         """
#         return sorted(self.notes) == sorted(other.notes)
# 
#     def transpose(self, steps=None, semitones=None, octaves=None):
#         """
# 	Transposing a chord is returns a new chord with all of the notes transposed.
# 	"""
#         notes = [ note.transpose(steps=steps, octaves=octaves, semitones=None) for note in self.notes ]
#         return Chord(notes=notes)
# 
#     def invert(self, amount=1, octaves=1):
#         """
#         Inverts a chord.
#         ex: chord("c4 major").invert() -> chord(["E4","G4","C5"])
#         """
#         new_chord = self.copy()
#         if amount >= 1:
#             new_chord.notes[0] = new_chord.notes[0].transpose(octaves=octaves)
#         if amount >= 2:
#             new_chord.notes[1] = new_chord.notes[1].transpose(octaves=octaves)
#         if amount >= 3:
#             new_chord.notes[2] = new_chord.notes[2].transpose(octaves=octaves)
#         return new_chord
# 
# def chord(input):
#     """
#     Shortcut: chord(['C5', 'E5', 'G5') -> Chord object
#     Shortcut: chord('C5 dim') -> Chord object
#     """
#     if type(input) == list:
#         notes = [ note(n) for n in input ]
#         return Chord(notes)
#     else:
#         tokens = input.split()
#         assert len(tokens) == 2, "invalid chord expression: %s" % input
#         return Chord(root=note(tokens[0]), typ=tokens[1])


# Path: tests/chord.py
from camp.core.note import note
from camp.core.chord import Chord, chord

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""


class TestChord(object):

   def test_basics(self):

       notes = [ note('C4'), note('E4'), note('G4')]

       chord1 = Chord(notes=notes)
       assert chord1.notes[0] == note('C4')
       assert chord1.notes[1] == note('E4')
       assert chord1.notes[2] == note('G4')
       assert str(chord1) == 'Chord<C4,E4,G4>'

       chord2 = chord(['G4','C4','E4'])
       assert str(chord2) == 'Chord<C4,E4,G4>'
       assert chord1 == chord2

       assert chord(['C4','E4','G4']) != chord(['C4'])
       assert chord(['C4','E4','G4']) != chord(['C4', 'E4', 'G4', 'C5'])

   def test_chord_types_and_shortcuts(self):

       assert Chord(root=note('C4'), typ='major') == chord(['C4', 'E4', 'G4'])

       assert Chord(root=note('C4'), typ='minor') == chord(['C4', 'Eb4', 'G4'])