def test_composites(self): # {{{ ' Test sorting and searching in composite columns ' from calibre.utils.date import parse_only_date as p cache = self.init_cache() cache.create_custom_column('mult', 'CC1', 'composite', True, display={'composite_template': 'b,a,c'}) cache.create_custom_column('single', 'CC2', 'composite', False, display={'composite_template': 'b,a,c'}) cache.create_custom_column('number', 'CC3', 'composite', False, display={'composite_template': '{#float}', 'composite_sort':'number'}) cache.create_custom_column('size', 'CC4', 'composite', False, display={'composite_template': '{#float:human_readable()}', 'composite_sort':'number'}) cache.create_custom_column('ccdate', 'CC5', 'composite', False, display={'composite_template': '{pubdate:format_date(d-M-yy)}', 'composite_sort':'date'}) cache.create_custom_column('bool', 'CC6', 'composite', False, display={'composite_template': '{#yesno}', 'composite_sort':'bool'}) cache.create_custom_column('ccm', 'CC7', 'composite', True, display={'composite_template': '{#tags}'}) cache.create_custom_column('ccp', 'CC8', 'composite', True, display={'composite_template': '{publisher}'}) cache.create_custom_column('ccf', 'CC9', 'composite', True, display={'composite_template': "{:'approximate_formats()'}"}) cache = self.init_cache() # Test searching self.assertEqual({1,2,3}, cache.search('#mult:=a')) self.assertEqual(set(), cache.search('#mult:=b,a,c')) self.assertEqual({1,2,3}, cache.search('#single:=b,a,c')) self.assertEqual(set(), cache.search('#single:=b')) # Test numeric sorting cache.set_field('#float', {1:2, 2:10, 3:0.0001}) self.assertEqual([3, 1, 2], cache.multisort([('#number', True)])) cache.set_field('#float', {1:3, 2:2*1024, 3:1*1024*1024}) self.assertEqual([1, 2, 3], cache.multisort([('#size', True)])) # Test date sorting cache.set_field('pubdate', {1:p('2001-2-6'), 2:p('2001-10-6'), 3:p('2001-6-6')}) self.assertEqual([1, 3, 2], cache.multisort([('#ccdate', True)])) # Test bool sorting self.assertEqual([2, 1, 3], cache.multisort([('#bool', True)])) # Test is_multiple sorting cache.set_field('#tags', {1:'b, a, c', 2:'a, b, c', 3:'a, c, b'}) self.assertEqual([1, 2, 3], cache.multisort([('#ccm', True)])) # Test that lock downgrading during update of search cache works self.assertEqual(cache.search('#ccp:One'), {2}) cache.set_field('publisher', {2:'One', 1:'One'}) self.assertEqual(cache.search('#ccp:One'), {1, 2}) self.assertEqual(cache.search('#ccf:FMT1'), {1, 2}) cache.remove_formats({1:('FMT1',)}) self.assertEqual('FMT2', cache.field_for('#ccf', 1))
def test_sorting(self): # {{{ 'Test sorting' cache = self.init_cache() ae = self.assertEqual for field, order in { 'title': [2, 1, 3], 'authors': [2, 1, 3], 'series': [3, 1, 2], 'tags': [3, 1, 2], 'rating': [3, 2, 1], # 'identifiers': [3, 2, 1], There is no stable sort since 1 and # 2 have the same identifier keys # 'last_modified': [3, 2, 1], There is no stable sort as two # records have the exact same value 'timestamp': [2, 1, 3], 'pubdate': [1, 2, 3], 'publisher': [3, 2, 1], 'languages': [3, 2, 1], 'comments': [3, 2, 1], '#enum': [3, 2, 1], '#authors': [3, 2, 1], '#date': [3, 1, 2], '#rating': [3, 2, 1], '#series': [3, 2, 1], '#tags': [3, 2, 1], '#yesno': [2, 1, 3], '#comments': [3, 2, 1], 'id': [1, 2, 3], }.iteritems(): x = list(reversed(order)) ae(order, cache.multisort([(field, True)], ids_to_sort=x), 'Ascending sort of %s failed' % field) ae(x, cache.multisort([(field, False)], ids_to_sort=order), 'Descending sort of %s failed' % field) # Test sorting of is_multiple fields. # Author like fields should be sorted by generating sort names from the # actual values in entry order for field in ('authors', '#authors'): ae( cache.set_field( field, { 1: ('aa bb', 'bb cc', 'cc dd'), 2: ('bb aa', 'xx yy'), 3: ('aa bb', 'bb aa') }), {1, 2, 3}) ae([2, 3, 1], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) ae([1, 3, 2], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # All other is_multiple fields should be sorted by sorting the values # for each book and using that as the sort key for field in ('tags', '#tags'): ae( cache.set_field(field, { 1: ('b', 'a'), 2: ('c', 'y'), 3: ('b', 'z') }), {1, 2, 3}) ae([1, 3, 2], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) ae([2, 3, 1], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # Test tweak to sort dates by visible format from calibre.utils.date import parse_only_date as p from calibre.utils.config_base import Tweak ae( cache.set_field('pubdate', { 1: p('2001-3-3'), 2: p('2002-2-3'), 3: p('2003-1-3') }), {1, 2, 3}) ae([1, 2, 3], cache.multisort([('pubdate', True)])) with Tweak('gui_pubdate_display_format', 'MMM'), Tweak('sort_dates_using_visible_fields', True): c2 = self.init_cache() ae([3, 2, 1], c2.multisort([('pubdate', True)])) # Test bool sorting when not tristate cache.set_pref('bools_are_tristate', False) c2 = self.init_cache() ae([2, 3, 1], c2.multisort([('#yesno', True), ('id', False)])) # Test subsorting ae([3, 2, 1], cache.multisort([('identifiers', True), ('title', True)]), 'Subsort failed') from calibre.ebooks.metadata.book.base import Metadata for i in xrange(7): cache.create_book_entry(Metadata('title%d' % i), apply_import_tags=False) cache.create_custom_column('one', 'CC1', 'int', False) cache.create_custom_column('two', 'CC2', 'int', False) cache.create_custom_column('three', 'CC3', 'int', False) cache.close() cache = self.init_cache() cache.set_field('#one', {(i + (5 * m)): m for m in (0, 1) for i in xrange(1, 6)}) cache.set_field('#two', {i + (m * 3): m for m in (0, 1, 2) for i in (1, 2, 3)}) cache.set_field('#two', {10: 2}) cache.set_field('#three', {i: i for i in xrange(1, 11)}) ae( list(xrange(1, 11)), cache.multisort([('#one', True), ('#two', True)], ids_to_sort=sorted(cache.all_book_ids()))) ae([4, 5, 1, 2, 3, 7, 8, 9, 10, 6], cache.multisort([('#one', True), ('#two', False)], ids_to_sort=sorted(cache.all_book_ids()))) ae([5, 4, 3, 2, 1, 10, 9, 8, 7, 6], cache.multisort([('#one', True), ('#two', False), ('#three', False)], ids_to_sort=sorted(cache.all_book_ids())))
def test_composites(self): # {{{ " Test sorting and searching in composite columns " from calibre.utils.date import parse_only_date as p cache = self.init_cache() cache.create_custom_column("mult", "CC1", "composite", True, display={"composite_template": "b,a,c"}) cache.create_custom_column("single", "CC2", "composite", False, display={"composite_template": "b,a,c"}) cache.create_custom_column( "number", "CC3", "composite", False, display={"composite_template": "{#float}", "composite_sort": "number"} ) cache.create_custom_column( "size", "CC4", "composite", False, display={"composite_template": "{#float:human_readable()}", "composite_sort": "number"}, ) cache.create_custom_column( "ccdate", "CC5", "composite", False, display={"composite_template": "{pubdate:format_date(d-M-yy)}", "composite_sort": "date"}, ) cache.create_custom_column( "bool", "CC6", "composite", False, display={"composite_template": "{#yesno}", "composite_sort": "bool"} ) cache.create_custom_column("ccm", "CC7", "composite", True, display={"composite_template": "{#tags}"}) cache.create_custom_column("ccp", "CC8", "composite", True, display={"composite_template": "{publisher}"}) cache.create_custom_column( "ccf", "CC9", "composite", True, display={"composite_template": "{:'approximate_formats()'}"} ) cache = self.init_cache() # Test searching self.assertEqual({1, 2, 3}, cache.search("#mult:=a")) self.assertEqual(set(), cache.search("#mult:=b,a,c")) self.assertEqual({1, 2, 3}, cache.search("#single:=b,a,c")) self.assertEqual(set(), cache.search("#single:=b")) # Test numeric sorting cache.set_field("#float", {1: 2, 2: 10, 3: 0.0001}) self.assertEqual([3, 1, 2], cache.multisort([("#number", True)])) cache.set_field("#float", {1: 3, 2: 2 * 1024, 3: 1 * 1024 * 1024}) self.assertEqual([1, 2, 3], cache.multisort([("#size", True)])) # Test date sorting cache.set_field("pubdate", {1: p("2001-2-6"), 2: p("2001-10-6"), 3: p("2001-6-6")}) self.assertEqual([1, 3, 2], cache.multisort([("#ccdate", True)])) # Test bool sorting self.assertEqual([2, 1, 3], cache.multisort([("#bool", True)])) # Test is_multiple sorting cache.set_field("#tags", {1: "b, a, c", 2: "a, b, c", 3: "a, c, b"}) self.assertEqual([1, 2, 3], cache.multisort([("#ccm", True)])) # Test that lock downgrading during update of search cache works self.assertEqual(cache.search("#ccp:One"), {2}) cache.set_field("publisher", {2: "One", 1: "One"}) self.assertEqual(cache.search("#ccp:One"), {1, 2}) self.assertEqual(cache.search("#ccf:FMT1"), {1, 2}) cache.remove_formats({1: ("FMT1",)}) self.assertEqual("FMT2", cache.field_for("#ccf", 1))
def test_sorting(self): # {{{ "Test sorting" cache = self.init_cache() ae = self.assertEqual for field, order in { "title": [2, 1, 3], "authors": [2, 1, 3], "series": [3, 1, 2], "tags": [3, 1, 2], "rating": [3, 2, 1], # 'identifiers': [3, 2, 1], There is no stable sort since 1 and # 2 have the same identifier keys # 'last_modified': [3, 2, 1], There is no stable sort as two # records have the exact same value "timestamp": [2, 1, 3], "pubdate": [1, 2, 3], "publisher": [3, 2, 1], "languages": [3, 2, 1], "comments": [3, 2, 1], "#enum": [3, 2, 1], "#authors": [3, 2, 1], "#date": [3, 1, 2], "#rating": [3, 2, 1], "#series": [3, 2, 1], "#tags": [3, 2, 1], "#yesno": [2, 1, 3], "#comments": [3, 2, 1], "id": [1, 2, 3], }.iteritems(): x = list(reversed(order)) ae(order, cache.multisort([(field, True)], ids_to_sort=x), "Ascending sort of %s failed" % field) ae(x, cache.multisort([(field, False)], ids_to_sort=order), "Descending sort of %s failed" % field) # Test sorting of is_multiple fields. # Author like fields should be sorted by generating sort names from the # actual values in entry order for field in ("authors", "#authors"): ae( cache.set_field(field, {1: ("aa bb", "bb cc", "cc dd"), 2: ("bb aa", "xx yy"), 3: ("aa bb", "bb aa")}), {1, 2, 3}, ) ae([2, 3, 1], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) ae([1, 3, 2], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # All other is_multiple fields should be sorted by sorting the values # for each book and using that as the sort key for field in ("tags", "#tags"): ae(cache.set_field(field, {1: ("b", "a"), 2: ("c", "y"), 3: ("b", "z")}), {1, 2, 3}) ae([1, 3, 2], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) ae([2, 3, 1], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # Test tweak to sort dates by visible format from calibre.utils.date import parse_only_date as p from calibre.utils.config_base import Tweak ae(cache.set_field("pubdate", {1: p("2001-3-3"), 2: p("2002-2-3"), 3: p("2003-1-3")}), {1, 2, 3}) ae([1, 2, 3], cache.multisort([("pubdate", True)])) with Tweak("gui_pubdate_display_format", "MMM"), Tweak("sort_dates_using_visible_fields", True): c2 = self.init_cache() ae([3, 2, 1], c2.multisort([("pubdate", True)])) # Test bool sorting when not tristate cache.set_pref("bools_are_tristate", False) c2 = self.init_cache() ae([2, 3, 1], c2.multisort([("#yesno", True), ("id", False)])) # Test subsorting ae([3, 2, 1], cache.multisort([("identifiers", True), ("title", True)]), "Subsort failed") from calibre.ebooks.metadata.book.base import Metadata for i in xrange(7): cache.create_book_entry(Metadata("title%d" % i), apply_import_tags=False) cache.create_custom_column("one", "CC1", "int", False) cache.create_custom_column("two", "CC2", "int", False) cache.create_custom_column("three", "CC3", "int", False) cache.close() cache = self.init_cache() cache.set_field("#one", {(i + (5 * m)): m for m in (0, 1) for i in xrange(1, 6)}) cache.set_field("#two", {i + (m * 3): m for m in (0, 1, 2) for i in (1, 2, 3)}) cache.set_field("#two", {10: 2}) cache.set_field("#three", {i: i for i in xrange(1, 11)}) ae( list(xrange(1, 11)), cache.multisort([("#one", True), ("#two", True)], ids_to_sort=sorted(cache.all_book_ids())), ) ae( [4, 5, 1, 2, 3, 7, 8, 9, 10, 6], cache.multisort([("#one", True), ("#two", False)], ids_to_sort=sorted(cache.all_book_ids())), ) ae( [5, 4, 3, 2, 1, 10, 9, 8, 7, 6], cache.multisort( [("#one", True), ("#two", False), ("#three", False)], ids_to_sort=sorted(cache.all_book_ids()) ), )
def test_sorting(self): # {{{ 'Test sorting' cache = self.init_cache() for field, order in { 'title' : [2, 1, 3], 'authors': [2, 1, 3], 'series' : [3, 1, 2], 'tags' : [3, 1, 2], 'rating' : [3, 2, 1], # 'identifiers': [3, 2, 1], There is no stable sort since 1 and # 2 have the same identifier keys # 'last_modified': [3, 2, 1], There is no stable sort as two # records have the exact same value 'timestamp': [2, 1, 3], 'pubdate' : [1, 2, 3], 'publisher': [3, 2, 1], 'languages': [3, 2, 1], 'comments': [3, 2, 1], '#enum' : [3, 2, 1], '#authors' : [3, 2, 1], '#date': [3, 1, 2], '#rating':[3, 2, 1], '#series':[3, 2, 1], '#tags':[3, 2, 1], '#yesno':[2, 1, 3], '#comments':[3, 2, 1], }.iteritems(): x = list(reversed(order)) self.assertEqual(order, cache.multisort([(field, True)], ids_to_sort=x), 'Ascending sort of %s failed'%field) self.assertEqual(x, cache.multisort([(field, False)], ids_to_sort=order), 'Descending sort of %s failed'%field) # Test subsorting self.assertEqual([3, 2, 1], cache.multisort([('identifiers', True), ('title', True)]), 'Subsort failed') # Test sorting of is_multiple fields. # Author like fields should be sorted by generating sort names from the # actual values in entry order for field in ('authors', '#authors'): self.assertEqual( cache.set_field(field, {1:('aa bb', 'bb cc', 'cc dd'), 2:('bb aa', 'xx yy'), 3: ('aa bb', 'bb aa')}), {1, 2, 3}) self.assertEqual([2, 3, 1], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) self.assertEqual([1, 3, 2], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # All other is_multiple fields should be sorted by sorting the values # for each book and using that as the sort key for field in ('tags', '#tags'): self.assertEqual( cache.set_field(field, {1:('b', 'a'), 2:('c', 'y'), 3: ('b', 'z')}), {1, 2, 3}) self.assertEqual([1, 3, 2], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) self.assertEqual([2, 3, 1], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # Test tweak to sort dates by visible format from calibre.utils.date import parse_only_date as p from calibre.utils.config_base import Tweak self.assertEqual(cache.set_field('pubdate', {1:p('2001-3-3'), 2:p('2002-2-3'), 3:p('2003-1-3')}), {1, 2, 3}) self.assertEqual([1, 2, 3], cache.multisort([('pubdate', True)])) with Tweak('gui_pubdate_display_format', 'MMM'), Tweak('sort_dates_using_visible_fields', True): c2 = self.init_cache() self.assertEqual([3, 2, 1], c2.multisort([('pubdate', True)])) # Test bool sorting when not tristate cache.set_pref('bools_are_tristate', False) c2 = self.init_cache() self.assertEqual([2, 3, 1], c2.multisort([('#yesno', True), ('id', False)]))
def test_sorting(self): # {{{ 'Test sorting' cache = self.init_cache() ae = self.assertEqual for field, order in { 'title' : [2, 1, 3], 'authors': [2, 1, 3], 'series' : [3, 1, 2], 'tags' : [3, 1, 2], 'rating' : [3, 2, 1], # 'identifiers': [3, 2, 1], There is no stable sort since 1 and # 2 have the same identifier keys # 'last_modified': [3, 2, 1], There is no stable sort as two # records have the exact same value 'timestamp': [2, 1, 3], 'pubdate' : [1, 2, 3], 'publisher': [3, 2, 1], 'languages': [3, 2, 1], 'comments': [3, 2, 1], '#enum' : [3, 2, 1], '#authors' : [3, 2, 1], '#date': [3, 1, 2], '#rating':[3, 2, 1], '#series':[3, 2, 1], '#tags':[3, 2, 1], '#yesno':[2, 1, 3], '#comments':[3, 2, 1], 'id': [1, 2, 3], }.iteritems(): x = list(reversed(order)) ae(order, cache.multisort([(field, True)], ids_to_sort=x), 'Ascending sort of %s failed'%field) ae(x, cache.multisort([(field, False)], ids_to_sort=order), 'Descending sort of %s failed'%field) # Test sorting of is_multiple fields. # Author like fields should be sorted by generating sort names from the # actual values in entry order for field in ('authors', '#authors'): ae( cache.set_field(field, {1:('aa bb', 'bb cc', 'cc dd'), 2:('bb aa', 'xx yy'), 3: ('aa bb', 'bb aa')}), {1, 2, 3}) ae([2, 3, 1], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) ae([1, 3, 2], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # All other is_multiple fields should be sorted by sorting the values # for each book and using that as the sort key for field in ('tags', '#tags'): ae( cache.set_field(field, {1:('b', 'a'), 2:('c', 'y'), 3: ('b', 'z')}), {1, 2, 3}) ae([1, 3, 2], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) ae([2, 3, 1], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # Test tweak to sort dates by visible format from calibre.utils.date import parse_only_date as p from calibre.utils.config_base import Tweak ae(cache.set_field('pubdate', {1:p('2001-3-3'), 2:p('2002-2-3'), 3:p('2003-1-3')}), {1, 2, 3}) ae([1, 2, 3], cache.multisort([('pubdate', True)])) with Tweak('gui_pubdate_display_format', 'MMM'), Tweak('sort_dates_using_visible_fields', True): c2 = self.init_cache() ae([3, 2, 1], c2.multisort([('pubdate', True)])) # Test bool sorting when not tristate cache.set_pref('bools_are_tristate', False) c2 = self.init_cache() ae([2, 3, 1], c2.multisort([('#yesno', True), ('id', False)])) # Test subsorting ae([3, 2, 1], cache.multisort([('identifiers', True), ('title', True)]), 'Subsort failed') from calibre.ebooks.metadata.book.base import Metadata for i in xrange(7): cache.create_book_entry(Metadata('title%d' % i), apply_import_tags=False) cache.create_custom_column('one', 'CC1', 'int', False) cache.create_custom_column('two', 'CC2', 'int', False) cache.create_custom_column('three', 'CC3', 'int', False) cache.close() cache = self.init_cache() cache.set_field('#one', {(i+(5*m)):m for m in (0, 1) for i in xrange(1, 6)}) cache.set_field('#two', {i+(m*3):m for m in (0, 1, 2) for i in (1, 2, 3)}) cache.set_field('#two', {10:2}) cache.set_field('#three', {i:i for i in xrange(1, 11)}) ae(list(xrange(1, 11)), cache.multisort([('#one', True), ('#two', True)], ids_to_sort=sorted(cache.all_book_ids()))) ae([4, 5, 1, 2, 3, 7,8, 9, 10, 6], cache.multisort([('#one', True), ('#two', False)], ids_to_sort=sorted(cache.all_book_ids()))) ae([5, 4, 3, 2, 1, 10, 9, 8, 7, 6], cache.multisort([('#one', True), ('#two', False), ('#three', False)], ids_to_sort=sorted(cache.all_book_ids())))
def test_sorting(self): # {{{ 'Test sorting' cache = self.init_cache() for field, order in { 'title': [2, 1, 3], 'authors': [2, 1, 3], 'series': [3, 1, 2], 'tags': [3, 1, 2], 'rating': [3, 2, 1], # 'identifiers': [3, 2, 1], There is no stable sort since 1 and # 2 have the same identifier keys # 'last_modified': [3, 2, 1], There is no stable sort as two # records have the exact same value 'timestamp': [2, 1, 3], 'pubdate': [1, 2, 3], 'publisher': [3, 2, 1], 'languages': [3, 2, 1], 'comments': [3, 2, 1], '#enum': [3, 2, 1], '#authors': [3, 2, 1], '#date': [3, 1, 2], '#rating': [3, 2, 1], '#series': [3, 2, 1], '#tags': [3, 2, 1], '#yesno': [2, 1, 3], '#comments': [3, 2, 1], }.iteritems(): x = list(reversed(order)) self.assertEqual(order, cache.multisort([(field, True)], ids_to_sort=x), 'Ascending sort of %s failed' % field) self.assertEqual( x, cache.multisort([(field, False)], ids_to_sort=order), 'Descending sort of %s failed' % field) # Test subsorting self.assertEqual([3, 2, 1], cache.multisort([('identifiers', True), ('title', True)]), 'Subsort failed') # Test sorting of is_multiple fields. # Author like fields should be sorted by generating sort names from the # actual values in entry order for field in ('authors', '#authors'): self.assertEqual( cache.set_field( field, { 1: ('aa bb', 'bb cc', 'cc dd'), 2: ('bb aa', 'xx yy'), 3: ('aa bb', 'bb aa') }), {1, 2, 3}) self.assertEqual([2, 3, 1], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) self.assertEqual([1, 3, 2], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # All other is_multiple fields should be sorted by sorting the values # for each book and using that as the sort key for field in ('tags', '#tags'): self.assertEqual( cache.set_field(field, { 1: ('b', 'a'), 2: ('c', 'y'), 3: ('b', 'z') }), {1, 2, 3}) self.assertEqual([1, 3, 2], cache.multisort([(field, True)], ids_to_sort=(1, 2, 3))) self.assertEqual([2, 3, 1], cache.multisort([(field, False)], ids_to_sort=(1, 2, 3))) # Test tweak to sort dates by visible format from calibre.utils.date import parse_only_date as p from calibre.utils.config_base import Tweak self.assertEqual( cache.set_field('pubdate', { 1: p('2001-3-3'), 2: p('2002-2-3'), 3: p('2003-1-3') }), {1, 2, 3}) self.assertEqual([1, 2, 3], cache.multisort([('pubdate', True)])) with Tweak('gui_pubdate_display_format', 'MMM'), Tweak('sort_dates_using_visible_fields', True): c2 = self.init_cache() self.assertEqual([3, 2, 1], c2.multisort([('pubdate', True)])) # Test bool sorting when not tristate cache.set_pref('bools_are_tristate', False) c2 = self.init_cache() self.assertEqual([2, 3, 1], c2.multisort([('#yesno', True), ('id', False)]))