doremi-script
Version:
Letter music notation processor
691 lines (688 loc) • 27.1 kB
JavaScript
(function() {
var Logger, aux1, debug, first_line, first_sargam_line, my_inspect, parse_without_reporting_error, parser, root, should_not_parse, sys, test_parses, utils, _;
root = typeof exports !== "undefined" && exports !== null ? exports : this;
debug = false;
if (typeof global !== "undefined" && global !== null) {
global._console || (global._console = require('./underscore.logger.js'));
}
Logger = global._console.constructor;
_console.level = Logger.INFO;
if (typeof require !== "undefined" && require !== null) {
_ = require("underscore")._;
}
require('./doremi_script_parser.js');
sys = require('sys');
utils = require('./tree_iterators.js');
_.mixin(_console.toObject());
_.mixin({
each_slice: function(obj, slice_size, iterator, context) {
var collection = obj.map(function(item) { return item; });
if (typeof collection.slice !== 'undefined') {
for (var i = 0, s = Math.ceil(collection.length/slice_size); i < s; i++) {
iterator.call(context, _(collection).slice(i*slice_size, (i*slice_size)+slice_size), obj);
}
}
return;
}
});;
my_inspect = function(x) {
var arg, _i, _len, _results;
if (!(debug != null)) {
return;
}
console.log("debug is " + debug);
if (!debug) {
return;
}
if (!(typeof JSON !== "undefined" && JSON !== null)) {
return;
}
_results = [];
for (_i = 0, _len = arguments.length; _i < _len; _i++) {
arg = arguments[_i];
_results.push(console.log(JSON.stringify(arg, null, " ")));
}
return _results;
};
_.mixin({
my_inspect: my_inspect
});
parser = DoremiScriptParser;
aux1 = function(str, result) {
if (!sys) {
return;
}
_.debug("Result of parsing <<" + str + ">> is");
return _.debug(sys.inspect(result, true, null));
};
should_not_parse = function(str, test, msg) {
_.debug(str);
_.debug("Testing that <<" + str + ">> does NOT parse");
return test.throws((function() {
return parser.parse(str);
}), "<<\n" + str + "\n>> should not parse!. " + msg);
};
parse_without_reporting_error = function(str) {
_.debug("Entering parse_without_reporting_error");
_.debug("Parsing <<\n" + str + ">>");
try {
return parser.parse(str);
} catch (error) {
return _.debug("Didn't parse");
}
};
first_sargam_line = function(composition_data) {
return composition_data.lines[0];
};
first_line = function(composition_data) {
return composition_data.lines[0];
};
test_parses = function(str, test, msg) {
var composition;
if (msg == null) {
msg = "";
}
_.debug("Entering test_parses, str is " + str);
composition = parser.parse(str);
_.debug("in test_parses,composition is " + composition);
return composition;
/*
test.doesNotThrow(-> result=parser.parse(str))
test.ok(result?,"didn't parse")
_.debug(sys.inspect(result,false,null))
*/
};
exports.test_bad_input = function(test) {
var str;
str = ':';
should_not_parse(str, test);
return test.done();
};
exports.test_does_not_accept_single_barline = function(test) {
var str;
str = '|';
should_not_parse(str, test);
return test.done();
};
exports.test_accepts_various_eols = function(test) {
var str, _i, _len, _ref;
_ref = ["| SS\n\n| RR", "| SS\r\r | SS", "| SS\r\n\n| RR", "| SS\n\r| SS"];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
str = _ref[_i];
test_parses(str, test);
}
return test.done();
};
exports.test_does_not_accepts_single_left_repeat = function(test) {
var str;
str = '|:';
should_not_parse(str, test);
return test.done();
};
exports.test_accepts_five_octaves_of_chromatic_notes = function(test) {
var str;
str = ' . .... .... .... : \n1) SrRg GmMP dDnN S | SrRg GmMP dDnN S | SrRg GmMP dDnN S| SrRg GmMP dDnN S |\n :::: :::: :::: . .... .... ....\n\n . .... .... .... : :::: :::: ::::\n2) | SrRg GmMP dDnN S| SrRg GmMP dDnN S | SrRg GmMP dDnN ---- |';
test_parses(str, test);
return test.done();
};
exports.test_accepts_right_repeat = function(test) {
var str;
str = '|: :|';
test_parses(str, test);
return test.done();
};
exports.test_accepts_chords = function(test) {
var str;
str = ' V i IVm\n|SR\n';
test_parses(str, test);
return test.done();
};
exports.test_eof_ends_beat = function(test) {
var composition, line, measure, second_item, str;
str = '|SR';
composition = test_parses(str, test);
_.debug(composition);
line = first_sargam_line(composition);
measure = line.items[0];
second_item = measure.items[1];
_.debug(second_item);
test.equal(second_item.my_type, "beat", "second item of " + str + " should be a beat containing SR");
test.equal(second_item.subdivisions, 2);
return test.done();
};
exports.test_barline_ends_beat = function(test) {
var composition, line, measure, second_item, str;
str = '|SR|S';
composition = test_parses(str, test);
line = first_sargam_line(composition);
measure = line.items[0];
second_item = measure.items[1];
_.debug(second_item);
test.equal(second_item.my_type, "beat", "second item of " + str + " should be a beat containing SR");
test.equal(second_item.subdivisions, 2);
return test.done();
};
exports.test_dashes_inside_beat = function(test) {
var composition, line, measure, second_item, str, x;
str = '|S--R|';
composition = test_parses(str, test);
line = first_sargam_line(composition);
measure = line.items[0];
second_item = measure.items[1];
_.debug(second_item);
test.equal(second_item.my_type, "beat", "second item of " + str + " should be a beat containing S--R");
test.equal(second_item.subdivisions, x = 4, "subdivisions of beat " + str + " should be " + x);
return test.done();
};
exports.test_lines = function(test) {
var composition, second_item, str, third_item;
str = '| S- |\n\n';
composition = test_parses(str, test);
_.debug(composition);
test.done();
return;
second_item = composition.lines[0].items[1];
_.debug(second_item);
test.equal(second_item.my_type, "beat", "second item of " + str + " should be a beat");
test.equal(second_item.items.length, 2, "the beat's length should be 2");
test.equal(second_item.items[0].my_type, "dash", "dash should be first item");
third_item = composition.lines[0].items[2];
_.debug(third_item);
test.equal(third_item.my_type, "barline", "third item of " + str + " should be a barline");
return test.done();
};
exports.test_dash_starts_beat = function(test) {
var composition, line, measure, second_item, str;
str = '|-R|';
composition = test_parses(str, test);
line = first_sargam_line(composition);
measure = line.items[0];
second_item = measure.items[1];
_.debug(second_item);
test.equal(second_item.my_type, "beat", "second item of " + str + " should be a beat");
test.equal(second_item.items.length, 2, "the beat's length should be 2");
test.equal(second_item.items[0].my_type, "dash", "dash should be first item");
return test.done();
};
exports.test_recognizes_upper_octave_line = function(test) {
var composition, str;
str = ' .:~*\n|SRGR';
composition = test_parses(str, test);
return test.done();
};
exports.test_recognizes_lower_octave_line = function(test) {
var composition, str;
str = '|SRG R\n .: *';
composition = test_parses(str, test);
return test.done();
};
exports.test_recognizes_slurs = function(test) {
var composition, str;
str = '| (S R)\n .\n';
composition = test_parses(str, test);
return test.done();
};
exports.test_accepts_delimited_beat = function(test) {
var composition, str;
str = '| <SR>\n';
composition = test_parses(str, test);
_.debug(composition);
return test.done();
};
exports.test_accepts_spaces_in_delimited_beat = function(test) {
var composition, str;
str = '| <S R>\n';
composition = test_parses(str, test);
_.debug(composition);
return test.done();
};
exports.test_accepts_delimited_beat = function(test) {
var composition, str;
str = '| <SR>\n';
composition = test_parses(str, test);
_.debug(composition);
return test.done();
};
exports.test_recognizes_ornament_symbol = function(test) {
var composition, str;
str = ' ~\n| S R';
composition = test_parses(str, test);
return test.done();
};
exports.test_attributes = function(test) {
var composition, str;
str = 'Rag:Bhairavi\n\n| SRG';
composition = test_parses(str, test);
return test.done();
};
exports.test_line_can_come_right_after_header_line = function(test) {
var composition, str;
str = 'Rag:Kafi\n | S';
composition = test_parses(str, test);
return test.done();
};
exports.test_leading_spaces_in_upper_octave_line = function(test) {
var composition, str;
str = 'Rag:Kafi\n\n .\n| SRGmPDNS';
composition = test_parses(str, test);
return test.done();
};
exports.test_leading_spaces_in_sargam_line = function(test) {
var composition, str;
str = 'Rag:Kafi\n\n| Sr';
composition = test_parses(str, test);
return test.done();
};
exports.test_gives_warning_if_misplaced_upper_octave_indicator = function(test) {
var composition, str, z;
str = 'Rag:Kafi\n .\n| r';
composition = test_parses(str, test);
test.ok(composition.warnings.length > 0, "expected warnings");
test.ok(composition.warnings[0].indexOf(z = "upper_octave_indicator") > -1, "Expected warning to include " + z + ". Warning was " + composition.warnings[0]);
return test.done();
};
exports.test_gives_warning_if_unmatched_parens_for_slurs = function(test) {
var composition, str, z;
str = '| (Pm';
composition = test_parses(str, test);
test.ok(composition.warnings.length > 0, "expected warnings");
test.ok(composition.warnings[0].indexOf(z = "unbalanced parens") > -1, "Expected warning to include " + z + ". Warning was " + composition.warnings[0]);
return test.done();
};
exports.test_syllable_assigned_using_melismas = function(test) {
var composition, line, my_pitch, str;
str = '| (SR G)m P\nhe-llo john \n';
composition = test_parses(str, test);
line = first_sargam_line(composition);
my_pitch = utils.tree_find(line, function(item) {
return item.syllable === "llo";
});
test.equal("m", my_pitch.source);
my_pitch = utils.tree_find(line, function(item) {
return item.source === "R";
});
test.ok(!(my_pitch.syllable != null), "R is part of a slur SRG an should not be assigned a syllable");
return test.done();
};
exports.test_upper_octave_assigned_to_note_below_it = function(test) {
var composition, ga, ma, re, sa, str;
str = ' .*::\n| Srgm';
composition = test_parses(str, test);
sa = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "S";
});
re = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "r";
});
ga = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "g";
});
ma = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "m";
});
test.equal(sa.octave, 1, "" + str + " should have octave 1 for S");
test.equal(re.octave, 1, "" + str + " should have octave 1 for r");
test.equal(ga.octave, 2, "" + str + " should have octave 1 for g");
test.equal(ma.octave, 2, "" + str + " should have octave 1 for m");
return test.done();
};
exports.test_recognizes_ornament_to_right_of_pitch2 = function(test) {
var composition, item, orn, str;
str = ' DSnDn\nn---';
composition = test_parses(str, test);
item = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "n";
});
orn = _.detect(item.attributes, function(attr) {
return attr.my_type === "ornament";
});
_.debug("orn " + orn.my_inspect);
test.ok(orn);
test.ok(orn.source === "DSnDn");
return test.done();
};
exports.test_recognizes_ornament_to_right_of_pitch = function(test) {
var composition, item, orn, str;
str = ' NRSNS \n| S';
composition = test_parses(str, test);
item = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "S";
});
orn = _.detect(item.attributes, function(attr) {
return attr.my_type === "ornament";
});
_.debug("orn " + orn.my_inspect);
test.ok(orn);
test.ok(orn.source === "NRSNS");
return test.done();
};
exports.test_lower_octave_assigned_to_note_above_it = function(test) {
var composition, ga, ma, re, sa, str;
str = '|Srgm\n .*::';
composition = test_parses(str, test);
sa = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "S";
});
re = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "r";
});
ga = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "g";
});
ma = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "m";
});
test.equal(sa.octave, -1, "" + str + " should have octave -1 for S");
test.equal(re.octave, -1, "" + str + " should have octave -1 for r");
test.equal(ga.octave, -2, "" + str + " should have octave -2 for g");
test.equal(ma.octave, -2, "" + str + " should have octave -2 for m");
return test.done();
};
exports.test_all = function(test) {
var composition, first_sargam_source, line, str, strzz, x;
x = 'dog';
_.debug("x=" + x);
str = 'Rag:Bhairavi\nTal:Tintal\nTitle:Bansuri\nSource:AAK\n\n 3 + 2 .\n1) |: (Sr | n) S (gm Pd) || P - P P | P - D <(nDSn)> |\n .\n ban- su- ri ba- ja ra- hi dhu- na\n\n0 3 + . * .\n| P d P d | <(Pm> PmnP) (g m) || PdnS -- g S |\n ma-dhu-ra kan- nai- ya khe- la-ta\n\n2 0 ~\n| d-Pm g P m | r - S :| %\n ga- wa-ta ho- ri\n\n + 2 0 3\n2) [| Srgm PdnS SndP mgrS | % | % | S--S --S- ---- R-G- |]\n';
strzz = 'Rag:Bhairavi\nTal:Tintal\nTitle:Bansuri\nSource:AAK\n\n 3 + 2 .\n1) |: (Sr | n) S (gm Pd) || P - P P | P - D <(nDSn)> |\n .\n ban- su- ri ba- ja ra- hi dhu- na\n0 3 + . * .\n| P d P d | <(Pm> PmnP) (g m) || PdnS -- g S |\n ma-dhu-ra kan- nai- ya khe- la-ta\n\n2 0 ~\n| d-Pm g P m | r - S :| %\n ga- wa-ta ho- ri\n\n + 2 0 3\n2) [| Srgm PdnS SndP mgrS | % | % | S--S --S- ---- R-G- |]';
composition = test_parses(str, test);
first_sargam_source = str.split('\n')[6];
line = first_sargam_line(composition);
test.equal(line.source, first_sargam_source, "sanity check, expected first line's source to be " + first_sargam_source);
return test.done();
};
exports.test_parses_measure_at_beginning_of_line = function(test) {
var composition, measure, str;
str = 'Sr\nban-';
str = '|Sr\n ban-';
composition = test_parses(str, test);
measure = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "measure";
});
test.equal(measure.items[1].my_type, "beat", "<<" + str + ">> should be parsed as a measure with beat " + str);
return test.done();
};
exports.test_parses_lyrics_line_without_leading_and_trailing_spaces = function(test) {
var composition, str;
str = '|Srgm| S\n he-llo john';
composition = test_parses(str, test);
return test.done();
/*
test.equal(lyrics.items[0].source,"he-","he- source should be he-")
test.equal(lyrics.items[0].syllable,"he-","he- should be parsed as a syllable")
test.equal(lyrics.items[1].syllable,"llo","llo should be parsed as a syllable")
test.equal(lyrics.items[1].source,"llo","source for syllable should NOT include trailing white space!")
test.equal(lyrics.items[3].source,"john","source for john should john")
test.equal(lyrics.items[3].syllable,"john","john should be parsed as a syllable")
aux1(str,composition)
test.done()
*/
};
exports.test_collects_sargam_line_source = function(test) {
var composition, expect, str;
str = '|Sr g m |';
composition = test_parses(str, test);
expect = "|Sr g m |";
test.equal(first_sargam_line(composition).source, "|Sr g m |", "should collect source, expected " + expect + " . Note that eol is not included");
return test.done();
};
exports.test_parses_lyrics_line_with_leading_and_trailing_spaces = function(test) {
var composition, first, str;
str = '|Sr g m |\n he- llo john ';
/*
Note that whitespace is included.
lyric items are parsed something like:
items:
[ { my_type: 'whitespace', source: ' ' },
{ my_type: 'syllable', syllable: 'he-', source: 'he-' },
{ my_type: 'whitespace', source: ' ' },
{ my_type: 'syllable', syllable: 'llo', source: 'llo' },
{ my_type: 'whitespace', source: ' ' },
{ my_type: 'syllable',
syllable: 'john',
source: 'john' },
{ my_type: 'whitespace', source: ' ' } ]
*/
composition = test_parses(str, test);
test.ok(composition.lines != null, "parsed composition should have a lines attribute");
test.equal(composition.lines.length, 1, "<<\n" + str + "\n>> should have 1 line");
first = first_line(composition);
return test.done();
};
exports.test_column_assignment = function(test) {
var composition, my_pitch, str;
str = '|Sr';
composition = test_parses(str, test);
my_pitch = utils.tree_find(composition.lines[0], function(item) {
return item.source === "S";
});
test.equal(1, my_pitch.column);
return test.done();
};
exports.test_parses_lines = function(test) {
var composition, str;
str = '|S\n\n|R';
composition = test_parses(str, test);
_.debug("test_parses_lines, after test_parses");
_.debug(composition.toString());
_.debug("z");
test.ok(composition.lines != null, "parsed composition should have a lines attribute");
test.equal(composition.lines.length, 2, "Should have 2 lines");
aux1(str, composition);
return test.done();
};
exports.test_position_counting = function(test) {
var composition, str;
str = '|Sr';
composition = test_parses(str, test);
aux1(str, composition);
return test.done();
};
/*
[ { my_type: 'sargam_line',
items:
[ { my_type: 'pitch', source: 'S', octave: 0 },
{ my_type: 'pitch', source: 'r', octave: 0 } ],
aux1: 'hi' } ]
*/
exports.test_accepts_attributes = function(test) {
var str;
str = "hi:john\n";
test_parses(str, test);
return test.done();
};
exports.test_accepts_attributes2 = function(test) {
var str;
str = "hi:john\nhi:jane\n";
test_parses(str, test);
return test.done();
};
exports.test_accepts_attributes3 = function(test) {
var str;
str = "hi:john\nhi:jane\n\n\n\n \n";
test_parses(str, test);
return test.done();
};
exports.test_accepts_double_barline = function(test) {
var str;
str = '|| S';
test_parses(str, test, "should parse as a single measure with a single S");
return test.done();
};
exports.test_accepts_mordent = function(test) {
var str;
str = ' ~\n| S';
test_parses(str, test);
return test.done();
};
exports.test_parses_one_as_tala = function(test) {
var composition, line, str, x;
str = ' 1\n| S';
composition = test_parses(str, test);
line = first_sargam_line(composition);
x = sys.inspect(line, true, null);
test.ok(x.indexOf('tala') > -1, "" + x + " -1st line should have tala object");
return test.done();
};
exports.test_ending_one_dot = function(test) {
var composition, line, str, x;
str = ' 1.\n| S';
composition = test_parses(str, test);
line = first_sargam_line(composition);
x = sys.inspect(line, true, null);
test.ok(x.indexOf('ending') > -1, "" + x + " -line should have ending object");
return test.done();
};
exports.test_chord_iv = function(test) {
var composition, line, str, x;
str = ' iv\n| S';
composition = test_parses(str, test);
line = first_sargam_line(composition);
x = sys.inspect(line, true, null);
test.ok(x.indexOf('chord_symbol') > -1, "" + x + " -line should have chord object");
return test.done();
};
exports.test_ending_one_dot_underscores = function(test) {
var composition, line, str, x;
str = ' 1.__\n| S';
composition = test_parses(str, test);
line = first_sargam_line(composition);
x = sys.inspect(line, true, null);
test.ok(x.indexOf('ending') > -1, "" + x + " -line should have ending object");
return test.done();
};
exports.test_ending_two_underscores = function(test) {
var composition, line, str, x;
str = ' 2______\n| S';
composition = test_parses(str, test);
line = first_sargam_line(composition);
x = sys.inspect(line, true, null);
test.ok(x.indexOf('ending') > -1, "" + x + " -line should have ending object");
return test.done();
};
exports.test_tivra_ma_devanagri = function(test) {
var composition, line, str, x;
str = '|म\'\n tivrama';
composition = test_parses(str, test);
line = first_sargam_line(composition);
x = sys.inspect(line, true, null);
test.ok(x.indexOf("source: 'म\\'") > -1, "" + x + " -line should have tivra ma");
return test.done();
};
exports.test_devanagri_and_latin_sargam_together_should_fail = function(test) {
var composition, str;
str = ' .\n| सरग़मपधऩस SrRgGmMPdDnN\n SRGmPDNS';
composition = should_not_parse(str, test);
return test.done();
};
exports.test_devanagri = function(test) {
var composition, line, str, x, z;
str = ' .\nसरग़मपधऩस\nSRGmPDNS';
composition = test_parses(str, test);
line = first_sargam_line(composition);
x = sys.inspect(line, true, null);
test.ok(x.indexOf('स') > -1, "" + x + " -line should have स");
test.ok(x.indexOf('denominator: 8') > -1, "" + x + " -line should have 8 pitches");
test.equal(line.kind, z = "devanagri", "line.kind should be " + z);
return test.done();
};
exports.test_kommal_indicator = function(test) {
var composition, line, str, x;
str = 'र\n_';
composition = test_parses(str, test);
line = first_sargam_line(composition);
x = sys.inspect(line, true, null);
test.ok(x.indexOf('kommal_indicator') > -1, "" + x + " -line should have kommal indicator");
return test.done();
};
exports.test_abc = function(test) {
var composition, line, str, x;
str = 'C#D#F#G#A#B#DbEbGbAbBbCC#DbDD#EbEFF#GbGAbAA#BbBB# ';
composition = test_parses(str, test);
line = first_sargam_line(composition);
x = sys.inspect(line, true, null);
return test.done();
};
exports.test_title = function(test) {
var composition, str;
str = 'Title: The entertainer \n \n| S';
composition = test_parses(str, test);
test.equal(composition.title, "The entertainer");
return test.done();
};
exports.test_filename = function(test) {
var composition, str;
str = 'Filename: the_entertainer \n\n| S';
composition = test_parses(str, test);
test.equal(composition.filename, "the_entertainer");
return test.done();
};
exports.test_empty_lines_with_blanks = function(test) {
var composition, str;
str = ' --S- ---- --r-\n \n\n | S';
composition = test_parses(str, test);
return test.done();
};
exports.test_simple_line = function(test) {
var composition, str;
str = "| S\n\n|R\n\n|G\n\n|m";
composition = test_parses(str, test);
return test.done();
};
exports.test_recognizes_number_notation = function(test) {
var composition, str;
str = '| 1234567 1#2#3#4#5#6#7#- 1b2b3b4b5b6b7b- \n hello';
composition = test_parses(str, test);
test.equal(composition.lines[0].kind, "number", "should set composition kind to number");
return test.done();
};
exports.test_recognizes_sa = function(test) {
var composition, str, z;
str = 'S';
composition = test_parses(str, test);
test.equal(composition.lines[0].kind, z = "latin_sargam", "should set composition kind to " + z);
return test.done();
};
exports.test_slurred = function(test) {
var composition, item, str;
str = "(SR)";
str = " SR";
composition = test_parses(str, test);
item = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "S";
});
test.equal(1, item.column);
item = utils.tree_find(composition.lines[0], function(item) {
return item.my_type === "pitch" && item.source === "R";
});
test.equal(2, item.column);
return test.done();
};
exports.test_two_blank_lines_case = function(test) {
var composition, str;
str = "S\n\n\nR";
composition = test_parses(str, test);
return test.done();
};
exports.test_measure_pitch_durations = function(test) {
var composition, line, my_pitch, str;
str = '--S- ---- --r-';
composition = test_parses(str, test);
line = first_sargam_line(composition);
my_pitch = utils.tree_find(line, function(item) {
return item.source === "S";
});
return test.done();
};
exports.test_zzz = function(test) {
var str;
str = ' ..\nCDbDEb EFF#G AbABbB CD\n\n ..\nSrGmMP dDnN SR \n\n \nसररग़ग़ मम\'पधधऩऩ\n_ _ _ __\n';
return test.done();
};
exports.test_ornament_item = function(test) {
var composition, str;
str = " S\n|(Sr n)";
composition = test_parses(str, test, "");
test.ok((composition.toString()).indexOf("ornament_item") > -1);
return test.done();
};
}).call(this);