1+ /* eslint-disable no-trailing-spaces */
2+ /* eslint-disable indent */
3+ /* eslint-disable quotes */
4+ /* eslint-disable no-undef */
5+ // Mock global window for btoa function
6+ global . _ = jest . fn ( ( str ) => str ) ;
7+ global . window = {
8+ btoa : jest . fn ( ( str ) => Buffer . from ( str , "utf8" ) . toString ( "base64" ) )
9+ } ;
10+
11+ const {
12+ setOctaveRatio,
13+ getOctaveRatio,
14+ TEMPERAMENT ,
15+ TEMPERAMENTS ,
16+ INITIALTEMPERAMENTS ,
17+ PreDefinedTemperaments,
18+ getTemperamentsList,
19+ getTemperament,
20+ getTemperamentKeys,
21+ addTemperamentToList,
22+ addTemperamentToDictionary,
23+ updateTemperaments,
24+ deleteTemperamentFromList,
25+ DEFAULTINVERT ,
26+ DEFAULTMODE ,
27+ customMode,
28+ getInvertMode,
29+ getIntervalNumber,
30+ getIntervalDirection,
31+ getIntervalRatio,
32+ getModeNumbers,
33+ getDrumIndex,
34+ getDrumName,
35+ getDrumSymbol,
36+ getFilterTypes
37+ } = require ( "../musicutils" ) ;
38+
39+
40+ describe ( "musicutils" , ( ) => {
41+ it ( "should set and get Octave Ratio" , ( ) => {
42+ setOctaveRatio ( 4 ) ;
43+ const octaveR = getOctaveRatio ( ) ;
44+ expect ( octaveR ) . toBe ( 4 ) ;
45+ } ) ;
46+ } ) ;
47+
48+ describe ( "Temperament Functions" , ( ) => {
49+ test ( "getTemperamentsList should return the list of temperaments" , ( ) => {
50+ expect ( getTemperamentsList ( ) ) . toEqual ( [
51+ [ _ ( "Equal (12EDO)" ) , "equal" , "equal" ] ,
52+ [ _ ( "Equal (5EDO)" ) , "equal5" , "equal5" ] ,
53+ [ _ ( "Equal (7EDO)" ) , "equal7" , "equal7" ] ,
54+ [ _ ( "Equal (19EDO)" ) , "equal19" , "equal19" ] ,
55+ [ _ ( "Equal (31EDO)" ) , "equal31" , "equal31" ] ,
56+ [ _ ( "5-limit Just Intonation" ) , "just intonation" , "just intonation" ] ,
57+ [ _ ( "Pythagorean (3-limit JI)" ) , "Pythagorean" , "Pythagorean" ] ,
58+ [ _ ( "Meantone" ) + " (1/3)" , "1/3 comma meantone" , "meantone (1/3)" ] ,
59+ [ _ ( "Meantone" ) + " (1/4)" , "1/4 comma meantone" , "meantone (1/4)" ] ,
60+ [ _ ( "Custom" ) , "custom" , "custom" ]
61+ ] ) ;
62+ } ) ;
63+
64+ describe ( "getTemperament" , ( ) => {
65+ it ( "should return the correct temperament for a valid key" , ( ) => {
66+ const equalTemperament = getTemperament ( "equal" ) ;
67+ expect ( equalTemperament ) . toHaveProperty ( "perfect 1" ) ;
68+ expect ( equalTemperament ) . toHaveProperty ( "minor 2" ) ;
69+ expect ( equalTemperament ) . toHaveProperty ( "pitchNumber" , 12 ) ;
70+ } ) ;
71+
72+ it ( 'should return the correct temperament for equal5 key' , ( ) => {
73+ const equal5Temperament = getTemperament ( "equal5" ) ;
74+ expect ( equal5Temperament ) . toHaveProperty ( "perfect 1" ) ;
75+ expect ( equal5Temperament ) . toHaveProperty ( "minor 2" ) ;
76+ expect ( equal5Temperament ) . toHaveProperty ( "pitchNumber" , 5 ) ;
77+ } ) ;
78+
79+ it ( "should return undefined for an invalid key" , ( ) => {
80+ const invalidTemperament = getTemperament ( "invalid" ) ;
81+ expect ( invalidTemperament ) . toBeUndefined ( ) ;
82+ } ) ;
83+ } ) ;
84+
85+ describe ( "getTemperamentKeys" , ( ) => {
86+ it ( "should return an array with the correct length" , ( ) => {
87+ const keys = getTemperamentKeys ( ) ;
88+ expect ( keys . length ) . toBe ( 10 ) ;
89+ } ) ;
90+
91+ it ( 'should return an array containing all keys' , ( ) => {
92+ const keys = getTemperamentKeys ( ) ;
93+ expect ( keys ) . toEqual (
94+ expect . arrayContaining ( [
95+ "equal" ,
96+ "equal5" ,
97+ "equal7" ,
98+ "equal19" ,
99+ "equal31" ,
100+ "just intonation" ,
101+ "Pythagorean" ,
102+ "1/3 comma meantone" ,
103+ "1/4 comma meantone" ,
104+ "custom"
105+ ] )
106+ ) ;
107+ } ) ;
108+ } ) ;
109+
110+ describe ( "Temperament Management" , ( ) => {
111+ beforeEach ( ( ) => {
112+ // Reset global variables before each test
113+ global . TEMPERAMENTS = [ ...INITIALTEMPERAMENTS ] ;
114+ global . TEMPERAMENT = {
115+ equal : {
116+ pitchNumber : 12 ,
117+ interval : [ "perfect 1" , "minor 2" , "major 2" ]
118+ }
119+ } ;
120+ } ) ;
121+
122+ test ( "addTemperamentToList should add a new temperament if not predefined" , ( ) => {
123+ const newEntry = "customTemperament" ;
124+ addTemperamentToList ( newEntry ) ;
125+ expect ( TEMPERAMENTS ) . toContain ( newEntry ) ;
126+ } ) ;
127+
128+ test ( "addTemperamentToList should not add a predefined temperament" , ( ) => {
129+ const predefinedEntry = "equal" ;
130+ addTemperamentToList ( predefinedEntry ) ;
131+ expect ( TEMPERAMENTS ) . not . toContain ( predefinedEntry ) ;
132+ } ) ;
133+
134+ test ( "deleteTemperamentFromList should remove a temperament from the dictionary" , ( ) => {
135+ const oldEntry = "equal" ;
136+ deleteTemperamentFromList ( oldEntry ) ;
137+ expect ( TEMPERAMENT [ oldEntry ] ) . toBeUndefined ( ) ;
138+ } ) ;
139+
140+ test ( "addTemperamentToDictionary should add a new temperament to the dictionary" , ( ) => {
141+ const entryName = "newTemperament" ;
142+ const entryValue = {
143+ pitchNumber : 7 ,
144+ interval : [ "perfect 1" , "minor 3" , "major 3" ]
145+ } ;
146+ addTemperamentToDictionary ( entryName , entryValue ) ;
147+ expect ( TEMPERAMENT [ entryName ] ) . toEqual ( entryValue ) ;
148+ } ) ;
149+
150+ test ( "updateTemperaments should update TEMPERAMENTS with new entries" , ( ) => {
151+ const newEntry = "customTemperament" ;
152+ TEMPERAMENT [ newEntry ] = {
153+ pitchNumber : 8 ,
154+ interval : [ "perfect 1" , "minor 3" ]
155+ } ;
156+ updateTemperaments ( ) ;
157+ expect ( TEMPERAMENTS . some ( ( [ _ , name ] ) => name === newEntry ) ) . toBe ( true ) ;
158+ } ) ;
159+
160+ test ( "updateTemperaments should not duplicate predefined temperaments" , ( ) => {
161+ updateTemperaments ( ) ;
162+ const predefinedEntries = TEMPERAMENTS . filter ( ( [ _ , name ] ) => name in PreDefinedTemperaments ) ;
163+ expect ( predefinedEntries . length ) . toBe ( Object . keys ( PreDefinedTemperaments ) . length ) ;
164+ } ) ;
165+ } ) ;
166+ } ) ;
167+
168+ describe ( "Constants" , ( ) => {
169+ test ( "should have correct default values" , ( ) => {
170+ expect ( DEFAULTINVERT ) . toBe ( "even" ) ;
171+ expect ( DEFAULTMODE ) . toBe ( "major" ) ;
172+ } ) ;
173+ } ) ;
174+
175+ describe ( "customMode" , ( ) => {
176+ test ( "should return custom mode from MUSICALMODES" , ( ) => {
177+ expect ( customMode ) . toEqual ( [ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ] ) ;
178+ } ) ;
179+ } ) ;
180+
181+ describe ( "getInvertMode" , ( ) => {
182+ test ( "should return the correct invert mode name" , ( ) => {
183+ expect ( getInvertMode ( "even" ) ) . toBe ( "even" ) ;
184+ expect ( getInvertMode ( "scalar" ) ) . toBe ( "scalar" ) ;
185+ expect ( getInvertMode ( "nonexistent" ) ) . toBe ( "nonexistent" ) ;
186+ } ) ;
187+ } ) ;
188+
189+ describe ( "getIntervalNumber" , ( ) => {
190+ test ( "should return the number of semi-tones for a given interval" , ( ) => {
191+ expect ( getIntervalNumber ( "perfect 5" ) ) . toBe ( 7 ) ;
192+ expect ( getIntervalNumber ( "major 3" ) ) . toBe ( 4 ) ;
193+ } ) ;
194+ } ) ;
195+
196+ describe ( "getIntervalDirection" , ( ) => {
197+ test ( "should return the direction of the interval" , ( ) => {
198+ expect ( getIntervalDirection ( "diminished 6" ) ) . toBe ( - 1 ) ;
199+ expect ( getIntervalDirection ( "minor 3" ) ) . toBe ( - 1 ) ;
200+ } ) ;
201+ } ) ;
202+
203+ describe ( "getIntervalRatio" , ( ) => {
204+ test ( "should return the ratio for a given interval" , ( ) => {
205+ expect ( getIntervalRatio ( "perfect 5" ) ) . toBe ( 1.5 ) ;
206+ expect ( getIntervalRatio ( "major 3" ) ) . toBe ( 1.25 ) ;
207+ } ) ;
208+ } ) ;
209+
210+ //
211+
212+ describe ( "getModeNumbers" , ( ) => {
213+ test ( "should return the correct mode numbers for a valid mode" , ( ) => {
214+ expect ( getModeNumbers ( "chromatic" ) ) . toBe ( "0 1 2 3 4 5 6 7 8 9 10 11" ) ;
215+ expect ( getModeNumbers ( "major" ) ) . toBe ( "0 2 4 5 7 9 11" ) ;
216+ expect ( getModeNumbers ( "minor" ) ) . toBe ( "0 2 3 5 7 8 10" ) ;
217+ } ) ;
218+
219+ test ( "should return an empty string for an invalid mode" , ( ) => {
220+ expect ( getModeNumbers ( "invalidMode" ) ) . toBe ( "" ) ;
221+ } ) ;
222+
223+ test ( "should handle custom mode correctly" , ( ) => {
224+ expect ( getModeNumbers ( "custom" ) ) . toBe ( "0 1 2 3 4 5 6 7 8 9 10 11" ) ;
225+ } ) ;
226+ } ) ;
227+
228+ //
229+
230+ jest . mock ( '../musicutils' , ( ) => {
231+ const actualModule = jest . requireActual ( '../musicutils' ) ;
232+ return {
233+ ...actualModule ,
234+ getDrumIndex : jest . fn ( ) ,
235+ getDrumName : jest . fn ( ) ,
236+ getDrumSymbol : jest . fn ( )
237+ } ;
238+ } ) ;
239+
240+ describe ( 'getDrum' , ( ) => {
241+ let DRUMNAMES , DEFAULTDRUM ;
242+
243+ beforeEach ( ( ) => {
244+ DRUMNAMES = [
245+ [ "snare drum" , "snare drum" , "images/snaredrum.svg" , "sn" , "drum" ] ,
246+ [ "kick drum" , "kick drum" , "images/kick.svg" , "hh" , "drum" ] ,
247+ [ "tom tom" , "tom tom" , "images/tom.svg" , "tomml" , "drum" ] ,
248+ [ "floor tom" , "floor tom" , "images/floortom.svg" , "tomfl" , "drum" ] ,
249+ [ "bass drum" , "bass drum" , "images/kick.svg" , "tomfl" , "drum" ] ,
250+ [ "hi hat" , "hi hat" , "images/hihat.svg" , "hh" , "bell" ]
251+ ] ;
252+ DEFAULTDRUM = "kick drum" ;
253+
254+ // Mock for getDrumIndex
255+ require ( '../musicutils' ) . getDrumIndex . mockImplementation ( ( name ) => {
256+ if ( name . slice ( 0 , 4 ) === "http" ) return null ;
257+ if ( name === "" ) return DRUMNAMES . findIndex ( drum => drum [ 0 ] === DEFAULTDRUM ) ;
258+
259+ const index = DRUMNAMES . findIndex (
260+ ( drum ) => drum [ 0 ] . toLowerCase ( ) === name . toLowerCase ( )
261+ ) ;
262+ return index >= 0 ? index : - 1 ;
263+ } ) ;
264+
265+ // Mock for getDrumName
266+ require ( '../musicutils' ) . getDrumName . mockImplementation ( ( name ) => {
267+ if ( name === "" ) name = DEFAULTDRUM ;
268+ if ( name . slice ( 0 , 4 ) === "http" ) return null ;
269+
270+ for ( let drum = 0 ; drum < DRUMNAMES . length ; drum ++ ) {
271+ if ( DRUMNAMES [ drum ] [ 0 ] . toLowerCase ( ) === name . toLowerCase ( ) ) {
272+ return DRUMNAMES [ drum ] [ 0 ] ;
273+ } else if ( DRUMNAMES [ drum ] [ 1 ] . toLowerCase ( ) === name . toLowerCase ( ) ) {
274+ return DRUMNAMES [ drum ] [ 1 ] ;
275+ }
276+ }
277+
278+ return null ;
279+ } ) ;
280+
281+ require ( '../musicutils' ) . getDrumSymbol . mockImplementation ( ( name ) => {
282+ if ( name === "" ) return "hh" ;
283+
284+ for ( let drum = 0 ; drum < DRUMNAMES . length ; drum ++ ) {
285+ if ( DRUMNAMES [ drum ] [ 0 ] . toLowerCase ( ) === name . toLowerCase ( ) ) {
286+ return DRUMNAMES [ drum ] [ 3 ] ;
287+ } else if ( DRUMNAMES [ drum ] [ 1 ] . toLowerCase ( ) === name . toLowerCase ( ) ) {
288+ return "hh" ;
289+ }
290+ }
291+
292+ return "hh" ;
293+ } ) ;
294+ } ) ;
295+
296+ describe ( 'getDrumIndex' , ( ) => {
297+ it ( 'should return the index of a valid drum name' , ( ) => {
298+ expect ( getDrumIndex ( 'snare drum' ) ) . toBe ( 0 ) ;
299+ expect ( getDrumIndex ( 'kick drum' ) ) . toBe ( 1 ) ;
300+ expect ( getDrumIndex ( 'floor tom' ) ) . toBe ( 3 ) ;
301+ } ) ;
302+
303+ it ( 'should return -1 for an invalid drum name' , ( ) => {
304+ expect ( getDrumIndex ( 'invalid drum' ) ) . toBe ( - 1 ) ;
305+ } ) ;
306+
307+ it ( 'should return the index of the DEFAULTDRUM for empty input' , ( ) => {
308+ expect ( getDrumIndex ( '' ) ) . toBe ( 1 ) ;
309+ } ) ;
310+
311+ it ( 'should ignore case sensitivity when matching drum names' , ( ) => {
312+ expect ( getDrumIndex ( 'SNARE DRUM' ) ) . toBe ( 0 ) ;
313+ } ) ;
314+
315+ it ( 'should return null for names starting with "http"' , ( ) => {
316+ expect ( getDrumIndex ( 'http' ) ) . toBe ( null ) ;
317+ } ) ;
318+ } ) ;
319+
320+ describe ( 'getDrumName' , ( ) => {
321+ it ( 'should return the name of a valid drum' , ( ) => {
322+ expect ( getDrumName ( 'snare drum' ) ) . toBe ( 'snare drum' ) ;
323+ expect ( getDrumName ( 'kick drum' ) ) . toBe ( 'kick drum' ) ;
324+ } ) ;
325+
326+ it ( 'should return the DEFAULTDRUM name for empty input' , ( ) => {
327+ expect ( getDrumName ( '' ) ) . toBe ( 'kick drum' ) ;
328+ } ) ;
329+
330+ it ( 'should return null for names starting with "http"' , ( ) => {
331+ expect ( getDrumName ( 'http' ) ) . toBe ( null ) ;
332+ } ) ;
333+
334+ it ( 'should ignore case sensitivity when matching drum names' , ( ) => {
335+ expect ( getDrumName ( 'SNARE DRUM' ) ) . toBe ( 'snare drum' ) ;
336+ expect ( getDrumName ( 'KICK DRUM' ) ) . toBe ( 'kick drum' ) ;
337+ } ) ;
338+
339+ it ( 'should return null for an invalid drum name' , ( ) => {
340+ expect ( getDrumName ( 'invalid drum' ) ) . toBe ( null ) ;
341+ } ) ;
342+
343+ it ( 'should match the second element of DRUMNAMES if provided' , ( ) => {
344+ expect ( getDrumName ( 'kick drum' ) ) . toBe ( 'kick drum' ) ;
345+ } ) ;
346+ } ) ;
347+
348+ describe ( 'getDrumSymbol' , ( ) => {
349+ it ( 'should return the correct symbol for a valid drum name' , ( ) => {
350+ expect ( getDrumSymbol ( 'snare drum' ) ) . toBe ( 'sn' ) ;
351+ expect ( getDrumSymbol ( 'kick drum' ) ) . toBe ( 'hh' ) ;
352+ expect ( getDrumSymbol ( 'floor tom' ) ) . toBe ( 'tomfl' ) ;
353+ } ) ;
354+
355+ it ( 'should return "hh" for an empty name' , ( ) => {
356+ expect ( getDrumSymbol ( '' ) ) . toBe ( 'hh' ) ;
357+ } ) ;
358+
359+ it ( 'should return "hh" for an invalid drum name' , ( ) => {
360+ expect ( getDrumSymbol ( 'invalid drum' ) ) . toBe ( 'hh' ) ;
361+ } ) ;
362+
363+ it ( 'should return "hh" for a name matching the second element of DRUMNAMES' , ( ) => {
364+ expect ( getDrumSymbol ( 'snare drum' ) ) . toBe ( 'sn' ) ;
365+ expect ( getDrumSymbol ( 'kick drum' ) ) . toBe ( 'hh' ) ; // As per logic
366+ } ) ;
367+
368+ it ( 'should ignore case sensitivity when matching drum names' , ( ) => {
369+ expect ( getDrumSymbol ( 'SNARE DRUM' ) ) . toBe ( 'sn' ) ;
370+ expect ( getDrumSymbol ( 'KICK DRUM' ) ) . toBe ( 'hh' ) ;
371+ } ) ;
372+ } ) ;
373+ } ) ;
374+
375+ describe ( 'getFilterTypes' , ( ) => {
376+ it ( 'should return default filter type' , ( ) => {
377+ expect ( getFilterTypes ( '' ) ) . toBe ( 'highpass' ) ; //DEFAULTFILTERTYPES
378+ } ) ;
379+ it ( 'should return correct filter types' , ( ) => {
380+ expect ( getFilterTypes ( 'highpass' ) ) . toBe ( 'highpass' ) ;
381+ expect ( getFilterTypes ( 'notch' ) ) . toBe ( 'notch' ) ;
382+ } ) ;
383+ } ) ;
0 commit comments