# coding: utf-8 # Created on: 13.09.2016 # Author: Roman Miroshnychenko aka Roman V.M. (romanvm@yandex.ua) # # Copyright (c) 2016 Roman Miroshnychenko # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from __future__ import unicode_literals import os import sys import time from unittest import TestCase, main from subprocess import Popen from selenium import webdriver from selenium.webdriver.common.keys import Keys cwd = os.path.dirname(os.path.abspath(__file__)) db_py = os.path.join(cwd, 'db.py') class SeleniumTestCase(TestCase): @classmethod def setUpClass(cls): if sys.platform == 'win32': cls.browser = webdriver.Firefox() else: options = webdriver.ChromeOptions() options.add_argument('headless') options.add_argument('disable-gpu') cls.browser = webdriver.Chrome(options=options) cls.browser.implicitly_wait(10) cls.browser.get('http://127.0.0.1:5555') cls.stdin = cls.browser.find_element_by_id('stdin') cls.send_btn = cls.browser.find_element_by_id('send_btn') cls.stdout_tag = cls.browser.find_element_by_id('stdout') @classmethod def tearDownClass(cls): cls.stdin.clear() cls.stdin.send_keys('q') cls.send_btn.click() time.sleep(1) cls.db_proc.kill() cls.browser.quit() class WebPdbTestCase(SeleniumTestCase): """ This class provides basic functionality testing for Web-PDB """ @classmethod def setUpClass(cls): cls.db_proc = Popen(['python', db_py], shell=False) super(WebPdbTestCase, cls).setUpClass() def test_1_set_trace(self): """ Test back-end/front-end interaction during debugging """ time.sleep(1) filename_tag = self.browser.find_element_by_id('filename') self.assertEqual(filename_tag.text, 'db.py') curr_line_tag = self.browser.find_element_by_id('curr_line') self.assertEqual(curr_line_tag.text, '14') curr_file_tag = self.browser.find_element_by_id('curr_file_code') self.assertIn('foo = \'foo\'', curr_file_tag.text) globals_tag = self.browser.find_element_by_id('globals') self.assertIn('foo = \'foo\'', globals_tag.text) self.assertIn('-> bar = \'bar\'', self.stdout_tag.text) # Test if Prismjs syntax coloring actually works self.assertIn('foo <span class="token operator">=</span> <span class="token string">\'foo\'</span>', self.browser.page_source) def test_2_next_command(self): """ Test sending PDB commands """ self.stdin.clear() self.stdin.send_keys('n') self.send_btn.click() time.sleep(1) curr_line_tag = self.browser.find_element_by_id('curr_line') self.assertEqual(curr_line_tag.text, '15') globals_tag = self.browser.find_element_by_id('globals') self.assertIn('bar = \'bar\'', globals_tag.text) self.assertIn('-> ham = \'spam\'', self.stdout_tag.text) self.assertEqual(self.stdin.get_attribute('value'), '') def test_3_history(self): """ Test for the recent commands history """ self.stdin.clear() self.stdin.send_keys('h') self.send_btn.click() time.sleep(1) self.stdin.send_keys(Keys.ARROW_UP) self.assertEqual(self.stdin.get_attribute('value'), 'h') self.stdin.send_keys(Keys.ARROW_UP) self.assertEqual(self.stdin.get_attribute('value'), 'n') def test_4_breakpints(self): """ Test for highlighting breakpoints """ self.stdin.clear() self.stdin.send_keys('b 20') self.send_btn.click() time.sleep(1) line_numbers_rows = self.browser.find_element_by_css_selector('span.line-numbers-rows') line_spans = line_numbers_rows.find_elements_by_tag_name('span') self.assertEqual(line_spans[19].get_attribute('class'), 'breakpoint') def test_5_unicode_literal(self): """ Test for displaying unicode literals """ self.stdin.clear() self.stdin.send_keys('n') self.send_btn.click() time.sleep(1) self.assertIn('-> name = u\'Монти\'', self.stdout_tag.text) def test_6_entering_unicode_string(self): """ Test for entering unicode literal via console """ self.stdin.clear() self.stdin.send_keys('p u\'python - питон\'') self.send_btn.click() time.sleep(1) stdout_tag = self.browser.find_element_by_id('stdout') self.assertIn('u\'python - питон\'', stdout_tag.text) def test_7_local_vars(self): """ Test for displaying local variables """ self.stdin.clear() self.stdin.send_keys('c') self.send_btn.click() time.sleep(1) locals_tag = self.browser.find_element_by_id('locals') self.assertIn('spam = \'spam\'', locals_tag.text) globals_tag = self.browser.find_element_by_id('globals') self.assertNotEqual(globals_tag.text, locals_tag.text) class PatchStdStreamsTestCase(SeleniumTestCase): """ This class tests patching sys.std* streams """ @classmethod def setUpClass(cls): cls.db_proc = Popen(['python', os.path.join(cwd, 'db_ps.py')], shell=False) super(PatchStdStreamsTestCase, cls).setUpClass() def test_patching_std_streams(self): """ Test if std streams are correctly redirected to the web-console """ time.sleep(1) self.stdin.send_keys('n') self.send_btn.click() time.sleep(1) self.assertIn('Enter something:', self.stdout_tag.text) self.stdin.send_keys('spam') self.send_btn.click() time.sleep(1) self.stdin.send_keys('n') self.send_btn.click() time.sleep(1) self.assertIn('You have entered: spam', self.stdout_tag.text) class CatchPostMortemTestCase(SeleniumTestCase): """ This class for catching exceptions """ @classmethod def setUpClass(cls): cls.db_proc = Popen(['python', os.path.join(cwd, 'db_pm.py')], shell=False) super(CatchPostMortemTestCase, cls).setUpClass() def test_catch_post_mortem(self): """ Test if catch_post_mortem context manager catches exceptions """ time.sleep(1) curr_line_tag = self.browser.find_element_by_id('curr_line') self.assertEqual(curr_line_tag.text, '14') curr_file_tag = self.browser.find_element_by_id('curr_file_code') self.assertIn('assert False, \'Oops!\'', curr_file_tag.text) stdout_tag = self.browser.find_element_by_id('stdout') self.assertIn('AssertionError', stdout_tag.text) class InspectCommandTestCase(SeleniumTestCase): """ Test for inspect command """ @classmethod def setUpClass(cls): cls.db_proc = Popen(['python', os.path.join(cwd, 'db_i.py')], shell=False) super(InspectCommandTestCase, cls).setUpClass() def test_inspect_existing_object(self): """ Test inspecting existing object """ time.sleep(1) self.stdin.send_keys('i Foo') self.send_btn.click() time.sleep(1) self.assertIn('foo: \'foo\'', self.stdout_tag.text) self.assertIn('bar: \'bar\'', self.stdout_tag.text) self.stdin.send_keys('i bar') self.send_btn.click() time.sleep(1) self.assertNotIn('NameError: name "bar" is not defined', self.stdout_tag.text) def test_inspect_non_existing_object(self): """ Test inspecting non-existing object """ self.stdin.send_keys('i spam') self.send_btn.click() time.sleep(1) self.assertIn('NameError: name "spam" is not defined', self.stdout_tag.text) if __name__ == '__main__': main()