Package jptests :: Package data :: Module init
[hide private]
[frames] | no frames]

Source Code for Module jptests.data.init

  1  """Unit tests for jazzparser.data module 
  2   
  3  """ 
  4  """ 
  5  ============================== License ======================================== 
  6   Copyright (C) 2008, 2010-12 University of Edinburgh, Mark Granroth-Wilding 
  7    
  8   This file is part of The Jazz Parser. 
  9    
 10   The Jazz Parser is free software: you can redistribute it and/or modify 
 11   it under the terms of the GNU General Public License as published by 
 12   the Free Software Foundation, either version 3 of the License, or 
 13   (at your option) any later version. 
 14    
 15   The Jazz Parser is distributed in the hope that it will be useful, 
 16   but WITHOUT ANY WARRANTY; without even the implied warranty of 
 17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 18   GNU General Public License for more details. 
 19    
 20   You should have received a copy of the GNU General Public License 
 21   along with The Jazz Parser.  If not, see <http://www.gnu.org/licenses/>. 
 22   
 23  ============================ End license ====================================== 
 24   
 25  """ 
 26  __author__ = "Mark Granroth-Wilding <mark.granroth-wilding@ed.ac.uk>"  
 27   
 28  import unittest 
 29  from jazzparser.data import Chord, DerivationTrace, Fraction 
 30   
31 -class TestChord(unittest.TestCase):
32 """ 33 Tests for the various ways of creating instances of Chord. 34 35 """ 36 ALLOWED_NUMERALS = [ 37 ("C", 0, "C" ), 38 ("Db", 1, "Db"), 39 ("D", 2, "D" ), 40 ("Eb", 3, "Eb"), 41 ("E", 4, "E" ), 42 ("F", 5, "F" ), 43 ("F#", 6, "Gb"), 44 ("G", 7, "G" ), 45 ("G#", 8, "Ab"), 46 ("A", 9, "A" ), 47 ("Bb", 10, "Bb"), 48 ("B", 11, "B" ), 49 ] 50
51 - def test_from_numerals(self):
52 """ 53 Try creating chords using all possbile numerals and check the numeral 54 and root get set correctly. 55 56 """ 57 for numeral,root,trg_num in self.ALLOWED_NUMERALS: 58 # Try creating a Chord with each numeral 59 c = Chord(numeral) 60 # Check it has the right numeral 61 self.assertEqual(trg_num, c.root_numeral) 62 # and the right root number 63 self.assertEqual(root, c.root)
64
65 - def test_set_root(self):
66 """ 67 Try setting the root or numeral after a chord is created and check 68 that both values get correctly set. 69 70 """ 71 c = Chord(self.ALLOWED_NUMERALS[0][0]) 72 for numeral,root,trg_num in self.ALLOWED_NUMERALS: 73 # Try setting the root and check root and numeral are correct 74 c.root = root 75 self.assertEqual(root, c.root) 76 self.assertEqual(trg_num, c.root_numeral) 77 for numeral,root,trg_num in self.ALLOWED_NUMERALS: 78 # Try setting the numeral and check root and numeral are correct 79 c.root_numeral = numeral 80 self.assertEqual(root, c.root) 81 self.assertEqual(trg_num, c.root_numeral)
82
83 - def test_init_type(self):
84 """ 85 Try creating chords with a particular type and check (a) that they 86 successfully create a chord and (b) that the chord has the right type. 87 88 """ 89 for ctype in Chord.TYPE_SYMBOLS.values(): 90 c = Chord("C", type=ctype) 91 self.assertEqual(c.type, ctype)
92
93 - def test_interval(self):
94 """ 95 Try getting the interval between two chords and check it comes out 96 as expected. 97 98 """ 99 # Some randomly chosen tests 100 tests = [ 101 (0, "C", "C", True), 102 (2, "F", "G", False), 103 (4, "D", "F#", False), 104 (6, "B", "F", True), 105 (8, "F", "Db", False), 106 (10, "Ab", "F#", False) 107 ] 108 for interval,lower,upper,invertible in tests: 109 c0 = Chord(lower) 110 c1 = Chord(upper) 111 self.assertEqual(interval, Chord.interval(c0,c1)) 112 # Try inverting the interval and check it's only the same in the 113 # cases where the interval is its own inverse 114 if invertible: 115 self.assertEqual(interval, Chord.interval(c1,c0)) 116 else: 117 self.assertNotEqual(interval, Chord.interval(c1,c0))
118
119 - def test_from_name(self):
120 """ 121 from_name covers a lot of possible chord instances. Here we just test 122 a sample of textual chords and check the instance gets the right 123 attributes out of the name. 124 It's by no means exhaustive! 125 126 """ 127 tests = [ 128 # Name, root, type, additions, tetrad type 129 ("C", 0, "", "", ""), 130 ("F#m7", 6, "m7", "", "m7"), 131 ("G7(9)", 7, "7", "9", "7"), 132 ("A(9)", 9, "", "9", "7"), 133 ("Dsus4", 2, "sus4", "", "sus4"), 134 ("Esus4,7", 4, "sus4,7","", "sus4,7"), 135 ("Esus4(9)", 4, "sus4", "9", "sus4,7"), 136 ("Fm,M7(+11)", 5, "m,M7", "+11", "m,M7"), 137 ] 138 for name,root,ctype,additions,tetrad in tests: 139 c = Chord.from_name(name) 140 self.assertEqual(root, c.root) 141 self.assertEqual(ctype, c.type) 142 self.assertEqual(additions, c.additions) 143 self.assertEqual(tetrad, c.tetrad_type)
144 145
146 -class TestDerivationTraceHalfspan(unittest.TestCase):
147 """ 148 A derivation trace is quite a simple data structure. We test that it 149 behaves correctly when used to store a trace of derivations in the 150 halfspan formalism. 151 152 This is specific to the L{halfspan 153 formalism<jazzparser.formalisms.music_halfspan>}, the current and 154 only supported formalism at the time 155 of writing. If the formalism is deprecated these tests will need to 156 be rewritten for the new formalism and these tests should be removed. 157 158 """
159 - def setUp(self):
160 from jazzparser.formalisms.music_halfspan.rules import ApplicationRule 161 from jazzparser.formalisms.music_halfspan.syntax import AtomicCategory, \ 162 ComplexCategory, HalfCategory, Sign, Slash 163 from jazzparser.formalisms.music_halfspan.semantics import \ 164 DummyLogicalForm, Semantics 165 from jazzparser.grammar import Grammar 166 167 # Use the default grammar 168 self.grammar = Grammar() 169 170 # Get a rule to instantiate: forward application 171 self.rule = self.grammar.rules_by_name['appf'] 172 # Create some categories we can store as if the rule applied to them 173 # Create an atomic category 174 self.cat0 = AtomicCategory( 175 HalfCategory("I"), 176 HalfCategory("I") ) 177 # Create a complex category that could be applied to the atomic one 178 self.cat1 = ComplexCategory( 179 HalfCategory("V", function="D"), 180 Slash(True), 181 HalfCategory("I", function=["D","T"]) ) 182 # An atomic category, as if 0 was applied to 1 183 self.cat2 = AtomicCategory( 184 HalfCategory("V", function="D"), 185 HalfCategory("I") ) 186 187 # A dummy semantics to use for all signs 188 dummy_sem = Semantics(DummyLogicalForm()) 189 190 # Create signs from the categories 191 self.sign0 = Sign(self.cat0, dummy_sem.copy()) 192 self.sign1 = Sign(self.cat1, dummy_sem.copy()) 193 self.sign2 = Sign(self.cat2, dummy_sem.copy())
194
196 """ 197 Just creates a derivation trace in the simplest possible way, as if 198 it's a lexical production. 199 200 """ 201 trace = DerivationTrace(self.sign0, word="IM7")
202
203 - def test_create_rule_trace(self):
204 """ 205 First creates two lexical traces (as tested in 206 L{test_create_lexical_trace}) and then a trace for applying the 207 application rule to them. The rule is not actually applied, we 208 just pretend it was. 209 210 """ 211 trace0 = DerivationTrace(self.sign0, word="IM7") 212 trace1 = DerivationTrace(self.sign1, word="V7") 213 # Pretend the rule was applied to the above signs 214 trace2 = DerivationTrace(self.sign2, rule=self.rule, args=[trace1, trace0])
215
217 """ 218 Creates two derivation traces like that created in 219 L{test_create_rule_trace} and combines them into a single trace. 220 221 """ 222 trace0 = DerivationTrace(self.sign0, word="IM7") 223 trace1 = DerivationTrace(self.sign1, word="V7") 224 # Pretend the rule was applied to the above signs 225 trace2 = DerivationTrace(self.sign2, rule=self.rule, args=[trace1, trace0]) 226 # This rule app is actually the same as trace2, but the DT shouldn't 227 # care about that, as it's not clever enough 228 trace2.add_rule(self.rule, [trace1, trace0])
229
230 - def test_combined_traces(self):
231 """ 232 Does the same thing as L{test_multiple_source_trace}, but does it by 233 creating two DTs and adding the rules from one to the other. 234 235 """ 236 trace0 = DerivationTrace(self.sign0, word="IM7") 237 trace1 = DerivationTrace(self.sign1, word="V7") 238 # Pretend the rule was applied to the above signs 239 trace2 = DerivationTrace(self.sign2, rule=self.rule, args=[trace1, trace0]) 240 # This is actually the same as trace2 241 trace2b = DerivationTrace(self.sign2, rule=self.rule, args=[trace1, trace0]) 242 trace2.add_rules_from_trace(trace2b)
243 244
245 -class TestFraction(unittest.TestCase):
246 """ 247 Tests for L{jazzparser.data.Fraction}. 248 249 """
250 - def test_create_int(self):
251 """ Simplest instantiation: int """ 252 f = Fraction(9) 253 self.assertEqual(f, 9)
254
255 - def test_create_fraction(self):
256 """ Simplest instantiation: fraction """ 257 f = Fraction(9, 10)
258
259 - def test_simplify(self):
260 """ 261 Basic test of simplification of fractions. 262 263 """ 264 f0 = Fraction(9, 10) 265 f1 = Fraction(18, 20) 266 self.assertEqual(f0, f1) 267 f2 = Fraction(17, 20) 268 self.assertNotEqual(f0, f2)
269
270 - def test_create_string(self):
271 """ 272 Test creating a fraction from a string representation. 273 274 """ 275 f0 = Fraction("1 1/4") 276 self.assertEqual(f0, Fraction(5, 4)) 277 f1 = Fraction("5") 278 self.assertEqual(f1, Fraction(5)) 279 f2 = Fraction("5/4") 280 self.assertEqual(f2, Fraction(5, 4)) 281 for invalid in ["", "1.5", "1/1/1", "5 5", "4\\5", "a", "X"]: 282 self.assertRaises(Fraction.ValueError, Fraction, invalid)
283
284 - def test_reparse_string(self):
285 """ 286 Create some random fractions, get their string representation and check 287 the this can by used to correctly reinstantiate the fraction. 288 289 """ 290 from random import randint 291 for i in range(50): 292 # Create a random fraction 293 f0 = Fraction(randint(0,100), randint(1,100)) 294 f0_str = str(f0) 295 self.assertEqual(f0, Fraction(f0_str))
296
297 - def test_zero_denominator(self):
298 """ 299 Setting a Fraction's denominator to 0 should raise an error. 300 301 """ 302 self.assertRaises(ZeroDivisionError, Fraction, 5, 0) 303 f = Fraction(1) 304 self.assertRaises(ZeroDivisionError, lambda x: f / x, 0)
305
306 - def test_add(self):
307 """ 308 Try adding Fractions together. 309 310 """ 311 f0 = Fraction(5) 312 f1 = Fraction(6) 313 self.assertEqual(f0+f1, 11) 314 f2 = Fraction(7, 12) + f0 315 self.assertEqual(f2, Fraction("5 7/12")) 316 self.assertEqual(f2, Fraction(67, 12))
317
318 - def test_neg(self):
319 """ Try negating Fractions """ 320 f0 = Fraction(5, 7) 321 self.assertEqual(-f0, Fraction(-5, 7)) 322 f1 = Fraction("5 4/5") 323 self.assertEqual(-f1, Fraction("-5 4/5"))
324
325 - def test_sub(self):
326 """ Test subtraction """ 327 f0 = Fraction(5) 328 f1 = Fraction(6) 329 self.assertEqual(f0-f1, -1) 330 f2 = Fraction(7, 12) - f0 331 self.assertEqual(f2, Fraction("-4 5/12")) 332 self.assertEqual(f2, Fraction(-53, 12))
333
334 - def test_mul(self):
335 """ Test multiplication """ 336 f0 = Fraction(1,2) * Fraction(3) 337 self.assertEqual(f0, Fraction(3,2)) 338 f1 = Fraction(5,7) * Fraction(3,9) 339 self.assertEqual(f1, Fraction(15, 63)) 340 f2 = Fraction(-5,7) * Fraction(3,-9) 341 self.assertEqual(f2, f1)
342
343 - def test_div(self):
344 """ Test division """ 345 f0 = Fraction(1,2) / 3 346 self.assertEqual(f0, Fraction(1,6)) 347 f0 = Fraction(1,2) / Fraction(3) 348 self.assertEqual(f0, Fraction(1,6)) 349 f1 = Fraction(5,7) / Fraction(3,9) 350 self.assertEqual(f1, Fraction(45, 21)) 351 f2 = Fraction(-5,7) / Fraction(3,-9) 352 self.assertEqual(f2, f1) 353 f3 = Fraction(5, 7) / 0.5 354 self.assertEqual(f3, 10.0/7.0)
355
356 - def test_float(self):
357 """ Conversion to float """ 358 from random import randint 359 for i in range(50): 360 n = randint(0, 100) 361 d = randint(1, 100) 362 self.assertEqual(float(Fraction(n,d)), float(n)/float(d))
363
364 - def test_long(self):
365 """ Conversion to long """ 366 from random import randint 367 for i in range(50): 368 n = randint(0, 100) 369 d = randint(1, 100) 370 self.assertEqual(long(Fraction(n,d)), long(n)/long(d))
371
372 - def test_int(self):
373 """ Conversion to int """ 374 from random import randint 375 for i in range(50): 376 n = randint(0, 100) 377 d = randint(1, 100) 378 self.assertEqual(int(Fraction(n,d)), n/d)
379
380 - def test_equal(self):
381 """ Test that equal Fractions evaluate as equal """ 382 from random import randint 383 for i in range(10): 384 n = randint(0, 100) 385 d = randint(1, 100) 386 self.assertEqual(Fraction(n,d), Fraction(n,d)) 387 self.assertEqual(Fraction(50,4), Fraction("12 1/2")) 388 self.assertEqual(Fraction(50,4), Fraction(25,2)) 389 self.assertEqual(Fraction(7,6), --Fraction(7,6)) 390 f = Fraction(7, 19) 391 self.assertEqual(f, f/Fraction(6, 17)*Fraction(12, 34))
392 393 394 if __name__ == '__main__': 395 unittest.main() 396