%PDF- %PDF-
Direktori : /lib/calibre/calibre/utils/ |
Current File : //lib/calibre/calibre/utils/search_query_parser_test.py |
#!/usr/bin/env python3 # License: GPLv3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net> import operator import unittest from calibre.utils.search_query_parser import SearchQueryParser, Parser class Tester(SearchQueryParser): texts = { 1: ['Eugenie Grandet', 'Honor\xe9 de Balzac', 'manybooks.net', 'lrf'], 2: ['Fanny Hill', 'John Cleland', 'manybooks.net', 'lrf'], 3: ['Persuasion', 'Jane Austen', 'manybooks.net', 'lrf'], 4: ['Psmith, Journalist', 'P. G. Wodehouse', 'Some Publisher', 'lrf'], 5: ['The Complete Works of William Shakespeare', 'William Shakespeare', 'manybooks.net', 'lrf'], 6: ['The History of England, Volume I', 'David Hume', 'manybooks.net', 'lrf'], 7: ['Someone Comes to Town, Someone Leaves Town', 'Cory Doctorow', 'Tor Books', 'lrf'], 8: ['Stalky and Co.', 'Rudyard Kipling', 'manybooks.net', 'lrf'], 9: ['A Game of Thrones', 'George R. R. Martin', None, 'lrf,rar'], 10: ['A Clash of Kings', 'George R. R. Martin', None, 'lrf,rar'], 11: ['A Storm of Swords', 'George R. R. Martin', None, 'lrf,rar'], 12: ['Biggles - Pioneer Air Fighter', 'W. E. Johns', None, 'lrf,rtf'], 13: ['Biggles of the Camel Squadron', 'W. E. Johns', 'London:Thames, (1977)', 'lrf,rtf'], 14: ['A Feast for Crows', 'George R. R. Martin', None, 'lrf,rar'], 15: ['Cryptonomicon', 'Neal Stephenson', None, 'lrf,rar'], 16: ['Quicksilver', 'Neal Stephenson', None, 'lrf,zip'], 17: ['The Comedies of William Shakespeare', 'William Shakespeare', None, 'lrf'], 18: ['The Histories of William Shakespeare', 'William Shakespeare', None, 'lrf'], 19: ['The Tragedies of William Shakespeare', 'William Shakespeare', None, 'lrf'], 20: ['An Ideal Husband', 'Oscar Wilde', 'manybooks.net', 'lrf'], 21: ['Flight of the Nighthawks', 'Raymond E. Feist', None, 'lrf,rar'], 22: ['Into a Dark Realm', 'Raymond E. Feist', None, 'lrf,rar'], 23: ['The Sundering', 'Walter Jon Williams', None, 'lrf,rar'], 24: ['The Praxis', 'Walter Jon Williams', None, 'lrf,rar'], 25: ['Conventions of War', 'Walter Jon Williams', None, 'lrf,rar'], 26: ['Banewreaker', 'Jacqueline Carey', None, 'lrf,rar'], 27: ['Godslayer', 'Jacqueline Carey', None, 'lrf,rar'], 28: ["Kushiel's Scion", 'Jacqueline Carey', None, 'lrf,rar'], 29: ['Underworld', 'Don DeLillo', None, 'lrf,rar'], 30: ['Genghis Khan and The Making of the Modern World', 'Jack Weatherford Orc', 'Three Rivers Press', 'lrf,zip'], 31: ['The Best and the Brightest', 'David Halberstam', 'Modern Library', 'lrf,zip'], 32: ['The Killer Angels', 'Michael Shaara', None, 'html,lrf'], 33: ['Band Of Brothers', 'Stephen E Ambrose', None, 'lrf,txt'], 34: ['The Gates of Rome', 'Conn Iggulden', None, 'lrf,rar'], 35: ['The Death of Kings', 'Conn Iggulden', 'Bantam Dell', 'lit,lrf'], 36: ['The Field of Swords', 'Conn Iggulden', None, 'lrf,rar'], 37: ['Masterman Ready', 'Marryat, Captain Frederick', None, 'lrf'], 38: ['With the Lightnings', 'David Drake', 'Baen Publishing Enterprises', 'lit,lrf'], 39: ['Lt. Leary, Commanding', 'David Drake', 'Baen Publishing Enterprises', 'lit,lrf'], 40: ['The Far Side of The Stars', 'David Drake', 'Baen Publishing Enterprises', 'lrf,rar'], 41: ['The Way to Glory', 'David Drake', 'Baen Publishing Enterprises', 'lrf,rar'], 42: ['Some Golden Harbor', 'David Drake', 'Baen Books', 'lrf,rar'], 43: ['Harry Potter And The Half-Blood Prince', 'J. K. Rowling', None, 'lrf,rar'], 44: ['Harry Potter and the Order of the Phoenix', 'J. K. Rowling', None, 'lrf,rtf'], 45: ['The Stars at War', 'David Weber , Steve White', None, 'lrf,rtf'], 46: ['The Stars at War II', 'Steve White', 'Baen Publishing Enterprises', 'lrf,rar'], 47: ['Exodus', 'Steve White,Shirley Meier', 'Baen Books', 'lrf,rar'], 48: ['Harry Potter and the Goblet of Fire', 'J. K. Rowling', None, 'lrf,rar'], 49: ['Harry Potter and the Prisoner of Azkaban', 'J. K. Rowling', None, 'lrf,rtf'], 50: ['Harry Potter and the Chamber of Secrets', 'J. K. Rowling', None, 'lit,lrf'], 51: ['Harry Potter and the Deathly Hallows', 'J.K. Rowling', None, 'lit,lrf,pdf'], 52: ["His Majesty's Dragon", 'Naomi Novik', None, 'lrf,rar'], 53: ['Throne of Jade', 'Naomi Novik', 'Del Rey', 'lit,lrf'], 54: ['Black Powder War', 'Naomi Novik', 'Del Rey', 'lrf,rar'], 55: ['War and Peace', 'Leo Tolstoy', 'gutenberg.org', 'lrf,txt'], 56: ['Anna Karenina', 'Leo Tolstoy', 'gutenberg.org', 'lrf,txt'], 57: ['A Shorter History of Rome', 'Eugene Lawrence,Sir William Smith', 'gutenberg.org', 'lrf,zip'], 58: ['The Name of the Rose', 'Umberto Eco', None, 'lrf,rar'], 71: ["Wind Rider's Oath", 'David Weber', 'Baen', 'lrf'], 74: ['Rally Cry', 'William R Forstchen', None, 'htm,lrf'], 86: ['Empire of Ivory', 'Naomi Novik', None, 'lrf,rar'], 87: ["Renegade's Magic", 'Robin Hobb', None, 'lrf,rar'], 89: ['Master and commander', "Patrick O'Brian", 'Fontana,\n1971', 'lit,lrf'], 91: ['A Companion to Wolves', 'Sarah Monette,Elizabeth Beär', None, 'lrf,rar'], 92: ['The Lions of al-Rassan', 'Guy Gavriel Kay', 'Eos', 'lit,lrf'], 93: ['Gardens of the Moon', 'Steven Erikson', 'Tor Fantasy', 'lit,lrf'], 95: ['The Master and Margarita', 'Mikhail Bulgakov', 'N.Y. : Knopf, 1992.', 'lrf,rtf'], 120: ['Deadhouse Gates', 'Steven Erikson', 'London : Bantam Books, 2001.', 'lit,lrf'], 121: ['Memories of Ice', 'Steven Erikson', 'Bantam Books', 'lit,lrf'], 123: ['House of Chains', 'Steven Erikson', 'Bantam Books', 'lit,lrf'], 125: ['Midnight Tides', 'Steven Erikson', 'Bantam Books', 'lit,lrf'], 126: ['The Bonehunters', 'Steven Erikson', 'Bantam Press', 'lit,lrf'], 129: ['Guns, germs, and steel: the fates of human societies', 'Jared Diamond', 'New York : W.W. Norton, c1997.', 'lit,lrf'], 136: ['Wildcards', 'George R. R. Martin', None, 'html,lrf'], 138: ['Off Armageddon Reef', 'David Weber', 'Tor Books', 'lit,lrf'], 144: ['Atonement', 'Ian McEwan', 'New York : Nan A. Talese/Doubleday, 2002.', 'lrf,rar'], 146: ['1632', 'Eric Flint', 'Baen Books', 'lit,lrf'], 147: ['1633', 'David Weber,Eric Flint,Dru Blair', 'Baen', 'lit,lrf'], 148: ['1634: The Baltic War', 'David Weber,Eric Flint', 'Baen', 'lit,lrf'], 150: ['The Dragonbone Chair', 'Tad Williams', 'DAW Trade', 'lrf,rtf'], 152: ['The Little Book That Beats the Market', 'Joel Greenblatt', 'Wiley', 'epub,lrf'], 153: ['Pride of Carthage', 'David Anthony Durham', 'Anchor', 'lit,lrf'], 154: ['Stone of farewell', 'Tad Williams', 'New York : DAW Books, 1990.', 'lrf,txt'], 166: ['American Gods', 'Neil Gaiman', 'HarperTorch', 'lit,lrf'], 176: ['Pillars of the Earth', 'Ken Follett', 'New American Library', 'lit,lrf'], 182: ['The Eye of the world', 'Robert Jordan', 'New York : T. Doherty Associates, c1990.', 'lit,lrf'], 188: ['The Great Hunt', 'Robert Jordan', 'ATOM', 'lrf,zip'], 189: ['The Dragon Reborn', 'Robert Jordan', None, 'lit,lrf'], 190: ['The Shadow Rising', 'Robert Jordan', None, 'lit,lrf'], 191: ['The Fires of Heaven', 'Robert Jordan', 'Time Warner Books Uk', 'lit,lrf'], 216: ['Lord of chaos', 'Robert Jordan', 'New York : TOR, c1994.', 'lit,lrf'], 217: ['A Crown of Swords', 'Robert Jordan', None, 'lit,lrf'], 236: ['The Path of Daggers', 'Robert Jordan', None, 'lit,lrf'], 238: ['The Client', 'John Grisham', 'New York : Island, 1994, c1993.', 'lit,lrf'], 240: ["Winter's Heart", 'Robert Jordan', None, 'lit,lrf'], 242: ['In the Beginning was the Command Line', 'Neal Stephenson', None, 'lrf,txt'], 249: ['Crossroads of Twilight', 'Robert Jordan', None, 'lit,lrf'], 251: ['Caves of Steel', 'Isaac Asimov', 'Del Rey', 'lrf,zip'], 253: ["Hunter's Run", 'George R. R. Martin,Gardner Dozois,Daniel Abraham', 'Eos', 'lrf,rar'], 257: ['Knife of Dreams', 'Robert Jordan', None, 'lit,lrf'], 258: ['Saturday', 'Ian McEwan', 'London : Jonathan Cape, 2005.', 'lrf,txt'], 259: ['My name is Red', 'Orhan Pamuk; translated from the Turkish by Erda\u011f G\xf6knar', 'New York : Alfred A. Knopf, 2001.', 'lit,lrf'], 265: ['Harbinger', 'David Mack', 'Star Trek', 'lit,lrf'], 267: ['Summon the Thunder', 'Dayton Ward,Kevin Dilmore', 'Pocket Books', 'lit,lrf'], 268: ['Shalimar the Clown', 'Salman Rushdie', 'New York : Random House, 2005.', 'lit,lrf'], 269: ['Reap the Whirlwind', 'David Mack', 'Star Trek', 'lit,lrf'], 272: ['Mistborn', 'Brandon Sanderson', 'Tor Fantasy', 'lrf,rar'], 273: ['The Thousandfold Thought', 'R. Scott Bakker', 'Overlook TP', 'lrf,rtf'], 276: ['Elantris', 'Brandon Sanderson', 'New York : Tor, 2005.', 'lrf,rar'], 291: ['Sundiver', 'David Brin', 'New York : Bantam Books, 1995.', 'lit,lrf'], 299: ['Imperium', 'Robert Harris', 'Arrow', 'lrf,rar'], 300: ['Startide Rising', 'David Brin', 'Bantam', 'htm,lrf'], 301: ['The Uplift War', 'David Brin', 'Spectra', 'lit,lrf'], 304: ['Brightness Reef', 'David Brin', 'Orbit', 'lrf,rar'], 305: ["Infinity's Shore", 'David Brin', 'Spectra', 'txt'], 306: ["Heaven's Reach", 'David Brin', 'Spectra', 'lrf,rar'], 325: ["Foundation's Triumph", 'David Brin', 'Easton Press', 'lit,lrf'], 327: ['I am Charlotte Simmons', 'Tom Wolfe', 'Vintage', 'htm,lrf'], 335: ['The Currents of Space', 'Isaac Asimov', None, 'lit,lrf'], 340: ['The Other Boleyn Girl', 'Philippa Gregory', 'Touchstone', 'lit,lrf'], 341: ["Old Man's War", 'John Scalzi', 'Tor', 'htm,lrf'], 342: ['The Ghost Brigades', 'John Scalzi', 'Tor Science Fiction', 'html,lrf'], 343: ['The Last Colony', 'John S"calzi', 'Tor Books', 'html,lrf'], 344: ['Gossip Girl', 'Cecily von Ziegesar', 'Warner Books', 'lrf,rtf'], 347: ['Little Brother', 'Cory Doctorow', 'Tor Teen', 'lrf'], 348: ['The Reality Dysfunction', 'Peter F. Hamilton', 'Pan MacMillan', 'lit,lrf'], 353: ['A Thousand Splendid Suns', 'Khaled Hosseini', 'Center Point Large Print', 'lit,lrf'], 354: ['Amsterdam', 'Ian McEwan', 'Anchor', 'lrf,txt'], 355: ['The Neutronium Alchemist', 'Peter F. Hamilton', 'Aspect', 'lit,lrf'], 356: ['The Naked God', 'Peter F. Hamilton', 'Aspect', 'lit,lrf'], 421: ['A Shadow in Summer', 'Daniel Abraham', 'Tor Fantasy', 'lrf,rar'], 427: ['Lonesome Dove', 'Larry M\\cMurtry', None, 'lit,lrf'], 440: ['Ghost', 'John Ringo', 'Baen', 'lit,lrf'], 441: ['Kildar', 'John Ringo', 'Baen', 'lit,lrf'], 443: ['Hidden Empire ', 'Kevin J. Anderson', 'Aspect', 'lrf,rar'], 444: ['The Gun Seller', 'Hugh Laurie', 'Washington Square Press', 'lrf,rar'] } tests = { 'Dysfunction' : {348}, 'title:Dysfunction' : {348}, 'Title:Dysfunction' : {348}, 'title:Dysfunction OR author:Laurie': {348, 444}, '(tag:txt or tag:pdf)': {33, 258, 354, 305, 242, 51, 55, 56, 154}, '(tag:txt OR tag:pdf) and author:Tolstoy': {55, 56}, 'Tolstoy txt': {55, 56}, 'Hamilton Amsterdam' : set(), 'Beär' : {91}, 'dysfunc or tolstoy': {348, 55, 56}, 'tag:txt AND NOT tolstoy': {33, 258, 354, 305, 242, 154}, 'not tag:lrf' : {305}, 'london:thames': {13}, 'publisher:london:thames': {13}, '"(1977)"': {13}, 'jack weatherford orc': {30}, 'S\\"calzi': {343}, 'author:S\\"calzi': {343}, '"S\\"calzi"': {343}, 'M\\\\cMurtry': {427}, 'author:Tolstoy (tag:txt OR tag:pdf)': {55, 56}, } fields = {'title':0, 'author':1, 'publisher':2, 'tag':3} _universal_set = set(texts.keys()) def universal_set(self): return self._universal_set def get_matches(self, location, query, candidates=None): location = location.lower() if location in self.fields.keys(): getter = operator.itemgetter(self.fields[location]) elif location == 'all': getter = lambda y: ''.join(x if x else '' for x in y) else: getter = lambda x: '' if not query: return set() query = query.lower() if candidates: return {key for key, val in self.texts.items() if key in candidates and query and query in getattr(getter(val), 'lower', lambda : '')()} else: return {key for key, val in self.texts.items() if query and query in getattr(getter(val), 'lower', lambda : '')()} def run_tests(self, ae): for query in self.tests.keys(): res = self.parse(query) ae(self.tests[query], res, f'Failed for query: {query}') class TestSQP(unittest.TestCase): def do_test(self, optimize=False): tester = Tester(['authors', 'author', 'series', 'formats', 'format', 'publisher', 'rating', 'tags', 'tag', 'comments', 'comment', 'cover', 'isbn', 'ondevice', 'pubdate', 'size', 'date', 'title', '#read', 'all', 'search'], test=True, optimize=optimize) tester.run_tests(self.assertEqual) def test_sqp_optimized(self): self.do_test(True) def test_sqp_unoptimized(self): self.do_test(False) def test_sqp_tokenizer(self): p = Parser() def tokens(*a): ans = [] for i in range(0, len(a), 2): ans.append(({'O': Parser.OPCODE, 'W': Parser.WORD, 'Q': Parser.QUOTED_WORD}[a[i]], a[i+1])) return ans def t(query, *a): self.assertEqual(tokens(*a), p.tokenize(query)) t('xxx', 'W', 'xxx') t('"a \\" () b"', 'Q', 'a " () b') t('"a“b"', 'Q', 'a“b') t('"a”b"', 'Q', 'a”b') def find_tests(): return unittest.defaultTestLoader.loadTestsFromTestCase(TestSQP) class TestRunner(unittest.main): def createTests(self): self.test = find_tests() def run(verbosity=4): TestRunner(verbosity=verbosity, exit=False) if __name__ == '__main__': run()