def getReport(self, req, rid): """ Get report detail and matching tickets """ rid = int(rid) rm = ReportModule(self.env) r = Report(self.env, rid) title, description, sql = r.title, r.description, r.query cols, rows, do_, not_, care = rm.execute_paginated_report( req, rid, sql, {}, 0, 0) tickets = [] if 'ticket' in cols: for i in rows: tickets.append(i[cols.index('ticket')]) return { "report": { "id": r.id, "title": r.title, "description": r.description }, "tickets": tickets }
class ReportModuleTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.report_module = ReportModule(self.env) def tearDown(self): self.env.reset_db() def _insert_report(self, title, query, description): with self.env.db_transaction as db: cursor = db.cursor() cursor.execute( """ INSERT INTO report (title,query,description) VALUES (%s,%s,%s) """, (title, query, description)) return db.get_last_id(cursor, 'report') def test_create_report(self): req = MockRequest(self.env, method='POST', args={ 'action': 'new', 'title': "New Report", 'query': "SELECT 1", 'description': "The description" }) self.assertRaises(RequestDone, self.report_module.process_request, req) self.assertTrue(Report(self.env, 9).exists) self.assertIn("The report has been created.", req.chrome['notices']) self.assertEqual('http://example.org/trac.cgi/report/9', req.headers_sent['Location']) def test_create_report_cancel(self): req = MockRequest(self.env, method='POST', args={ 'action': 'new', 'cancel': True, 'title': "New Report", 'query': "SELECT 1", 'description': "The description" }) self.assertRaises(RequestDone, self.report_module.process_request, req) self.assertRaises(ResourceNotFound, Report, self.env, 9) self.assertNotIn("The report has been created.", req.chrome['notices']) self.assertEqual('http://example.org/trac.cgi/report', req.headers_sent['Location']) def test_delete_report(self): req = MockRequest(self.env, method='POST', args={ 'action': 'delete', 'id': '1' }) self.assertRaises(RequestDone, self.report_module.process_request, req) self.assertRaises(ResourceNotFound, Report, self.env, 1) self.assertIn("The report {1} has been deleted.", req.chrome['notices']) self.assertEqual('http://example.org/trac.cgi/report', req.headers_sent['Location']) def test_delete_report_cancel(self): req = MockRequest(self.env, method='POST', args={ 'action': 'delete', 'cancel': True, 'id': '1' }) self.assertRaises(RequestDone, self.report_module.process_request, req) self.assertTrue(Report(self.env, 1).exists) self.assertNotIn("The report {1} has been deleted.", req.chrome['notices']) self.assertEqual('http://example.org/trac.cgi/report/1', req.headers_sent['Location']) def test_update_report(self): report = Report(self.env) report.query = "SELECT 1" report.insert() req = MockRequest(self.env, method='POST', args={ 'action': 'edit', 'id': '1', 'title': "New Report edited", 'query': "SELECT 2", 'description': "The description edited" }) self.assertRaises(RequestDone, self.report_module.process_request, req) report = Report(self.env, 1) self.assertEqual("New Report edited", report.title) self.assertEqual("SELECT 2", report.query) self.assertEqual("The description edited", report.description) self.assertIn("Your changes have been saved.", req.chrome['notices']) def test_update_report_cancel(self): report = Report(self.env) report.query = "SELECT 1" report.insert() req = MockRequest(self.env, method='POST', args={ 'action': 'edit', 'cancel': True, 'id': '1', 'title': "New Report edited", 'query': "SELECT 2", 'description': "The description edited" }) self.assertRaises(RequestDone, self.report_module.process_request, req) report = Report(self.env, 1) self.assertEqual("Active Tickets", report.title) self.assertEqual( " * List all active tickets by priority.\n" " * Color each row based on priority.\n", report.description) self.assertIn("SELECT p.value AS __color__", report.query) self.assertNotIn("Your changes have been saved.", req.chrome['notices']) def test_render_confirm_delete(self): req = MockRequest(self.env, method='GET', args={ 'action': 'delete', 'id': '1' }) data = self.report_module.process_request(req)[1] self.assertEqual("Delete Report {1} Active Tickets", data['title']) self.assertEqual('delete', data['action']) self.assertEqual(1, data['report']['id']) self.assertEqual('Active Tickets', data['report']['title']) def test_render_editor(self): req = MockRequest(self.env, method='GET', args={ 'action': 'edit', 'id': '1' }) data = self.report_module.process_request(req)[1] self.assertEqual(1, data['report']['id']) self.assertEqual("Active Tickets", data['report']['title']) self.assertEqual( " * List all active tickets by priority.\n" " * Color each row based on priority.\n", data['report']['description']) self.assertIn("SELECT p.value AS __color__", data['report']['sql']) def test_render_list(self): req = MockRequest(self.env, method='GET', args={ 'action': 'view', 'id': '-1' }) data = self.report_module.process_request(req)[1] self.assertEqual('report', data['sort']) self.assertEqual(1, data['asc']) self.assertEqual(8, len(data['reports'])) self.assertEqual(1, data['reports'][0][0]) self.assertEqual('Active Tickets', data['reports'][0][1]) self.assertEqual( " * List all active tickets by priority.\n" " * Color each row based on priority.\n", data['reports'][0][2]) self.assertTrue('Active Reports', data['reports'][0][3]) self.assertTrue('Active Reports', data['reports'][0][4]) def test_render_view(self): req = MockRequest(self.env, method='GET', args={ 'action': 'view', 'id': '1' }) data = self.report_module.process_request(req)[1] self.assertEqual(1, data['report']['id']) self.assertEqual("{1} Active Tickets", data['title']) self.assertEqual( " * List all active tickets by priority.\n" " * Color each row based on priority.\n", data['description']) def test_render_empty_report(self): """Empty report raises a TracError.""" rid = self._insert_report('Empty report', '', '') req = MockRequest(self.env, method='GET', args={ 'action': 'view', 'id': rid }) data = self.report_module.process_request(req)[1] self.assertEqual("Report failed: Report {%d} has no SQL query." % rid, data['message']) def test_render_view_sort_order_preserved_on_update(self): """Sort column and order are preserved on update.""" req = MockRequest(self.env, method='GET', args={ 'action': 'view', 'id': 1, 'sort': 'summary', 'asc': '1' }) data = self.report_module.process_request(req)[1] self.assertEqual(1, data['asc']) self.assertEqual('summary', data['sort']) def test_sub_var_no_quotes(self): sql, values, missing_args = self.report_module.sql_sub_vars( u"$VAR", {'VAR': 'value'}) self.assertEqual("%s", sql) self.assertEqual(['value'], values) self.assertEqual([], missing_args) def test_sub_var_digits_underscore(self): sql, values, missing_args = self.report_module.sql_sub_vars( u"$_VAR, $VAR2, $2VAR", { '_VAR': 'value1', 'VAR2': 'value2' }) self.assertEqual("%s, %s, $2VAR", sql) self.assertEqual(['value1', 'value2'], values) self.assertEqual([], missing_args) def test_sub_var_quotes(self): sql, values, missing_args = self.report_module.sql_sub_vars( u"'$VAR'", {'VAR': 'value'}) with self.env.db_query as db: concatenated = db.concat("''", '%s', "''") self.assertEqual(concatenated, sql) self.assertEqual(['value'], values) self.assertEqual([], missing_args) def test_sub_var_missing_args(self): sql, values, missing_args = self.report_module.sql_sub_vars( u"$VAR, $PARAM, $MISSING", {'VAR': 'value'}) self.assertEqual("%s, %s, %s", sql) self.assertEqual(['value', '', ''], values) self.assertEqual(['PARAM', 'MISSING'], missing_args) def test_csv_escape(self): req = MockRequest(self.env) cols = ['TEST_COL', 'TEST_ZERO'] rows = [('value, needs escaped', 0)] self.assertRaises(RequestDone, self.report_module._send_csv, req, cols, rows) self.assertEqual( '\xef\xbb\xbfTEST_COL,TEST_ZERO\r\n"' 'value, needs escaped",0\r\n', req.response_sent.getvalue()) def test_saved_custom_query_redirect(self): query = u'query:?type=résumé' rid = self._insert_report('redirect', query, '') req = MockRequest(self.env) self.assertRaises(RequestDone, self.report_module._render_view, req, rid) self.assertEqual( 'http://example.org/trac.cgi/query?' + 'type=r%C3%A9sum%C3%A9&report=' + str(rid), req.headers_sent['Location']) def test_quoted_id_with_var(self): req = MockRequest(self.env) name = """%s"`'%%%?""" with self.env.db_query as db: sql = u'SELECT 1 AS %s, $USER AS user' % db.quote(name) rv = self.report_module.execute_paginated_report( req, 1, sql, {'USER': '******'}) self.assertEqual(5, len(rv), repr(rv)) cols, results, num_items, missing_args, limit_offset = rv self.assertEqual([name, 'user'], cols) self.assertEqual([(1, 'joe')], results) self.assertEqual([], missing_args) self.assertIsNone(limit_offset) def test_value_error_from_get_var_args(self): req = MockRequest(self.env, path_info='/report/1') def get_var_args(req): raise ValueError('<error>') self.report_module.get_var_args = get_var_args self.assertTrue(self.report_module.match_request(req)) data = self.report_module.process_request(req)[1] self.assertEqual('Report failed: <error>', data['message']) def test_title_and_description_with_sub_vars(self): with self.env.db_transaction: id_ = self._insert_report( 'Tickets on $M for $USER', 'SELECT * FROM ticket WHERE milestone=$M AND owner=$USER', 'Show tickets on $M for $USER') for milestone in ('milestone1', 'milestone2'): insert_ticket(self.env, status='new', summary='Test 1', owner='joe', milestone=milestone) req = MockRequest(self.env, path_info='/report/%d' % id_, authname='joe', args={'M': 'milestone2'}) self.assertTrue(self.report_module.match_request(req)) data = self.report_module.process_request(req)[1] self.assertEqual('{%d} Tickets on milestone2 for joe' % id_, data['title']) self.assertEqual('Show tickets on milestone2 for joe', data['description']) self.assertIsNone(data['message']) self.assertEqual(1, data['numrows']) def test_title_and_description_with_sub_vars_in_sql(self): with self.env.db_transaction: id_ = self._insert_report( 'Tickets on $M for $USER', '-- M=milestone1\r\n' 'SELECT * FROM ticket WHERE milestone=$M AND owner=$USER\r\n', 'Show tickets on $M for $USER') for milestone in ('milestone1', 'milestone2'): insert_ticket(self.env, status='new', summary='Test 1', owner='joe', milestone=milestone) req = MockRequest(self.env, path_info='/report/%d' % id_, authname='joe') self.assertTrue(self.report_module.match_request(req)) data = self.report_module.process_request(req)[1] self.assertEqual('{%d} Tickets on milestone1 for joe' % id_, data['title']) self.assertEqual('Show tickets on milestone1 for joe', data['description']) self.assertIsNone(data['message']) self.assertEqual(1, data['numrows']) def test_clear(self): req = MockRequest(self.env, method='GET', path_info='/report', args={'action': 'clear'}) req.session['query_href'] = req.href.query() req.session['query_tickets'] = '42' self.assertTrue(self.report_module.match_request(req)) self.assertEqual('report_list.html', self.report_module.process_request(req)[0]) self.assertIn('query_href', req.session) self.assertIn('query_tickets', req.session) req = MockRequest(self.env, method='POST', path_info='/report', args={'action': 'clear'}) self.assertTrue(self.report_module.match_request(req)) self.assertRaises(RequestDone, self.report_module.process_request, req) self.assertNotIn('query_href', req.session) self.assertNotIn('query_tickets', req.session) def test_valid_html_for_report(self): req = MockRequest( self.env, method='POST', path_info='/report', args={ 'action': 'new', 'title': '#13046', 'query': "SELECT '#13046' AS foo_, 42 AS bar, 'blah' AS _baz_", 'description': '' }) self.assertTrue(self.report_module.match_request(req)) self.assertRaises(RequestDone, self.report_module.process_request, req) req = MockRequest(self.env, method='GET', path_info='/report/9') self.assertTrue(self.report_module.match_request(req)) rv = self.report_module.process_request(req) rendered = Chrome(self.env).render_template(req, rv[0], rv[1], { 'fragment': False, 'iterable': False }) self.assertRegexpMatches( rendered, r'<tr[^>]*>\s*' r'<td class="fullrow foo" colspan="100">' r'\s*#13046\s*<hr />\s*</td>\s*</tr>') self.assertRegexpMatches( rendered, r'<tr[^>]*>\s*' r'<td class="fullrow bar" colspan="100">' r'\s*42\s*<hr />\s*</td>\s*</tr>') self.assertRegexpMatches( rendered, r'<tr[^>]*>\s*' r'<td class="fullrow baz" colspan="100">' r'\s*blah\s*<hr />\s*</td>\s*</tr>') if genshi: XML(rendered) # validates as XML def test_timestamp_columns(self): req = MockRequest( self.env, method='POST', path_info='/report', args={ 'action': 'new', 'title': '#13134', 'query': "SELECT %d AS time, %d AS created, %d AS datetime" % ((1 * 86400 + 42) * 1000000, (2 * 86400 + 43) * 1000000, (3 * 86400 + 44) * 1000000), 'description': '' }) self.assertTrue(self.report_module.match_request(req)) self.assertRaises(RequestDone, self.report_module.process_request, req) req = MockRequest(self.env, method='GET', path_info='/report/9') self.assertTrue(self.report_module.match_request(req)) rv = self.report_module.process_request(req) rendered = Chrome(self.env).render_template(req, rv[0], rv[1], { 'fragment': False, 'iterable': False }) self.assertRegexpMatches( rendered, r'<td class="date">\s*(12:00:42 AM|00:00:42)\s*</td>') self.assertRegexpMatches( rendered, r'<td class="date">\s*(Jan 3, 1970|01/03/70)\s*</td>') self.assertRegexpMatches( rendered, r'<td class="date">\s*(Jan 4, 1970, 12:00:44 AM|' r'01/04/70 00:00:44)\s*</td>')
class ReportTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.report_module = ReportModule(self.env) def tearDown(self): self.env.reset_db() def _make_environ(self, scheme='http', server_name='example.org', server_port=80, method='GET', script_name='/trac', **kwargs): environ = { 'wsgi.url_scheme': scheme, 'wsgi.input': StringIO(''), 'REQUEST_METHOD': method, 'SERVER_NAME': server_name, 'SERVER_PORT': server_port, 'SCRIPT_NAME': script_name } environ.update(kwargs) return environ def test_sub_var_no_quotes(self): sql, values, missing_args = self.report_module.sql_sub_vars( "$VAR", {'VAR': 'value'}) self.assertEqual("%s", sql) self.assertEqual(['value'], values) self.assertEqual([], missing_args) def test_sub_var_digits_underscore(self): sql, values, missing_args = self.report_module.sql_sub_vars( "$_VAR, $VAR2, $2VAR", { '_VAR': 'value1', 'VAR2': 'value2' }) self.assertEqual("%s, %s, $2VAR", sql) self.assertEqual(['value1', 'value2'], values) self.assertEqual([], missing_args) def test_sub_var_quotes(self): sql, values, missing_args = self.report_module.sql_sub_vars( "'$VAR'", {'VAR': 'value'}) with self.env.db_query as db: concatenated = db.concat("''", '%s', "''") self.assertEqual(concatenated, sql) self.assertEqual(['value'], values) self.assertEqual([], missing_args) def test_sub_var_missing_args(self): sql, values, missing_args = self.report_module.sql_sub_vars( "$VAR, $PARAM, $MISSING", {'VAR': 'value'}) self.assertEqual("%s, %s, %s", sql) self.assertEqual(['value', '', ''], values) self.assertEqual(['PARAM', 'MISSING'], missing_args) def test_csv_escape(self): buf = StringIO() def start_response(status, headers): return buf.write environ = self._make_environ() req = Request(environ, start_response) cols = ['TEST_COL', 'TEST_ZERO'] rows = [('value, needs escaped', 0)] try: self.report_module._send_csv(req, cols, rows) except RequestDone: pass self.assertEqual( '\xef\xbb\xbfTEST_COL,TEST_ZERO\r\n"value, needs escaped",0\r\n', buf.getvalue()) def test_saved_custom_query_redirect(self): query = u'query:?type=résumé' with self.env.db_transaction as db: cursor = db.cursor() cursor.execute( "INSERT INTO report (title,query,description) " "VALUES (%s,%s,%s)", ('redirect', query, '')) id = db.get_last_id(cursor, 'report') headers_sent = {} def start_response(status, headers): headers_sent.update(dict(headers)) environ = self._make_environ() req = Request(environ, start_response) req.authname = 'anonymous' req.session = Mock(save=lambda: None) self.assertRaises(RequestDone, self.report_module._render_view, req, id) self.assertEqual('http://example.org/trac/query?' + \ 'type=r%C3%A9sum%C3%A9&report=' + str(id), headers_sent['Location']) def test_quoted_id_with_var(self): req = Mock(base_path='', chrome={}, args={}, session={}, abs_href=Href('/'), href=Href('/'), locale='', perm=MockPerm(), authname=None, tz=None) name = """%s"`'%%%?""" with self.env.db_query as db: sql = 'SELECT 1 AS %s, $USER AS user' % db.quote(name) rv = self.report_module.execute_paginated_report( req, 1, sql, {'USER': '******'}) self.assertEqual(5, len(rv), repr(rv)) cols, results, num_items, missing_args, limit_offset = rv self.assertEqual([name, 'user'], cols) self.assertEqual([(1, 'joe')], results) self.assertEqual([], missing_args) self.assertEqual(None, limit_offset)
class ReportModuleTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True) self.report_module = ReportModule(self.env) def tearDown(self): self.env.reset_db() def test_create_report(self): req = MockRequest(self.env, method='POST', args={ 'action': 'new', 'title': "New Report", 'query': "SELECT 1", 'description': "The description" }) self.assertRaises(RequestDone, self.report_module.process_request, req) self.assertTrue(Report(self.env, 9).exists) self.assertIn("The report has been created.", req.chrome['notices']) self.assertEqual('http://example.org/trac.cgi/report/9', req.headers_sent['Location']) def test_create_report_cancel(self): req = MockRequest(self.env, method='POST', args={ 'action': 'new', 'cancel': True, 'title': "New Report", 'query': "SELECT 1", 'description': "The description" }) self.assertRaises(RequestDone, self.report_module.process_request, req) self.assertRaises(ResourceNotFound, Report, self.env, 9) self.assertNotIn("The report has been created.", req.chrome['notices']) self.assertEqual('http://example.org/trac.cgi/report', req.headers_sent['Location']) def test_delete_report(self): req = MockRequest(self.env, method='POST', args={ 'action': 'delete', 'id': '1' }) self.assertRaises(RequestDone, self.report_module.process_request, req) self.assertRaises(ResourceNotFound, Report, self.env, 1) self.assertIn("The report {1} has been deleted.", req.chrome['notices']) self.assertEqual('http://example.org/trac.cgi/report', req.headers_sent['Location']) def test_delete_report_cancel(self): req = MockRequest(self.env, method='POST', args={ 'action': 'delete', 'cancel': True, 'id': '1' }) self.assertRaises(RequestDone, self.report_module.process_request, req) self.assertTrue(Report(self.env, 1).exists) self.assertNotIn("The report {1} has been deleted.", req.chrome['notices']) self.assertEqual('http://example.org/trac.cgi/report/1', req.headers_sent['Location']) def test_update_report(self): Report(self.env).insert() req = MockRequest(self.env, method='POST', args={ 'action': 'edit', 'id': '1', 'title': "New Report edited", 'query': "SELECT 2", 'description': "The description edited" }) self.assertRaises(RequestDone, self.report_module.process_request, req) report = Report(self.env, 1) self.assertEqual("New Report edited", report.title) self.assertEqual("SELECT 2", report.query) self.assertEqual("The description edited", report.description) self.assertIn("Your changes have been saved.", req.chrome['notices']) def test_update_report_cancel(self): Report(self.env).insert() req = MockRequest(self.env, method='POST', args={ 'action': 'edit', 'cancel': True, 'id': '1', 'title': "New Report edited", 'query': "SELECT 2", 'description': "The description edited" }) self.assertRaises(RequestDone, self.report_module.process_request, req) report = Report(self.env, 1) self.assertEqual("Active Tickets", report.title) self.assertEqual( " * List all active tickets by priority.\n" " * Color each row based on priority.\n", report.description) self.assertIn("SELECT p.value AS __color__", report.query) self.assertNotIn("Your changes have been saved.", req.chrome['notices']) def test_render_confirm_delete(self): req = MockRequest(self.env, method='GET', args={ 'action': 'delete', 'id': '1' }) data = self.report_module.process_request(req)[1] self.assertEqual("Delete Report {1} Active Tickets", data['title']) self.assertEqual('delete', data['action']) self.assertEqual(1, data['report']['id']) self.assertEqual('Active Tickets', data['report']['title']) def test_render_editor(self): req = MockRequest(self.env, method='GET', args={ 'action': 'edit', 'id': '1' }) data = self.report_module.process_request(req)[1] self.assertEqual(1, data['report']['id']) self.assertEqual("Active Tickets", data['report']['title']) self.assertEqual( " * List all active tickets by priority.\n" " * Color each row based on priority.\n", data['report']['description']) self.assertIn("SELECT p.value AS __color__", data['report']['sql']) def test_render_list(self): req = MockRequest(self.env, method='GET', args={ 'action': 'view', 'id': '-1' }) data = self.report_module.process_request(req)[1] self.assertEqual('report', data['sort']) self.assertEqual(1, data['asc']) self.assertEqual(8, len(data['reports'])) self.assertEqual(1, data['reports'][0][0]) self.assertEqual('Active Tickets', data['reports'][0][1]) self.assertEqual( " * List all active tickets by priority.\n" " * Color each row based on priority.\n", data['reports'][0][2]) self.assertTrue('Active Reports', data['reports'][0][3]) self.assertTrue('Active Reports', data['reports'][0][4]) def test_render_view(self): req = MockRequest(self.env, method='GET', args={ 'action': 'view', 'id': '1' }) data = self.report_module.process_request(req)[1] self.assertEqual(1, data['report']['id']) self.assertEqual("{1} Active Tickets", data['title']) self.assertEqual( " * List all active tickets by priority.\n" " * Color each row based on priority.\n", data['description']) def test_sub_var_no_quotes(self): sql, values, missing_args = self.report_module.sql_sub_vars( u"$VAR", {'VAR': 'value'}) self.assertEqual("%s", sql) self.assertEqual(['value'], values) self.assertEqual([], missing_args) def test_sub_var_digits_underscore(self): sql, values, missing_args = self.report_module.sql_sub_vars( u"$_VAR, $VAR2, $2VAR", { '_VAR': 'value1', 'VAR2': 'value2' }) self.assertEqual("%s, %s, $2VAR", sql) self.assertEqual(['value1', 'value2'], values) self.assertEqual([], missing_args) def test_sub_var_quotes(self): sql, values, missing_args = self.report_module.sql_sub_vars( u"'$VAR'", {'VAR': 'value'}) with self.env.db_query as db: concatenated = db.concat("''", '%s', "''") self.assertEqual(concatenated, sql) self.assertEqual(['value'], values) self.assertEqual([], missing_args) def test_sub_var_missing_args(self): sql, values, missing_args = self.report_module.sql_sub_vars( u"$VAR, $PARAM, $MISSING", {'VAR': 'value'}) self.assertEqual("%s, %s, %s", sql) self.assertEqual(['value', '', ''], values) self.assertEqual(['PARAM', 'MISSING'], missing_args) def test_csv_escape(self): req = MockRequest(self.env) cols = ['TEST_COL', 'TEST_ZERO'] rows = [('value, needs escaped', 0)] self.assertRaises(RequestDone, self.report_module._send_csv, req, cols, rows) self.assertEqual( '\xef\xbb\xbfTEST_COL,TEST_ZERO\r\n"' 'value, needs escaped",0\r\n', req.response_sent.getvalue()) def test_saved_custom_query_redirect(self): query = u'query:?type=résumé' with self.env.db_transaction as db: cursor = db.cursor() cursor.execute( "INSERT INTO report (title,query,description) " "VALUES (%s,%s,%s)", ('redirect', query, '')) id = db.get_last_id(cursor, 'report') req = MockRequest(self.env) self.assertRaises(RequestDone, self.report_module._render_view, req, id) self.assertEqual( 'http://example.org/trac.cgi/query?' + 'type=r%C3%A9sum%C3%A9&report=' + str(id), req.headers_sent['Location']) def test_quoted_id_with_var(self): req = MockRequest(self.env) name = """%s"`'%%%?""" with self.env.db_query as db: sql = u'SELECT 1 AS %s, $USER AS user' % db.quote(name) rv = self.report_module.execute_paginated_report( req, 1, sql, {'USER': '******'}) self.assertEqual(5, len(rv), repr(rv)) cols, results, num_items, missing_args, limit_offset = rv self.assertEqual([name, 'user'], cols) self.assertEqual([(1, 'joe')], results) self.assertEqual([], missing_args) self.assertEqual(None, limit_offset)
class ReportTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub() self.report_module = ReportModule(self.env) def tearDown(self): self.env.reset_db() def _make_environ(self, scheme='http', server_name='example.org', server_port=80, method='GET', script_name='/trac', **kwargs): environ = {'wsgi.url_scheme': scheme, 'wsgi.input': StringIO(''), 'REQUEST_METHOD': method, 'SERVER_NAME': server_name, 'SERVER_PORT': server_port, 'SCRIPT_NAME': script_name} environ.update(kwargs) return environ def test_sub_var_no_quotes(self): sql, values, missing_args = self.report_module.sql_sub_vars( "$VAR", {'VAR': 'value'}) self.assertEqual("%s", sql) self.assertEqual(['value'], values) self.assertEqual([], missing_args) def test_sub_var_digits_underscore(self): sql, values, missing_args = self.report_module.sql_sub_vars( "$_VAR, $VAR2, $2VAR", {'_VAR': 'value1', 'VAR2': 'value2'}) self.assertEqual("%s, %s, $2VAR", sql) self.assertEqual(['value1', 'value2'], values) self.assertEqual([], missing_args) def test_sub_var_quotes(self): sql, values, missing_args = self.report_module.sql_sub_vars( "'$VAR'", {'VAR': 'value'}) with self.env.db_query as db: concatenated = db.concat("''", '%s', "''") self.assertEqual(concatenated, sql) self.assertEqual(['value'], values) self.assertEqual([], missing_args) def test_sub_var_missing_args(self): sql, values, missing_args = self.report_module.sql_sub_vars( "$VAR, $PARAM, $MISSING", {'VAR': 'value'}) self.assertEqual("%s, %s, %s", sql) self.assertEqual(['value', '', ''], values) self.assertEqual(['PARAM', 'MISSING'], missing_args) def test_csv_escape(self): buf = StringIO() def start_response(status, headers): return buf.write environ = self._make_environ() req = Request(environ, start_response) cols = ['TEST_COL', 'TEST_ZERO'] rows = [('value, needs escaped', 0)] try: self.report_module._send_csv(req, cols, rows) except RequestDone: pass self.assertEqual('\xef\xbb\xbfTEST_COL,TEST_ZERO\r\n"value, needs escaped",0\r\n', buf.getvalue()) def test_saved_custom_query_redirect(self): query = u'query:?type=résumé' with self.env.db_transaction as db: cursor = db.cursor() cursor.execute("INSERT INTO report (title,query,description) " "VALUES (%s,%s,%s)", ('redirect', query, '')) id = db.get_last_id(cursor, 'report') headers_sent = {} def start_response(status, headers): headers_sent.update(dict(headers)) environ = self._make_environ() req = Request(environ, start_response) req.authname = 'anonymous' req.session = Mock(save=lambda: None) self.assertRaises(RequestDone, self.report_module._render_view, req, id) self.assertEqual('http://example.org/trac/query?' + \ 'type=r%C3%A9sum%C3%A9&report=' + str(id), headers_sent['Location']) def test_quoted_id_with_var(self): req = Mock(base_path='', chrome={}, args={}, session={}, abs_href=Href('/'), href=Href('/'), locale='', perm=MockPerm(), authname=None, tz=None) name = """%s"`'%%%?""" with self.env.db_query as db: sql = 'SELECT 1 AS %s, $USER AS user' % db.quote(name) rv = self.report_module.execute_paginated_report(req, 1, sql, {'USER': '******'}) self.assertEqual(5, len(rv), repr(rv)) cols, results, num_items, missing_args, limit_offset = rv self.assertEqual([name, 'user'], cols) self.assertEqual([(1, 'joe')], results) self.assertEqual([], missing_args) self.assertEqual(None, limit_offset)