[
  {
    "path": ".gitignore",
    "content": "*.pyc\n*.db\n*.txt\n.DS_Store\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Rob Dawson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# markov-text\nThis is a Python implementation of a Markov Text Generator.\n\nA [Markov Text Generator](http://en.wikipedia.org/wiki/Markov_chain) can be used to randomly generate (somewhat) realistic sentences, using words from a source text. Words are joined together in sequence, with each new word being selected based on how often it follows the previous word in the source document.\n\nThe results are often just nonsense, but at times can be strangely poetic - the sentences below were generated from the text of The Hitchhikers Guide to the Galaxy:\n\n> Bits of perpetual unchangingness.  \n> So long waves of matter, strained, twisted sharply.  \n> So they are going to undulate across him and the species.  \n> The barman reeled for every particle of Gold streaked through her eye.  \n> We've met, haven't they? Look, said Ford never have good time you are merely a receipt.  \n> The silence was delighted.\n\n### Parsing\n\n<section>To use the utility, first find a source document (the larger the better) and save it as a UTF-8 encoded text file. Executing the utility in 'parse' mode, as shown, will create a .db file containing information about how frequently words follow other words in the text file.\n\n<pre>python markov.py parse &lt;name&gt; &lt;depth&gt; &lt;file&gt;\n</pre>\n\n*   The `name` argument can be any non-empty value - this is just the name you have chosen for the source document\n*   The `depth` argument is a numeric value (minimum 2) which determines how many of the previous words are used to select the next word. Normally a depth of 2 is used, meaning that each word is selected based only on the previous one. The larger the depth value, the more similar the generated sentences will be to those appearing in the source text. Beyond a certain depth the generated sentences will be identical to those appearing in the source.\n*   The `file` argument indicates the location of the source text file\n\nFor example:\n\n<pre>python markov.py parse hitchhikers_guide 2 /path/to/hitchhikers.txt\n</pre>\n\nThe parsing process may take a while to complete, depending on the size of the input document.</section>\n\n### Generating\n\n<section>To generate new sentences, run the utility in 'generate' mode, using the name specified during the parse operation\n\n<pre>python markov.py gen &lt;name&gt; &lt;count&gt;\n</pre>\n\n*   The `name` argument should match the name used with the earlier `parse` command\n*   The `count` argument is a numeric value indicating how many sentences to generate\n\nFor example:\n\n<pre>>python markov.py gen hitchhikers_guide 3\nLook, I can't speak Vogon! You don't need to touch the water\nHe frowned, then smiled, then tried to gauge the speed at which they were able to pick up hitch hikers\nThe hatchway sealed itself tight, and all the streets around it\n</pre>\n\n</section>\n"
  },
  {
    "path": "db.py",
    "content": "\r\nclass Db:\r\n\tDEPTH_PARAM_NAME = 'depth'\r\n\t\r\n\tdef __init__(self, conn, sql):\r\n\t\tself.conn   = conn \r\n\t\tself.cursor = conn.cursor()\r\n\t\tself.sql    = sql\r\n\t\tself.depth  = None\r\n\r\n\tdef setup(self, depth):\r\n\t\tself.depth = depth\r\n\t\tself.cursor.execute(self.sql.create_word_table_sql(depth))\r\n\t\tself.cursor.execute(self.sql.create_index_sql(depth))\r\n\t\tself.cursor.execute(self.sql.create_param_table_sql())\r\n\t\tself.cursor.execute(self.sql.set_param_sql(), (self.DEPTH_PARAM_NAME, depth))\r\n\r\n\tdef _get_word_list_count(self, word_list):\r\n\t\tif len(word_list) != self.get_depth():\r\n\t\t\traise ValueError('Expected %s words in list but found %s' % (self.get_depth(), len(word_list)))\r\n\r\n\t\tself.cursor.execute(self.sql.select_count_for_words_sql(self.get_depth()), word_list)\r\n\t\tr = self.cursor.fetchone()\r\n\t\tif r:\r\n\t\t\treturn r[0]\r\n\t\telse:\r\n\t\t\treturn 0\r\n\r\n\tdef get_depth(self):\r\n\t\tif self.depth == None:\r\n\t\t\tself.cursor.execute(self.sql.get_param_sql(), (self.DEPTH_PARAM_NAME,))\r\n\t\t\tr = self.cursor.fetchone()\r\n\t\t\tif r:\r\n\t\t\t\tself.depth = int(r[0])\r\n\t\t\telse:\r\n\t\t\t\traise ValueError('No depth value found in database, db does not seem to have been created by this utility')\r\n\t\t\t\r\n\t\treturn self.depth\r\n\t\t\r\n\tdef add_word(self, word_list):\r\n\t\tcount = self._get_word_list_count(word_list)\r\n\t\tif count:\r\n\t\t\tself.cursor.execute(self.sql.update_count_for_words_sql(self.get_depth()), [count + 1] + word_list)\r\n\t\telse:\r\n\t\t\tself.cursor.execute(self.sql.insert_row_for_words_sql(self.get_depth()), word_list + [1])\r\n\r\n\tdef commit(self):\r\n\t\tself.conn.commit()\r\n\r\n\tdef get_word_count(self, word_list):\r\n\t\tcounts = {}\r\n\t\tsql = self.sql.select_words_and_counts_sql(self.get_depth())\r\n\t\tfor row in self.cursor.execute(sql, word_list):\r\n\t\t\tcounts[row[0]] = row[1]\r\n\r\n\t\treturn counts\r\n"
  },
  {
    "path": "gen.py",
    "content": "from parse import Parser\r\n\r\nclass Generator:\r\n\tdef __init__(self, name, db, rnd):\r\n\t\tself.name = name\r\n\t\tself.db   = db\r\n\t\tself.rnd  = rnd\r\n\r\n\tdef _get_next_word(self, word_list):\r\n\t\tcandidate_words = self.db.get_word_count(word_list)\r\n\t\ttotal_next_words = sum(candidate_words.values())\r\n\t\ti = self.rnd.randint(total_next_words)\r\n\t\tt=0\r\n\t\tfor w in candidate_words.keys():\r\n\t\t\tt += candidate_words[w]\r\n\t\t\tif (i <= t):\r\n\t\t\t\treturn w\r\n\t\tassert False\r\n\r\n\tdef generate(self, word_separator):\r\n\t\tdepth = self.db.get_depth()\r\n\t\tsentence = [Parser.SENTENCE_START_SYMBOL] * (depth - 1)\r\n\t\tend_symbol = [Parser.SENTENCE_END_SYMBOL] * (depth - 1)\r\n\r\n\t\twhile True:\r\n\t\t\ttail = sentence[(-depth+1):]\r\n\t\t\tif tail == end_symbol:\r\n\t\t\t\tbreak\r\n\t\t\tword = self._get_next_word(tail)\r\n\t\t\tsentence.append(word)\r\n\t\t\r\n\t\treturn word_separator.join(sentence[depth-1:][:1-depth])\r\n"
  },
  {
    "path": "markov.py",
    "content": "from db import Db\r\nfrom gen import Generator\r\nfrom parse import Parser\r\nfrom sql import Sql\r\nfrom rnd import Rnd\r\nimport sys\r\nimport sqlite3\r\nimport codecs\r\n\r\nSENTENCE_SEPARATOR = '.'\r\nWORD_SEPARATOR = ' '\r\n\r\nif __name__ == '__main__':\r\n\targs = sys.argv\r\n\tusage = 'Usage: %s (parse <name> <depth> <path to txt file>|gen <name> <count>)' % (args[0], )\r\n\r\n\tif (len(args) < 3):\r\n\t\traise ValueError(usage)\r\n\r\n\tmode  = args[1]\r\n\tname  = args[2]\r\n\t\r\n\tif mode == 'parse':\r\n\t\tif (len(args) != 5):\r\n\t\t\traise ValueError(usage)\r\n\t\t\r\n\t\tdepth = int(args[3])\r\n\t\tfile_name = args[4]\r\n\t\t\r\n\t\tdb = Db(sqlite3.connect(name + '.db'), Sql())\r\n\t\tdb.setup(depth)\r\n\t\t\r\n\t\ttxt = codecs.open(file_name, 'r', 'utf-8').read()\r\n\t\tParser(name, db, SENTENCE_SEPARATOR, WORD_SEPARATOR).parse(txt)\r\n\t\r\n\telif mode == 'gen':\r\n\t\tcount = int(args[3])\r\n\t\tdb = Db(sqlite3.connect(name + '.db'), Sql())\r\n\t\tgenerator = Generator(name, db, Rnd())\r\n\t\tfor i in range(0, count):\r\n\t\t\tprint(generator.generate(WORD_SEPARATOR))\r\n\t\r\n\telse:\r\n\t\traise ValueError(usage)\r\n"
  },
  {
    "path": "parse.py",
    "content": "import sys\r\nimport re\r\n\r\nclass Parser:\r\n\tSENTENCE_START_SYMBOL = '^'\r\n\tSENTENCE_END_SYMBOL = '$'\r\n\r\n\tdef __init__(self, name, db, sentence_split_char = '\\n', word_split_char = ''):\r\n\t\tself.name = name\r\n\t\tself.db   = db\r\n\t\tself.sentence_split_char = sentence_split_char\r\n\t\tself.word_split_char = word_split_char\r\n\t\tself.whitespace_regex = re.compile('\\s+')\r\n\r\n\tdef parse(self, txt):\r\n\t\tdepth = self.db.get_depth()\r\n\t\tsentences = txt.split(self.sentence_split_char)\r\n\t\ti = 0\r\n\r\n\t\tfor sentence in sentences:\r\n\t\t\tsentence = self.whitespace_regex.sub(\" \", sentence).strip()\r\n\r\n\t\t\tlist_of_words = None\r\n\t\t\tif self.word_split_char:\r\n\t\t\t\tlist_of_words = sentence.split(self.word_split_char)\r\n\t\t\telse:\r\n\t\t\t\tlist_of_words = list(sentence.lower())\r\n\r\n\t\t\twords = [Parser.SENTENCE_START_SYMBOL] * (depth - 1) + list_of_words + [Parser.SENTENCE_END_SYMBOL] * (depth - 1)\r\n\t\t\t\r\n\t\t\tfor n in range(0, len(words) - depth + 1):\r\n\t\t\t\tself.db.add_word(words[n:n+depth])\r\n\r\n\t\t\ti += 1\r\n\t\t\tif i % 1000 == 0:\r\n\t\t\t\tprint(i)\r\n\t\t\t\tsys.stdout.flush()\r\n\r\n\t\tself.db.commit()\r\n\r\n"
  },
  {
    "path": "rnd.py",
    "content": "from random import randint\n\nclass Rnd:\n    def randint(self, maxint):\n        return randint(1, maxint)"
  },
  {
    "path": "sql.py",
    "content": "class Sql:\n    WORD_COL_NAME_PREFIX = 'word'\n    COUNT_COL_NAME       = 'count'\n    WORD_TABLE_NAME      = 'word'\n    INDEX_NAME           = 'i_word'\n    PARAM_TABLE_NAME     = 'param'\n    KEY_COL_NAME         = 'name'\n    VAL_COL_NAME         = 'value'\n    \n    def _check_column_count(self, count):\n        if count < 2:\n            raise ValueError('Invalid column_count value, must be >= 2')\n        \n    def _make_column_name_list(self, column_count):\n        return ', '.join([self.WORD_COL_NAME_PREFIX + str(n) for n in range(1, column_count + 1)])\n        \n    def _make_column_names_and_placeholders(self, column_count):\n        return ' AND '.join(['%s%s=?' % (self.WORD_COL_NAME_PREFIX, n) for n in range(1, column_count + 1)])\n\n    def create_word_table_sql(self, column_count):\n        return 'CREATE TABLE IF NOT EXISTS %s (%s, %s)' % (self.WORD_TABLE_NAME, self._make_column_name_list(column_count), self.COUNT_COL_NAME)\n    \n    def create_param_table_sql(self):\n        return 'CREATE TABLE IF NOT EXISTS %s (%s, %s)' % (self.PARAM_TABLE_NAME, self.KEY_COL_NAME, self.VAL_COL_NAME)\n    \n    def set_param_sql(self):\n        return 'INSERT INTO %s (%s, %s) VALUES (?, ?)' % (self.PARAM_TABLE_NAME, self.KEY_COL_NAME, self.VAL_COL_NAME)\n    \n    def get_param_sql(self):\n        return 'SELECT %s FROM %s WHERE %s=?' % (self.VAL_COL_NAME, self.PARAM_TABLE_NAME, self.KEY_COL_NAME)\n\n    def create_index_sql(self, column_count):\n        return 'CREATE INDEX IF NOT EXISTS %s ON %s (%s)' % (self.INDEX_NAME, self.WORD_TABLE_NAME, self._make_column_name_list(column_count))\n    \n    def select_count_for_words_sql(self, column_count):\n        return 'SELECT %s FROM %s WHERE %s' % (self.COUNT_COL_NAME, self.WORD_TABLE_NAME, self._make_column_names_and_placeholders(column_count)) \n    \n    def update_count_for_words_sql(self, column_count):\n        return 'UPDATE %s SET %s=? WHERE %s' % (self.WORD_TABLE_NAME, self.COUNT_COL_NAME, self._make_column_names_and_placeholders(column_count)) \n    \n    def insert_row_for_words_sql(self, column_count):\n        columns = self._make_column_name_list(column_count) + ', ' + self.COUNT_COL_NAME\n        values  = ', '.join(['?'] * (column_count + 1))\n        \n        return 'INSERT INTO %s (%s) VALUES (%s)' % (self.WORD_TABLE_NAME, columns, values) \n    \n    def select_words_and_counts_sql(self, column_count):\n        last_word_col_name = self.WORD_COL_NAME_PREFIX + str(column_count)\n        \n        return 'SELECT %s, %s FROM %s WHERE %s' % (last_word_col_name, self.COUNT_COL_NAME, self.WORD_TABLE_NAME, self._make_column_names_and_placeholders(column_count - 1))\n    \n    def delete_words_sql(self):\n        return 'DELETE FROM ' + self.WORD_TABLE_NAME\n        "
  },
  {
    "path": "test/db_test.py",
    "content": "import unittest\nfrom db import Db\n\nclass DbTest(unittest.TestCase):\n    def setUp(self):\n        self.conn = StubConn()\n        self.sql = StubSql()\n    \n    def test_correct_sql_run_when_setup_called(self):\n        Db(self.conn, self.sql).setup(3)\n        execute_args = self.conn.stub_cursor.execute_args\n        self.assertEqual(len(execute_args), 4)\n        self.assertEqual(execute_args[0], ('create_word_table_sql 3',))\n        self.assertEqual(execute_args[1], ('create_index_sql 3',))\n        self.assertEqual(execute_args[2], ('create_param_table_sql',))\n        self.assertEqual(execute_args[3], ('set_param_sql', ('depth', 3)))\n        \n    def test_error_when_add_word_count_wrong(self):\n        db = Db(self.conn, self.sql)\n        db.setup(3)\n        self.assertRaises(ValueError, db.add_word, ['one','two'])\n        \n    def test_insert_row_when_add_new_word_list(self):\n        db = Db(self.conn, self.sql)\n        db.setup(3)\n        word_list = ['one', 'two', 'three']\n        db.add_word(word_list)\n        \n        execute_args = self.conn.stub_cursor.execute_args\n        self.assertEqual(len(execute_args), 6)\n        self.assertEqual(execute_args[4], ('select_count_for_words_sql 3', word_list))\n        self.assertEqual(execute_args[5], ('insert_row_for_words_sql 3', word_list + [1]))\n        \n    def test_update_row_when_add_repeated_word_list(self):\n        db = Db(self.conn, self.sql)\n        db.setup(3)\n        row_count = 10\n        word_list = ['one', 'two', 'three']\n        self.conn.stub_cursor.fetchone_results.append([row_count])\n\n        db.add_word(word_list)\n        \n        execute_args = self.conn.stub_cursor.execute_args\n        self.assertEqual(len(execute_args), 6)\n        self.assertEqual(execute_args[4], ('select_count_for_words_sql 3', word_list))\n        self.assertEqual(execute_args[5], ('update_count_for_words_sql 3', [row_count + 1] + word_list))\n\n    def test_db_commit_performed_correctly(self):\n        db = Db(self.conn, self.sql)\n        db.setup(3)\n        self.assertEqual(self.conn.commit_count, 0)\n        db.commit()\n        self.assertEqual(self.conn.commit_count, 1)\n        \n    def test_get_word_counts_works_correctly(self):\n        db = Db(self.conn, self.sql)\n        db.setup(3)\n        word_list = ['i', 'like']\n        self.conn.stub_cursor.execute_results = [[['dogs',  1], ['cats',  2], ['frogs', 3]]]\n        \n        word_counts = db.get_word_count(word_list)\n        \n        self.assertEqual(word_counts, {'dogs' : 1, 'cats' : 2, 'frogs' : 3})\n        execute_args = self.conn.stub_cursor.execute_args\n        self.assertEqual(len(execute_args), 5)\n        self.assertEqual(execute_args[4], ('select_words_and_counts_sql 3', word_list))\n\nclass StubCursor:\n    def __init__(self):\n        self.execute_results = []\n        self.execute_args = []\n        self.fetchone_results = []\n        self.fetchone_count = 0\n        \n    def fetchone(self):\n        self.fetchone_count += 1\n        \n        if len(self.fetchone_results):\n            return self.fetchone_results.pop(0)\n        \n        return None\n    \n    def execute(self, *args):\n        self.execute_args.append(args)\n        \n        if len(self.execute_results):\n            return self.execute_results.pop(0)\n        \n        return None\n    \n    def get_execute_count(self):\n        return self.execute_count\n    \nclass StubConn:\n    def __init__(self):\n        self.commit_count = 0\n        self.stub_cursor = StubCursor()\n        \n    def commit(self):\n        self.commit_count += 1\n        \n    def cursor(self):\n        return self.stub_cursor\n\nclass StubSql:\n    def create_word_table_sql(self, column_count):\n        return 'create_word_table_sql' + ' ' + str(column_count)\n    \n    def create_index_sql(self, column_count):\n        return 'create_index_sql' + ' ' + str(column_count)\n    \n    def create_param_table_sql(self):\n        return 'create_param_table_sql'\n    \n    def set_param_sql(self):\n        return 'set_param_sql'\n    \n    def get_param_sql(self):\n        return 'get_param_sql'\n    \n    def select_count_for_words_sql(self, column_count):\n        return 'select_count_for_words_sql' + ' ' + str(column_count)\n    \n    def update_count_for_words_sql(self, column_count):\n        return 'update_count_for_words_sql'  + ' ' + str(column_count)\n    \n    def insert_row_for_words_sql(self, column_count):\n        return 'insert_row_for_words_sql' + ' ' + str(column_count)\n    \n    def select_words_and_counts_sql(self, column_count):\n        return 'select_words_and_counts_sql' + ' ' + str(column_count)\n    \n    def delete_words_sql(self):\n        return 'delete_words_sql'            \n    \nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "test/gen_test.py",
    "content": "import unittest\nfrom collections import OrderedDict\nfrom gen import Generator\n\nclass GenTest(unittest.TestCase):\n    def setUp(self):\n        self.db = StubDb()\n        self.rnd = StubRnd()\n        \n    def test_generated_sequence_is_correct(self):\n        self.db.count_values = [\n            OrderedDict([('the', 2), ('a', 1)]), \n            OrderedDict([('mat', 1), ('cat', 1)]), \n            OrderedDict([('sat', 2)]), \n            OrderedDict([('on', 1), ('under' , 4)]), \n            OrderedDict([('my', 2), ('the', 2)]), \n            OrderedDict([('mat', 1), ('cat', 1)]), \n            OrderedDict([('$', 1)])]\n        \n        self.rnd.vals = [1, 2, 2, 1, 4, 1, 1]\n        \n        self.assertEqual(Generator('name', self.db, self.rnd).generate(' '), 'the cat sat on the mat')\n        self.assertEqual(self.db.get_word_count_args, [['^'], ['the'], ['cat'], ['sat'], ['on'], ['the'], ['mat']])\n        self.assertEqual(self.rnd.maxints, [3, 2, 2, 5, 4, 2, 1])\n    \nclass StubDb:\n    def __init__(self):\n        self.count_values = []\n        self.get_word_count_args = []\n        self.depth = 2\n        \n    def get_depth(self):\n        return self.depth\n    \n    def get_word_count(self, word_list):   \n        self.get_word_count_args.append(word_list)     \n        return self.count_values.pop(0)\n        \nclass StubRnd:\n    def __init__(self):\n        self.vals = []\n        self.maxints = []\n        \n    def randint(self, maxint):\n        self.maxints.append(maxint)\n        return self.vals.pop(0)\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "test/parse_test.py",
    "content": "import unittest\nfrom parse import Parser\n\nclass ParserTest(unittest.TestCase):\n    def setUp(self):\n        self.db = StubDb()\n        \n    def test_db_updated_correctly_from_input_with_depth_2_and_extra_whitespace(self):\n        Parser('name', self.db, '\\n', ' ').parse(' the   cat  sat  on the  mat \\n good    cat ')\n        self.assertEqual(self.db.commit_count, 1)\n        self.assertEqual(self.db.added_word_list, [['^', 'the'], ['the', 'cat'], ['cat', 'sat'], ['sat', 'on'], ['on', 'the'], ['the', 'mat'], ['mat', '$'], ['^', 'good'], ['good', 'cat'], ['cat', '$']])\n        \n    def test_db_updated_correctly_from_input_with_depth_4(self):\n        self.db.depth = 4\n        Parser('name', self.db, '\\n', ' ').parse('the cat sat on the mat')\n        self.assertEqual(self.db.commit_count, 1)\n        self.assertEqual(self.db.added_word_list, [['^', '^', '^', 'the'], ['^', '^', 'the', 'cat'], ['^', 'the', 'cat', 'sat'], ['the', 'cat', 'sat', 'on'], ['cat', 'sat', 'on', 'the'], ['sat', 'on', 'the', 'mat'], ['on', 'the', 'mat', '$'], ['the', 'mat', '$', '$'], ['mat', '$', '$', '$']])\n\nclass StubDb:\n    def __init__(self):\n        self.commit_count = 0\n        self.added_word_list = []\n        self.depth = 2\n        \n    def get_depth(self):\n        return self.depth\n        \n    def add_word(self, word_list):\n        self.added_word_list.append(word_list)\n\n    def commit(self):\n        self.commit_count += 1\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "test/sql_test.py",
    "content": "import unittest\nfrom sql import Sql\n\nclass SqlTest(unittest.TestCase):\n    def test_create_word_table_sql_correct(self):\n        self.assertEqual(Sql().create_word_table_sql(3), 'CREATE TABLE IF NOT EXISTS word (word1, word2, word3, count)')\n    \n    def test_create_param_table_sql_correct(self):\n        self.assertEqual(Sql().create_param_table_sql(), 'CREATE TABLE IF NOT EXISTS param (name, value)')\n    \n    def test_set_param_sql_correct(self):\n        self.assertEqual(Sql().set_param_sql(), 'INSERT INTO param (name, value) VALUES (?, ?)')\n    \n    def test_create_index_sql_correct(self):\n        self.assertEqual(Sql().create_index_sql(3), 'CREATE INDEX IF NOT EXISTS i_word ON word (word1, word2, word3)')\n    \n    def test_select_count_for_words_sql_correct(self):\n        self.assertEqual(Sql().select_count_for_words_sql(3), 'SELECT count FROM word WHERE word1=? AND word2=? AND word3=?')\n     \n    def test_update_count_for_words_sql_correct(self):\n        self.assertEqual(Sql().update_count_for_words_sql(3), 'UPDATE word SET count=? WHERE word1=? AND word2=? AND word3=?')\n\n    def test_insert_row_for_words_sql_correct(self):\n        self.assertEqual(Sql().insert_row_for_words_sql(3), 'INSERT INTO word (word1, word2, word3, count) VALUES (?, ?, ?, ?)')\n\n    def test_select_words_and_counts_sql_correct(self):\n        self.assertEqual(Sql().select_words_and_counts_sql(3), 'SELECT word3, count FROM word WHERE word1=? AND word2=?')\n\n    def test_delete_words_sql_correct(self):\n        self.assertEqual(Sql().delete_words_sql(), 'DELETE FROM word')\n\nif __name__ == '__main__':\n    unittest.main()"
  },
  {
    "path": "test/suite.py",
    "content": "import unittest\nfrom db_test import DbTest\nfrom gen_test import GenTest\nfrom parse_test import ParserTest\nfrom sql_test import SqlTest\n\ndef suite():\n    test_suite = unittest.TestSuite()\n    test_suite.addTest(unittest.makeSuite(DbTest))\n    test_suite.addTest(unittest.makeSuite(GenTest))\n    test_suite.addTest(unittest.makeSuite(ParserTest))\n    test_suite.addTest(unittest.makeSuite(SqlTest))\n    return test_suite\n\nif __name__ == \"__main__\":\n    #So you can run tests from this module individually.\n    unittest.main() "
  }
]