Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit 52e613b

Browse files
authored
Merge pull request #890 from bjones1/lp_move
Refactor: Move LP code together,
2 parents 7e3f253 + 0e656b9 commit 52e613b

4 files changed

Lines changed: 137 additions & 190 deletions

File tree

runestone/lp/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
import sys
2-
from runestone.lp import inlinesyntaxhighlight
1+
from runestone.lp import inlinesyntaxhighlight, lp
2+
33

44
# Initialize both extensions.
55
def setup(app):
66
inlinesyntaxhighlight.setup(app)
7-
# The LP extension requires Python 3.
8-
if sys.version_info >= (3, 3):
9-
from runestone.lp import lp
10-
return lp.setup(app)
7+
return lp.setup(app)

runestone/lp/lp.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
1-
# .. Copyright (C) 2017 Bryan A. Jones.
1+
# .. Copyright (C) 2019 Bryan A. Jones.
22
#
3-
# This file is part of E-Book Binder.
4-
#
5-
# E-Book Binder is free software: you can redistribute it and/or modify it
6-
# under the terms of the GNU General Public License as published by the Free
7-
# Software Foundation, either version 3 of the License, or (at your option)
8-
# any later version.
9-
#
10-
# E-Book Binder is distributed in the hope that it will be useful, but WITHOUT
11-
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12-
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13-
# details.
14-
#
15-
# You should have received a copy of the GNU General Public License along
16-
# with E-Book Binder. If not, see <http://www.gnu.org/licenses/>.
173
#
184
# .. highlight:: python
195
#
@@ -49,7 +35,7 @@
4935
# Local imports
5036
# -------------
5137
from ..common.runestonedirective import RunestoneIdDirective, RunestoneNode
52-
from ..server.lp_common_lib import STUDENT_SOURCE_PATH, code_here_comment, SPHINX_CONFIG_NAME
38+
from .lp_common_lib import STUDENT_SOURCE_PATH, code_here_comment, SPHINX_CONFIG_NAME
5339
from ..server.componentdb import addQuestionToDB, addHTMLToDB
5440
#
5541
# Directives
Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
1-
# .. Copyright (C) 2017 Bryan A. Jones.
1+
# .. Copyright (C) 2019 Bryan A. Jones.
22
#
3-
# This file is part of E-Book Binder.
4-
#
5-
# E-Book Binder is free software: you can redistribute it and/or modify it
6-
# under the terms of the GNU General Public License as published by the Free
7-
# Software Foundation, either version 3 of the License, or (at your option)
8-
# any later version.
9-
#
10-
# E-Book Binder is distributed in the hope that it will be useful, but WITHOUT
11-
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12-
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13-
# details.
14-
#
15-
# You should have received a copy of the GNU General Public License along
16-
# with E-Book Binder. If not, see <http://www.gnu.org/licenses/>.
173
#
184
# .. highlight:: python
195
#

runestone/lp/test/test_lp.py

Lines changed: 131 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,99 @@
1-
# .. Copyright (C) 2017 Bryan A. Jones.
2-
#
3-
# This file is part of E-Book Binder.
4-
#
5-
# E-Book Binder is free software: you can redistribute it and/or modify it
6-
# under the terms of the GNU General Public License as published by the Free
7-
# Software Foundation, either version 3 of the License, or (at your option)
8-
# any later version.
9-
#
10-
# E-Book Binder is distributed in the hope that it will be useful, but WITHOUT
11-
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12-
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13-
# details.
14-
#
15-
# You should have received a copy of the GNU General Public License along
16-
# with E-Book Binder. If not, see <http://www.gnu.org/licenses/>.
17-
#
18-
# .. highlight:: python
19-
#
201
# ***********************
212
# test_lp.py - Unit tests
223
# ***********************
234
# Require Python 3 to run tests.
24-
import sys
25-
from unittest import TestCase, skip
26-
if sys.version_info < (3, 3):
27-
class TestOldPython(TestCase):
28-
@skip('Tests require Python 3.')
29-
def test_1():
30-
pass
31-
else:
32-
#
33-
# Imports
34-
# =======
35-
# These are listed in the order prescribed by `PEP 8
36-
# <http://www.python.org/dev/peps/pep-0008/#imports>`_.
37-
#
38-
# Standard library
39-
# ----------------
40-
from pathlib import Path
41-
from time import sleep
42-
#
43-
# Third-party imports
44-
# -------------------
45-
from selenium.webdriver.common.by import By
46-
from selenium.webdriver.support.ui import WebDriverWait
47-
from selenium.webdriver.support import expected_conditions as EC
48-
#
49-
# Local imports
50-
# -------------
51-
from runestone.lp.lp import (
52-
_remove_code_solutions, _textarea_replacement,
53-
TEXTAREA_REPLACEMENT_STRING, _source_read
54-
)
55-
from runestone.server.lp_common_lib import _add_line_comment_delimiter, STUDENT_SOURCE_PATH, read_sphinx_config, SPHINX_CONFIG_NAME
56-
from runestone.unittest_base import module_fixture_maker, RunestoneTestCase
57-
58-
mf, setUpModule, tearDownModule = module_fixture_maker(__file__, True)
59-
#
60-
# Mock classes
61-
# ============
62-
class MockApp:
63-
def __init__(self, docname):
64-
self.builder = MockBuilder(docname)
65-
self.env = self.builder.env
66-
self.outdir = '_build/html'
67-
68-
class MockBuilder:
69-
def __init__(self, docname):
70-
self.env = MockEnv(docname)
71-
72-
class MockEnv:
73-
def __init__(self, docname):
74-
self.docname = docname
75-
self.srcdir = '_source'
76-
self.titles = {docname: 'A test file'}
77-
78-
def doc2path(self, docname, *args):
79-
return docname
80-
#
81-
# Supporting utilities
82-
# ====================
83-
# Set up Sphinx mocks.
84-
def sphinx_setup():
85-
app = MockApp('test.c')
86-
env = app.builder.env
87-
return app, env
88-
#
89-
# Tests
90-
# =====
91-
# Test the code solution removal.
92-
class Unit_Test_Lp(TestCase):
93-
# Make sure there were no unexpected warnings in the build.
94-
def test_1(self):
95-
self.assertEqual(mf.build_stderr_data.count('WARNING'), 1)
96-
97-
# Make sure that the student source files were generated.
98-
def test_1a(self):
99-
sphinx_config = read_sphinx_config()
100-
sphinx_source_path = sphinx_config['SPHINX_SOURCE_PATH']
101-
sphinx_out_path = sphinx_config['SPHINX_OUT_PATH']
102-
self.assertTrue(sphinx_source_path)
103-
104-
# Check that a HTML version of the source was produced.
105-
self.assertTrue((Path(sphinx_out_path) / 'lp_tester.s-source.html').exists())
106-
107-
# Check that the student source has answers removed.
108-
with open(str(Path(sphinx_out_path) / STUDENT_SOURCE_PATH / 'lp_tester.s'), encoding='utf-8') as f:
109-
student_source = f.read()
110-
self.assertNotIn('_u16_b: .space 2', student_source)
111-
self.assertNotIn('mov #0xA15F, W0', student_source)
112-
113-
# Test _remove_code_solutions.
114-
def test_2(self):
115-
# Note: to avoid the tags being recognized when this file is parsed by Sphinx, they're broken apart in the strings below.
116-
self.assertEqual(_remove_code_solutions('foo.s', """# line 1
5+
6+
#
7+
# Imports
8+
# =======
9+
# These are listed in the order prescribed by `PEP 8
10+
# <http://www.python.org/dev/peps/pep-0008/#imports>`_.
11+
#
12+
# Standard library
13+
# ----------------
14+
from pathlib import Path
15+
from time import sleep
16+
from unittest import TestCase
17+
#
18+
# Third-party imports
19+
# -------------------
20+
from selenium.webdriver.common.by import By
21+
from selenium.webdriver.support.ui import WebDriverWait
22+
from selenium.webdriver.support import expected_conditions as EC
23+
#
24+
# Local imports
25+
# -------------
26+
from runestone.lp.lp import (
27+
_remove_code_solutions, _textarea_replacement,
28+
TEXTAREA_REPLACEMENT_STRING, _source_read
29+
)
30+
from runestone.lp.lp_common_lib import _add_line_comment_delimiter, STUDENT_SOURCE_PATH, read_sphinx_config
31+
from runestone.unittest_base import module_fixture_maker, RunestoneTestCase
32+
33+
mf, setUpModule, tearDownModule = module_fixture_maker(__file__, True)
34+
35+
36+
# Mock classes
37+
# ============
38+
class MockApp:
39+
def __init__(self, docname):
40+
self.builder = MockBuilder(docname)
41+
self.env = self.builder.env
42+
self.outdir = '_build/html'
43+
44+
45+
class MockBuilder:
46+
def __init__(self, docname):
47+
self.env = MockEnv(docname)
48+
49+
50+
class MockEnv:
51+
def __init__(self, docname):
52+
self.docname = docname
53+
self.srcdir = '_source'
54+
self.titles = {docname: 'A test file'}
55+
56+
def doc2path(self, docname, *args):
57+
return docname
58+
59+
60+
# Supporting utilities
61+
# ====================
62+
# Set up Sphinx mocks.
63+
def sphinx_setup():
64+
app = MockApp('test.c')
65+
env = app.builder.env
66+
return app, env
67+
68+
69+
# Tests
70+
# =====
71+
# Test the code solution removal.
72+
class Unit_Test_Lp(TestCase):
73+
# Make sure there were no unexpected warnings in the build.
74+
def test_1(self):
75+
self.assertEqual(mf.build_stderr_data.count('WARNING'), 1)
76+
77+
# Make sure that the student source files were generated.
78+
def test_1a(self):
79+
sphinx_config = read_sphinx_config()
80+
sphinx_source_path = sphinx_config['SPHINX_SOURCE_PATH']
81+
sphinx_out_path = sphinx_config['SPHINX_OUT_PATH']
82+
self.assertTrue(sphinx_source_path)
83+
84+
# Check that a HTML version of the source was produced.
85+
self.assertTrue((Path(sphinx_out_path) / 'lp_tester.s-source.html').exists())
86+
87+
# Check that the student source has answers removed.
88+
with open(str(Path(sphinx_out_path) / STUDENT_SOURCE_PATH / 'lp_tester.s'), encoding='utf-8') as f:
89+
student_source = f.read()
90+
self.assertNotIn('_u16_b: .space 2', student_source)
91+
self.assertNotIn('mov #0xA15F, W0', student_source)
92+
93+
# Test _remove_code_solutions.
94+
def test_2(self):
95+
# Note: to avoid the tags being recognized when this file is parsed by Sphinx, they're broken apart in the strings below.
96+
self.assertEqual(_remove_code_solutions('foo.s', """# line 1
11797
# line 2
11898
# line 3
11999
# SOLUTION_""" """BEGIN
@@ -137,23 +117,22 @@ def test_2(self):
137117
# Snip 14
138118
# line 15""")
139119

140-
# Test the addition of comments to a string.
141-
def test_3(self):
142-
self.assertEqual(_add_line_comment_delimiter('1\n2', 'foo.py'), '# 1\n# 2')
143-
self.assertEqual(_add_line_comment_delimiter('1\n2', 'foo.c'), '// 1\n// 2')
120+
# Test the addition of comments to a string.
121+
def test_3(self):
122+
self.assertEqual(_add_line_comment_delimiter('1\n2', 'foo.py'), '# 1\n# 2')
123+
self.assertEqual(_add_line_comment_delimiter('1\n2', 'foo.c'), '// 1\n// 2')
144124

145-
# Test ``_textarea_replacement``.
146-
def test_4(self):
147-
# Check a mimimum-length replacement.
148-
self.assertEqual(_textarea_replacement(3, 4, 'foo.py'), TEXTAREA_REPLACEMENT_STRING.format(4))
125+
# Test ``_textarea_replacement``.
126+
def test_4(self):
127+
# Check a mimimum-length replacement.
128+
self.assertEqual(_textarea_replacement(3, 4, 'foo.py'), TEXTAREA_REPLACEMENT_STRING.format(4))
149129

150-
# Check a replcement with added lines.
151-
self.assertEqual(_textarea_replacement(3, 22, 'foo.py').count('\n'), 20)
130+
# Check a replcement with added lines.
131+
self.assertEqual(_textarea_replacement(3, 22, 'foo.py').count('\n'), 20)
152132

153-
# Test the source-read event callback.
154-
def test_5(self):
155-
src = [
156-
"""Line 1
133+
# Test the source-read event callback.
134+
def test_5(self):
135+
src = ["""Line 1
157136
Line 2
158137
SOLUTION_""" """BEGIN
159138
Line 4
@@ -165,11 +144,9 @@ def test_5(self):
165144
Line 10
166145
SOLUTION_""" """END
167146
Line 12"""]
168-
app, env = sphinx_setup()
169-
_source_read(app, env.docname, src)
170-
self.assertEqual(src,
171-
[
172-
"""Line 1
147+
app, env = sphinx_setup()
148+
_source_read(app, env.docname, src)
149+
self.assertEqual(src, ["""Line 1
173150
Line 2
174151
175152
.. raw::
@@ -182,25 +159,26 @@ def test_5(self):
182159
183160
Line 12"""])
184161

185-
class Functional_Test_Lp(RunestoneTestCase):
186-
def test_1(self):
187-
self.driver.get(self.host + "/lp_tester.s.html")
188-
snippets = self.driver.find_elements_by_class_name("code_snippet")
189-
self.assertEqual(len(snippets), 2)
190-
check_button = self.driver.find_element_by_id('e1')
191-
result_area = self.driver.find_element_by_id('lp-result')
192-
193-
# Set snippets.
194-
self.driver.execute_script('LPList["e1"].textAreas[0].setValue("xxx"); LPList["e1"].textAreas[1].setValue("yyy");')
195-
self.assertFalse(result_area.text)
196-
197-
# Click the test button.
198-
check_button.click()
199-
WebDriverWait(self.driver, 10).until(EC.text_to_be_present_in_element_value((By.ID, 'lp-result'), 'Building...'))
200-
201-
# Refresh the page. See if saved snippets are restored.
202-
self.driver.get(self.host + "/lp_tester.s.html")
203-
# Wait for script to run. I don't see a wait condition what would work, unfortunately.
204-
sleep(0.5)
205-
self.assertEqual(self.driver.execute_script('return LPList["e1"].textAreas[0].getValue();'), 'xxx')
206-
self.assertEqual(self.driver.execute_script('return LPList["e1"].textAreas[1].getValue();'), 'yyy')
162+
163+
class Functional_Test_Lp(RunestoneTestCase):
164+
def test_1(self):
165+
self.driver.get(self.host + "/lp_tester.s.html")
166+
snippets = self.driver.find_elements_by_class_name("code_snippet")
167+
self.assertEqual(len(snippets), 2)
168+
check_button = self.driver.find_element_by_id('e1')
169+
result_area = self.driver.find_element_by_id('lp-result')
170+
171+
# Set snippets.
172+
self.driver.execute_script('LPList["e1"].textAreas[0].setValue("xxx"); LPList["e1"].textAreas[1].setValue("yyy");')
173+
self.assertFalse(result_area.text)
174+
175+
# Click the test button.
176+
check_button.click()
177+
WebDriverWait(self.driver, 10).until(EC.text_to_be_present_in_element_value((By.ID, 'lp-result'), 'Building...'))
178+
179+
# Refresh the page. See if saved snippets are restored.
180+
self.driver.get(self.host + "/lp_tester.s.html")
181+
# Wait for script to run. I don't see a wait condition what would work, unfortunately.
182+
sleep(0.5)
183+
self.assertEqual(self.driver.execute_script('return LPList["e1"].textAreas[0].getValue();'), 'xxx')
184+
self.assertEqual(self.driver.execute_script('return LPList["e1"].textAreas[1].getValue();'), 'yyy')

0 commit comments

Comments
 (0)