##// END OF EJS Templates
test that `-h` and `--help-all` work for various IPython entry points...
MinRK -
Show More
@@ -0,0 +1,29 b''
1 """Test NotebookApp"""
2
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 import nose.tools as nt
15
16 import IPython.testing.tools as tt
17
18 #-----------------------------------------------------------------------------
19 # Test functions
20 #-----------------------------------------------------------------------------
21
22 def test_help_output():
23 """ipython notebook -h works"""
24 tt.help_output_test('notebook')
25
26 def test_help_all_output():
27 """ipython notebook --help-all works"""
28 tt.help_all_output_test('notebook')
29
@@ -0,0 +1,29 b''
1 """Test QtConsoleApp"""
2
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 import nose.tools as nt
15
16 import IPython.testing.tools as tt
17
18 #-----------------------------------------------------------------------------
19 # Test functions
20 #-----------------------------------------------------------------------------
21
22 def test_help_output():
23 """ipython qtconsole -h works"""
24 tt.help_output_test('qtconsole')
25
26 def test_help_all_output():
27 """ipython qtconsole --help-all works"""
28 tt.help_all_output_test('qtconsole')
29
@@ -0,0 +1,67 b''
1 """Test help output of various IPython entry points"""
2
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 from IPython.testing.tools import help, help_all
15
16 #-----------------------------------------------------------------------------
17 # Tests
18 #-----------------------------------------------------------------------------
19
20
21 @help()
22 def test_ipython_help():
23 pass
24
25 @help_all()
26 def test_ipython_help_all():
27 pass
28
29 @help("profile")
30 def test_profile_help():
31 pass
32
33 @help_all("profile")
34 def test_profile_help_all():
35 pass
36
37 @help("profile list")
38 def test_profile_list_help():
39 pass
40
41 @help_all("profile list")
42 def test_profile_list_help_all():
43 pass
44
45 @help("profile create")
46 def test_profile_create_help():
47 pass
48
49 @help_all("profile create")
50 def test_profile_create_help_all():
51 pass
52
53 @help("locate")
54 def test_locate_help():
55 pass
56
57 @help_all("locate")
58 def test_locate_help_all():
59 pass
60
61 @help("locate profile")
62 def test_locate_profile_help():
63 pass
64
65 @help_all("locate profile")
66 def test_locate_profile_all():
67 pass
@@ -1,160 +1,164 b''
1 """
1 """Test NbConvertApp"""
2 Contains tests for the nbconvertapp
2
3 """
4 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
5 #Copyright (c) 2013, the IPython Development Team.
4 # Copyright (C) 2013 The IPython Development Team
6 #
7 #Distributed under the terms of the Modified BSD License.
8 #
5 #
9 #The full license is in the file COPYING.txt, distributed with this software.
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
10 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
11
9
12 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
13 # Imports
11 # Imports
14 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
15
13
16 import os
14 import os
17 import glob
15 import glob
18
16
19 from .base import TestsBase
17 from .base import TestsBase
20
18
19 import IPython.testing.tools as tt
21 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
22
21
23
22
24 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
25 # Constants
24 # Constants
26 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
27
26
28
27
29 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
30 # Classes and functions
29 # Classes and functions
31 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
32
31
33 class TestNbConvertApp(TestsBase):
32 class TestNbConvertApp(TestsBase):
34 """Collection of NbConvertApp tests"""
33 """Collection of NbConvertApp tests"""
35
34
36
35
37 def test_notebook_help(self):
36 def test_notebook_help(self):
38 """
37 """Will help show if no notebooks are specified?"""
39 Will help show if no notebooks are specified?
40 """
41 with self.create_temp_cwd():
38 with self.create_temp_cwd():
42 out, err = self.call('nbconvert --log-level 0', ignore_return_code=True)
39 out, err = self.call('nbconvert --log-level 0', ignore_return_code=True)
43 assert "see '--help-all'" in out
40 self.assertIn("see '--help-all'", out)
41
42 def test_help_output(self):
43 """ipython nbconvert -h works"""
44 tt.help_output_test('nbconvert')
44
45
46 def test_help_all_output(self):
47 """ipython nbconvert --help-all works"""
48 tt.help_all_output_test('nbconvert')
45
49
46 def test_glob(self):
50 def test_glob(self):
47 """
51 """
48 Do search patterns work for notebook names?
52 Do search patterns work for notebook names?
49 """
53 """
50 with self.create_temp_cwd(['notebook*.ipynb']):
54 with self.create_temp_cwd(['notebook*.ipynb']):
51 self.call('nbconvert --to python *.ipynb --log-level 0')
55 self.call('nbconvert --to python *.ipynb --log-level 0')
52 assert os.path.isfile('notebook1.py')
56 assert os.path.isfile('notebook1.py')
53 assert os.path.isfile('notebook2.py')
57 assert os.path.isfile('notebook2.py')
54
58
55
59
56 def test_glob_subdir(self):
60 def test_glob_subdir(self):
57 """
61 """
58 Do search patterns work for subdirectory notebook names?
62 Do search patterns work for subdirectory notebook names?
59 """
63 """
60 with self.create_temp_cwd():
64 with self.create_temp_cwd():
61 self.copy_files_to(['notebook*.ipynb'], 'subdir/')
65 self.copy_files_to(['notebook*.ipynb'], 'subdir/')
62 self.call('nbconvert --to python --log-level 0 ' +
66 self.call('nbconvert --to python --log-level 0 ' +
63 os.path.join('subdir', '*.ipynb'))
67 os.path.join('subdir', '*.ipynb'))
64 assert os.path.isfile('notebook1.py')
68 assert os.path.isfile('notebook1.py')
65 assert os.path.isfile('notebook2.py')
69 assert os.path.isfile('notebook2.py')
66
70
67
71
68 def test_explicit(self):
72 def test_explicit(self):
69 """
73 """
70 Do explicit notebook names work?
74 Do explicit notebook names work?
71 """
75 """
72 with self.create_temp_cwd(['notebook*.ipynb']):
76 with self.create_temp_cwd(['notebook*.ipynb']):
73 self.call('nbconvert --log-level 0 --to python notebook2')
77 self.call('nbconvert --log-level 0 --to python notebook2')
74 assert not os.path.isfile('notebook1.py')
78 assert not os.path.isfile('notebook1.py')
75 assert os.path.isfile('notebook2.py')
79 assert os.path.isfile('notebook2.py')
76
80
77
81
78 @dec.onlyif_cmds_exist('pdflatex')
82 @dec.onlyif_cmds_exist('pdflatex')
79 @dec.onlyif_cmds_exist('pandoc')
83 @dec.onlyif_cmds_exist('pandoc')
80 def test_filename_spaces(self):
84 def test_filename_spaces(self):
81 """
85 """
82 Generate PDFs with graphics if notebooks have spaces in the name?
86 Generate PDFs with graphics if notebooks have spaces in the name?
83 """
87 """
84 with self.create_temp_cwd(['notebook2.ipynb']):
88 with self.create_temp_cwd(['notebook2.ipynb']):
85 os.rename('notebook2.ipynb', 'notebook with spaces.ipynb')
89 os.rename('notebook2.ipynb', 'notebook with spaces.ipynb')
86 o,e = self.call('nbconvert --log-level 0 --to latex '
90 o,e = self.call('nbconvert --log-level 0 --to latex '
87 '"notebook with spaces" --post PDF '
91 '"notebook with spaces" --post PDF '
88 '--PDFPostProcessor.verbose=True')
92 '--PDFPostProcessor.verbose=True')
89 assert os.path.isfile('notebook with spaces.tex')
93 assert os.path.isfile('notebook with spaces.tex')
90 assert os.path.isdir('notebook with spaces_files')
94 assert os.path.isdir('notebook with spaces_files')
91 assert os.path.isfile('notebook with spaces.pdf')
95 assert os.path.isfile('notebook with spaces.pdf')
92
96
93 @dec.onlyif_cmds_exist('pdflatex')
97 @dec.onlyif_cmds_exist('pdflatex')
94 @dec.onlyif_cmds_exist('pandoc')
98 @dec.onlyif_cmds_exist('pandoc')
95 def test_post_processor(self):
99 def test_post_processor(self):
96 """
100 """
97 Do post processors work?
101 Do post processors work?
98 """
102 """
99 with self.create_temp_cwd(['notebook1.ipynb']):
103 with self.create_temp_cwd(['notebook1.ipynb']):
100 self.call('nbconvert --log-level 0 --to latex notebook1 '
104 self.call('nbconvert --log-level 0 --to latex notebook1 '
101 '--post PDF --PDFPostProcessor.verbose=True')
105 '--post PDF --PDFPostProcessor.verbose=True')
102 assert os.path.isfile('notebook1.tex')
106 assert os.path.isfile('notebook1.tex')
103 assert os.path.isfile('notebook1.pdf')
107 assert os.path.isfile('notebook1.pdf')
104
108
105
109
106 @dec.onlyif_cmds_exist('pandoc')
110 @dec.onlyif_cmds_exist('pandoc')
107 def test_template(self):
111 def test_template(self):
108 """
112 """
109 Do export templates work?
113 Do export templates work?
110 """
114 """
111 with self.create_temp_cwd(['notebook2.ipynb']):
115 with self.create_temp_cwd(['notebook2.ipynb']):
112 self.call('nbconvert --log-level 0 --to slides '
116 self.call('nbconvert --log-level 0 --to slides '
113 'notebook2.ipynb --template reveal')
117 'notebook2.ipynb --template reveal')
114 assert os.path.isfile('notebook2.slides.html')
118 assert os.path.isfile('notebook2.slides.html')
115 with open('notebook2.slides.html') as f:
119 with open('notebook2.slides.html') as f:
116 assert '/reveal.css' in f.read()
120 assert '/reveal.css' in f.read()
117
121
118
122
119 def test_glob_explicit(self):
123 def test_glob_explicit(self):
120 """
124 """
121 Can a search pattern be used along with matching explicit notebook names?
125 Can a search pattern be used along with matching explicit notebook names?
122 """
126 """
123 with self.create_temp_cwd(['notebook*.ipynb']):
127 with self.create_temp_cwd(['notebook*.ipynb']):
124 self.call('nbconvert --log-level 0 --to python '
128 self.call('nbconvert --log-level 0 --to python '
125 '*.ipynb notebook1.ipynb notebook2.ipynb')
129 '*.ipynb notebook1.ipynb notebook2.ipynb')
126 assert os.path.isfile('notebook1.py')
130 assert os.path.isfile('notebook1.py')
127 assert os.path.isfile('notebook2.py')
131 assert os.path.isfile('notebook2.py')
128
132
129
133
130 def test_explicit_glob(self):
134 def test_explicit_glob(self):
131 """
135 """
132 Can explicit notebook names be used and then a matching search pattern?
136 Can explicit notebook names be used and then a matching search pattern?
133 """
137 """
134 with self.create_temp_cwd(['notebook*.ipynb']):
138 with self.create_temp_cwd(['notebook*.ipynb']):
135 self.call('nbconvert --log-level 0 --to=python '
139 self.call('nbconvert --log-level 0 --to=python '
136 'notebook1.ipynb notebook2.ipynb *.ipynb')
140 'notebook1.ipynb notebook2.ipynb *.ipynb')
137 assert os.path.isfile('notebook1.py')
141 assert os.path.isfile('notebook1.py')
138 assert os.path.isfile('notebook2.py')
142 assert os.path.isfile('notebook2.py')
139
143
140
144
141 def test_default_config(self):
145 def test_default_config(self):
142 """
146 """
143 Does the default config work?
147 Does the default config work?
144 """
148 """
145 with self.create_temp_cwd(['notebook*.ipynb', 'ipython_nbconvert_config.py']):
149 with self.create_temp_cwd(['notebook*.ipynb', 'ipython_nbconvert_config.py']):
146 self.call('nbconvert --log-level 0')
150 self.call('nbconvert --log-level 0')
147 assert os.path.isfile('notebook1.py')
151 assert os.path.isfile('notebook1.py')
148 assert not os.path.isfile('notebook2.py')
152 assert not os.path.isfile('notebook2.py')
149
153
150
154
151 def test_override_config(self):
155 def test_override_config(self):
152 """
156 """
153 Can the default config be overriden?
157 Can the default config be overriden?
154 """
158 """
155 with self.create_temp_cwd(['notebook*.ipynb',
159 with self.create_temp_cwd(['notebook*.ipynb',
156 'ipython_nbconvert_config.py',
160 'ipython_nbconvert_config.py',
157 'override.py']):
161 'override.py']):
158 self.call('nbconvert --log-level 0 --config="override.py"')
162 self.call('nbconvert --log-level 0 --config="override.py"')
159 assert not os.path.isfile('notebook1.py')
163 assert not os.path.isfile('notebook1.py')
160 assert os.path.isfile('notebook2.py')
164 assert os.path.isfile('notebook2.py')
@@ -1,57 +1,67 b''
1 """Tests for two-process terminal frontend
1 """Tests for two-process terminal frontend
2
2
3 Currently only has the most simple test possible, starting a console and running
3 Currently only has the most simple test possible, starting a console and running
4 a single command.
4 a single command.
5
5
6 Authors:
6 Authors:
7
7
8 * Min RK
8 * Min RK
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import sys
15 import sys
16 import time
16 import time
17
17
18 import nose.tools as nt
18 import nose.tools as nt
19 from nose import SkipTest
19 from nose import SkipTest
20
20
21 import IPython.testing.tools as tt
21 from IPython.testing import decorators as dec
22 from IPython.testing import decorators as dec
22 from IPython.utils import py3compat
23 from IPython.utils import py3compat
23
24
24 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
25 # Test functions begin
26 # Tests
26 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
27
28
28 @dec.skip_win32
29 @dec.skip_win32
29 def test_console_starts():
30 def test_console_starts():
30 """test that `ipython console` starts a terminal"""
31 """test that `ipython console` starts a terminal"""
31 from IPython.external import pexpect
32 from IPython.external import pexpect
32
33
33 args = ['console', '--colors=NoColor']
34 args = ['console', '--colors=NoColor']
34 # FIXME: remove workaround for 2.6 support
35 # FIXME: remove workaround for 2.6 support
35 if sys.version_info[:2] > (2,6):
36 if sys.version_info[:2] > (2,6):
36 args = ['-m', 'IPython'] + args
37 args = ['-m', 'IPython'] + args
37 cmd = sys.executable
38 cmd = sys.executable
38 else:
39 else:
39 cmd = 'ipython'
40 cmd = 'ipython'
40
41
41 try:
42 try:
42 p = pexpect.spawn(cmd, args=args)
43 p = pexpect.spawn(cmd, args=args)
43 except IOError:
44 except IOError:
44 raise SkipTest("Couldn't find command %s" % cmd)
45 raise SkipTest("Couldn't find command %s" % cmd)
45
46
46 # timeout after one minute
47 # timeout after one minute
47 t = 60
48 t = 60
48 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
49 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
49 p.sendline('5')
50 p.sendline('5')
50 idx = p.expect([r'Out\[\d+\]: 5', pexpect.EOF], timeout=t)
51 idx = p.expect([r'Out\[\d+\]: 5', pexpect.EOF], timeout=t)
51 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
52 idx = p.expect([r'In \[\d+\]', pexpect.EOF], timeout=t)
52 # send ctrl-D;ctrl-D to exit
53 # send ctrl-D;ctrl-D to exit
53 p.sendeof()
54 p.sendeof()
54 p.sendeof()
55 p.sendeof()
55 p.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=t)
56 p.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=t)
56 if p.isalive():
57 if p.isalive():
57 p.terminate()
58 p.terminate()
59
60 def test_help_output():
61 """ipython console -h works"""
62 tt.help_output_test('console')
63
64 def test_help_all_output():
65 """ipython console --help-all works"""
66 tt.help_all_output_test('console')
67
@@ -1,410 +1,465 b''
1 """Generic testing tools.
1 """Generic testing tools.
2
2
3 Authors
3 Authors
4 -------
4 -------
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
5 - Fernando Perez <Fernando.Perez@berkeley.edu>
6 """
6 """
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2009-2011 The IPython Development Team
11 # Copyright (C) 2009 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 import inspect
21 import os
22 import os
22 import re
23 import re
23 import sys
24 import sys
24 import tempfile
25 import tempfile
25
26
26 from contextlib import contextmanager
27 from contextlib import contextmanager
27 from io import StringIO
28 from io import StringIO
28 from subprocess import Popen, PIPE
29 from subprocess import Popen, PIPE
29
30
30 try:
31 try:
31 # These tools are used by parts of the runtime, so we make the nose
32 # These tools are used by parts of the runtime, so we make the nose
32 # dependency optional at this point. Nose is a hard dependency to run the
33 # dependency optional at this point. Nose is a hard dependency to run the
33 # test suite, but NOT to use ipython itself.
34 # test suite, but NOT to use ipython itself.
34 import nose.tools as nt
35 import nose.tools as nt
35 has_nose = True
36 has_nose = True
36 except ImportError:
37 except ImportError:
37 has_nose = False
38 has_nose = False
38
39
39 from IPython.config.loader import Config
40 from IPython.config.loader import Config
41 from IPython.utils.process import get_output_error_code
40 from IPython.utils.text import list_strings
42 from IPython.utils.text import list_strings
41 from IPython.utils.io import temp_pyfile, Tee
43 from IPython.utils.io import temp_pyfile, Tee
42 from IPython.utils import py3compat
44 from IPython.utils import py3compat
43 from IPython.utils.encoding import DEFAULT_ENCODING
45 from IPython.utils.encoding import DEFAULT_ENCODING
44
46
45 from . import decorators as dec
47 from . import decorators as dec
46 from . import skipdoctest
48 from . import skipdoctest
47
49
48 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
49 # Functions and classes
51 # Functions and classes
50 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
51
53
52 # The docstring for full_path doctests differently on win32 (different path
54 # The docstring for full_path doctests differently on win32 (different path
53 # separator) so just skip the doctest there. The example remains informative.
55 # separator) so just skip the doctest there. The example remains informative.
54 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
56 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
55
57
56 @doctest_deco
58 @doctest_deco
57 def full_path(startPath,files):
59 def full_path(startPath,files):
58 """Make full paths for all the listed files, based on startPath.
60 """Make full paths for all the listed files, based on startPath.
59
61
60 Only the base part of startPath is kept, since this routine is typically
62 Only the base part of startPath is kept, since this routine is typically
61 used with a script's __file__ variable as startPath. The base of startPath
63 used with a script's __file__ variable as startPath. The base of startPath
62 is then prepended to all the listed files, forming the output list.
64 is then prepended to all the listed files, forming the output list.
63
65
64 Parameters
66 Parameters
65 ----------
67 ----------
66 startPath : string
68 startPath : string
67 Initial path to use as the base for the results. This path is split
69 Initial path to use as the base for the results. This path is split
68 using os.path.split() and only its first component is kept.
70 using os.path.split() and only its first component is kept.
69
71
70 files : string or list
72 files : string or list
71 One or more files.
73 One or more files.
72
74
73 Examples
75 Examples
74 --------
76 --------
75
77
76 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
78 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
77 ['/foo/a.txt', '/foo/b.txt']
79 ['/foo/a.txt', '/foo/b.txt']
78
80
79 >>> full_path('/foo',['a.txt','b.txt'])
81 >>> full_path('/foo',['a.txt','b.txt'])
80 ['/a.txt', '/b.txt']
82 ['/a.txt', '/b.txt']
81
83
82 If a single file is given, the output is still a list:
84 If a single file is given, the output is still a list:
83 >>> full_path('/foo','a.txt')
85 >>> full_path('/foo','a.txt')
84 ['/a.txt']
86 ['/a.txt']
85 """
87 """
86
88
87 files = list_strings(files)
89 files = list_strings(files)
88 base = os.path.split(startPath)[0]
90 base = os.path.split(startPath)[0]
89 return [ os.path.join(base,f) for f in files ]
91 return [ os.path.join(base,f) for f in files ]
90
92
91
93
92 def parse_test_output(txt):
94 def parse_test_output(txt):
93 """Parse the output of a test run and return errors, failures.
95 """Parse the output of a test run and return errors, failures.
94
96
95 Parameters
97 Parameters
96 ----------
98 ----------
97 txt : str
99 txt : str
98 Text output of a test run, assumed to contain a line of one of the
100 Text output of a test run, assumed to contain a line of one of the
99 following forms::
101 following forms::
100
102
101 'FAILED (errors=1)'
103 'FAILED (errors=1)'
102 'FAILED (failures=1)'
104 'FAILED (failures=1)'
103 'FAILED (errors=1, failures=1)'
105 'FAILED (errors=1, failures=1)'
104
106
105 Returns
107 Returns
106 -------
108 -------
107 nerr, nfail: number of errors and failures.
109 nerr, nfail: number of errors and failures.
108 """
110 """
109
111
110 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
112 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
111 if err_m:
113 if err_m:
112 nerr = int(err_m.group(1))
114 nerr = int(err_m.group(1))
113 nfail = 0
115 nfail = 0
114 return nerr, nfail
116 return nerr, nfail
115
117
116 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
118 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
117 if fail_m:
119 if fail_m:
118 nerr = 0
120 nerr = 0
119 nfail = int(fail_m.group(1))
121 nfail = int(fail_m.group(1))
120 return nerr, nfail
122 return nerr, nfail
121
123
122 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
124 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
123 re.MULTILINE)
125 re.MULTILINE)
124 if both_m:
126 if both_m:
125 nerr = int(both_m.group(1))
127 nerr = int(both_m.group(1))
126 nfail = int(both_m.group(2))
128 nfail = int(both_m.group(2))
127 return nerr, nfail
129 return nerr, nfail
128
130
129 # If the input didn't match any of these forms, assume no error/failures
131 # If the input didn't match any of these forms, assume no error/failures
130 return 0, 0
132 return 0, 0
131
133
132
134
133 # So nose doesn't think this is a test
135 # So nose doesn't think this is a test
134 parse_test_output.__test__ = False
136 parse_test_output.__test__ = False
135
137
136
138
137 def default_argv():
139 def default_argv():
138 """Return a valid default argv for creating testing instances of ipython"""
140 """Return a valid default argv for creating testing instances of ipython"""
139
141
140 return ['--quick', # so no config file is loaded
142 return ['--quick', # so no config file is loaded
141 # Other defaults to minimize side effects on stdout
143 # Other defaults to minimize side effects on stdout
142 '--colors=NoColor', '--no-term-title','--no-banner',
144 '--colors=NoColor', '--no-term-title','--no-banner',
143 '--autocall=0']
145 '--autocall=0']
144
146
145
147
146 def default_config():
148 def default_config():
147 """Return a config object with good defaults for testing."""
149 """Return a config object with good defaults for testing."""
148 config = Config()
150 config = Config()
149 config.TerminalInteractiveShell.colors = 'NoColor'
151 config.TerminalInteractiveShell.colors = 'NoColor'
150 config.TerminalTerminalInteractiveShell.term_title = False,
152 config.TerminalTerminalInteractiveShell.term_title = False,
151 config.TerminalInteractiveShell.autocall = 0
153 config.TerminalInteractiveShell.autocall = 0
152 config.HistoryManager.hist_file = tempfile.mktemp(u'test_hist.sqlite')
154 config.HistoryManager.hist_file = tempfile.mktemp(u'test_hist.sqlite')
153 config.HistoryManager.db_cache_size = 10000
155 config.HistoryManager.db_cache_size = 10000
154 return config
156 return config
155
157
156
158
157 def get_ipython_cmd(as_string=False):
159 def get_ipython_cmd(as_string=False):
158 """
160 """
159 Return appropriate IPython command line name. By default, this will return
161 Return appropriate IPython command line name. By default, this will return
160 a list that can be used with subprocess.Popen, for example, but passing
162 a list that can be used with subprocess.Popen, for example, but passing
161 `as_string=True` allows for returning the IPython command as a string.
163 `as_string=True` allows for returning the IPython command as a string.
162
164
163 Parameters
165 Parameters
164 ----------
166 ----------
165 as_string: bool
167 as_string: bool
166 Flag to allow to return the command as a string.
168 Flag to allow to return the command as a string.
167 """
169 """
168 ipython_cmd = [sys.executable, "-m", "IPython"]
170 ipython_cmd = [sys.executable, "-m", "IPython"]
169
171
170 if as_string:
172 if as_string:
171 ipython_cmd = " ".join(ipython_cmd)
173 ipython_cmd = " ".join(ipython_cmd)
172
174
173 return ipython_cmd
175 return ipython_cmd
174
176
175 def ipexec(fname, options=None):
177 def ipexec(fname, options=None):
176 """Utility to call 'ipython filename'.
178 """Utility to call 'ipython filename'.
177
179
178 Starts IPython with a minimal and safe configuration to make startup as fast
180 Starts IPython with a minimal and safe configuration to make startup as fast
179 as possible.
181 as possible.
180
182
181 Note that this starts IPython in a subprocess!
183 Note that this starts IPython in a subprocess!
182
184
183 Parameters
185 Parameters
184 ----------
186 ----------
185 fname : str
187 fname : str
186 Name of file to be executed (should have .py or .ipy extension).
188 Name of file to be executed (should have .py or .ipy extension).
187
189
188 options : optional, list
190 options : optional, list
189 Extra command-line flags to be passed to IPython.
191 Extra command-line flags to be passed to IPython.
190
192
191 Returns
193 Returns
192 -------
194 -------
193 (stdout, stderr) of ipython subprocess.
195 (stdout, stderr) of ipython subprocess.
194 """
196 """
195 if options is None: options = []
197 if options is None: options = []
196
198
197 # For these subprocess calls, eliminate all prompt printing so we only see
199 # For these subprocess calls, eliminate all prompt printing so we only see
198 # output from script execution
200 # output from script execution
199 prompt_opts = [ '--PromptManager.in_template=""',
201 prompt_opts = [ '--PromptManager.in_template=""',
200 '--PromptManager.in2_template=""',
202 '--PromptManager.in2_template=""',
201 '--PromptManager.out_template=""'
203 '--PromptManager.out_template=""'
202 ]
204 ]
203 cmdargs = default_argv() + prompt_opts + options
205 cmdargs = default_argv() + prompt_opts + options
204
206
205 test_dir = os.path.dirname(__file__)
207 test_dir = os.path.dirname(__file__)
206
208
207 ipython_cmd = get_ipython_cmd()
209 ipython_cmd = get_ipython_cmd()
208 # Absolute path for filename
210 # Absolute path for filename
209 full_fname = os.path.join(test_dir, fname)
211 full_fname = os.path.join(test_dir, fname)
210 full_cmd = ipython_cmd + cmdargs + [full_fname]
212 full_cmd = ipython_cmd + cmdargs + [full_fname]
211 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE)
213 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE)
212 out, err = p.communicate()
214 out, err = p.communicate()
213 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
215 out, err = py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
214 # `import readline` causes 'ESC[?1034h' to be output sometimes,
216 # `import readline` causes 'ESC[?1034h' to be output sometimes,
215 # so strip that out before doing comparisons
217 # so strip that out before doing comparisons
216 if out:
218 if out:
217 out = re.sub(r'\x1b\[[^h]+h', '', out)
219 out = re.sub(r'\x1b\[[^h]+h', '', out)
218 return out, err
220 return out, err
219
221
220
222
221 def ipexec_validate(fname, expected_out, expected_err='',
223 def ipexec_validate(fname, expected_out, expected_err='',
222 options=None):
224 options=None):
223 """Utility to call 'ipython filename' and validate output/error.
225 """Utility to call 'ipython filename' and validate output/error.
224
226
225 This function raises an AssertionError if the validation fails.
227 This function raises an AssertionError if the validation fails.
226
228
227 Note that this starts IPython in a subprocess!
229 Note that this starts IPython in a subprocess!
228
230
229 Parameters
231 Parameters
230 ----------
232 ----------
231 fname : str
233 fname : str
232 Name of the file to be executed (should have .py or .ipy extension).
234 Name of the file to be executed (should have .py or .ipy extension).
233
235
234 expected_out : str
236 expected_out : str
235 Expected stdout of the process.
237 Expected stdout of the process.
236
238
237 expected_err : optional, str
239 expected_err : optional, str
238 Expected stderr of the process.
240 Expected stderr of the process.
239
241
240 options : optional, list
242 options : optional, list
241 Extra command-line flags to be passed to IPython.
243 Extra command-line flags to be passed to IPython.
242
244
243 Returns
245 Returns
244 -------
246 -------
245 None
247 None
246 """
248 """
247
249
248 import nose.tools as nt
250 import nose.tools as nt
249
251
250 out, err = ipexec(fname, options)
252 out, err = ipexec(fname, options)
251 #print 'OUT', out # dbg
253 #print 'OUT', out # dbg
252 #print 'ERR', err # dbg
254 #print 'ERR', err # dbg
253 # If there are any errors, we must check those befor stdout, as they may be
255 # If there are any errors, we must check those befor stdout, as they may be
254 # more informative than simply having an empty stdout.
256 # more informative than simply having an empty stdout.
255 if err:
257 if err:
256 if expected_err:
258 if expected_err:
257 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
259 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
258 else:
260 else:
259 raise ValueError('Running file %r produced error: %r' %
261 raise ValueError('Running file %r produced error: %r' %
260 (fname, err))
262 (fname, err))
261 # If no errors or output on stderr was expected, match stdout
263 # If no errors or output on stderr was expected, match stdout
262 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
264 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
263
265
264
266
265 class TempFileMixin(object):
267 class TempFileMixin(object):
266 """Utility class to create temporary Python/IPython files.
268 """Utility class to create temporary Python/IPython files.
267
269
268 Meant as a mixin class for test cases."""
270 Meant as a mixin class for test cases."""
269
271
270 def mktmp(self, src, ext='.py'):
272 def mktmp(self, src, ext='.py'):
271 """Make a valid python temp file."""
273 """Make a valid python temp file."""
272 fname, f = temp_pyfile(src, ext)
274 fname, f = temp_pyfile(src, ext)
273 self.tmpfile = f
275 self.tmpfile = f
274 self.fname = fname
276 self.fname = fname
275
277
276 def tearDown(self):
278 def tearDown(self):
277 if hasattr(self, 'tmpfile'):
279 if hasattr(self, 'tmpfile'):
278 # If the tmpfile wasn't made because of skipped tests, like in
280 # If the tmpfile wasn't made because of skipped tests, like in
279 # win32, there's nothing to cleanup.
281 # win32, there's nothing to cleanup.
280 self.tmpfile.close()
282 self.tmpfile.close()
281 try:
283 try:
282 os.unlink(self.fname)
284 os.unlink(self.fname)
283 except:
285 except:
284 # On Windows, even though we close the file, we still can't
286 # On Windows, even though we close the file, we still can't
285 # delete it. I have no clue why
287 # delete it. I have no clue why
286 pass
288 pass
287
289
288 pair_fail_msg = ("Testing {0}\n\n"
290 pair_fail_msg = ("Testing {0}\n\n"
289 "In:\n"
291 "In:\n"
290 " {1!r}\n"
292 " {1!r}\n"
291 "Expected:\n"
293 "Expected:\n"
292 " {2!r}\n"
294 " {2!r}\n"
293 "Got:\n"
295 "Got:\n"
294 " {3!r}\n")
296 " {3!r}\n")
295 def check_pairs(func, pairs):
297 def check_pairs(func, pairs):
296 """Utility function for the common case of checking a function with a
298 """Utility function for the common case of checking a function with a
297 sequence of input/output pairs.
299 sequence of input/output pairs.
298
300
299 Parameters
301 Parameters
300 ----------
302 ----------
301 func : callable
303 func : callable
302 The function to be tested. Should accept a single argument.
304 The function to be tested. Should accept a single argument.
303 pairs : iterable
305 pairs : iterable
304 A list of (input, expected_output) tuples.
306 A list of (input, expected_output) tuples.
305
307
306 Returns
308 Returns
307 -------
309 -------
308 None. Raises an AssertionError if any output does not match the expected
310 None. Raises an AssertionError if any output does not match the expected
309 value.
311 value.
310 """
312 """
311 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
313 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
312 for inp, expected in pairs:
314 for inp, expected in pairs:
313 out = func(inp)
315 out = func(inp)
314 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
316 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
315
317
316
318
317 if py3compat.PY3:
319 if py3compat.PY3:
318 MyStringIO = StringIO
320 MyStringIO = StringIO
319 else:
321 else:
320 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
322 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
321 # so we need a class that can handle both.
323 # so we need a class that can handle both.
322 class MyStringIO(StringIO):
324 class MyStringIO(StringIO):
323 def write(self, s):
325 def write(self, s):
324 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
326 s = py3compat.cast_unicode(s, encoding=DEFAULT_ENCODING)
325 super(MyStringIO, self).write(s)
327 super(MyStringIO, self).write(s)
326
328
327 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
329 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
328 -------
330 -------
329 {2!s}
331 {2!s}
330 -------
332 -------
331 """
333 """
332
334
333 class AssertPrints(object):
335 class AssertPrints(object):
334 """Context manager for testing that code prints certain text.
336 """Context manager for testing that code prints certain text.
335
337
336 Examples
338 Examples
337 --------
339 --------
338 >>> with AssertPrints("abc", suppress=False):
340 >>> with AssertPrints("abc", suppress=False):
339 ... print "abcd"
341 ... print "abcd"
340 ... print "def"
342 ... print "def"
341 ...
343 ...
342 abcd
344 abcd
343 def
345 def
344 """
346 """
345 def __init__(self, s, channel='stdout', suppress=True):
347 def __init__(self, s, channel='stdout', suppress=True):
346 self.s = s
348 self.s = s
347 self.channel = channel
349 self.channel = channel
348 self.suppress = suppress
350 self.suppress = suppress
349
351
350 def __enter__(self):
352 def __enter__(self):
351 self.orig_stream = getattr(sys, self.channel)
353 self.orig_stream = getattr(sys, self.channel)
352 self.buffer = MyStringIO()
354 self.buffer = MyStringIO()
353 self.tee = Tee(self.buffer, channel=self.channel)
355 self.tee = Tee(self.buffer, channel=self.channel)
354 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
356 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
355
357
356 def __exit__(self, etype, value, traceback):
358 def __exit__(self, etype, value, traceback):
357 self.tee.flush()
359 self.tee.flush()
358 setattr(sys, self.channel, self.orig_stream)
360 setattr(sys, self.channel, self.orig_stream)
359 printed = self.buffer.getvalue()
361 printed = self.buffer.getvalue()
360 assert self.s in printed, notprinted_msg.format(self.s, self.channel, printed)
362 assert self.s in printed, notprinted_msg.format(self.s, self.channel, printed)
361 return False
363 return False
362
364
363 printed_msg = """Found {0!r} in printed output (on {1}):
365 printed_msg = """Found {0!r} in printed output (on {1}):
364 -------
366 -------
365 {2!s}
367 {2!s}
366 -------
368 -------
367 """
369 """
368
370
369 class AssertNotPrints(AssertPrints):
371 class AssertNotPrints(AssertPrints):
370 """Context manager for checking that certain output *isn't* produced.
372 """Context manager for checking that certain output *isn't* produced.
371
373
372 Counterpart of AssertPrints"""
374 Counterpart of AssertPrints"""
373 def __exit__(self, etype, value, traceback):
375 def __exit__(self, etype, value, traceback):
374 self.tee.flush()
376 self.tee.flush()
375 setattr(sys, self.channel, self.orig_stream)
377 setattr(sys, self.channel, self.orig_stream)
376 printed = self.buffer.getvalue()
378 printed = self.buffer.getvalue()
377 assert self.s not in printed, printed_msg.format(self.s, self.channel, printed)
379 assert self.s not in printed, printed_msg.format(self.s, self.channel, printed)
378 return False
380 return False
379
381
380 @contextmanager
382 @contextmanager
381 def mute_warn():
383 def mute_warn():
382 from IPython.utils import warn
384 from IPython.utils import warn
383 save_warn = warn.warn
385 save_warn = warn.warn
384 warn.warn = lambda *a, **kw: None
386 warn.warn = lambda *a, **kw: None
385 try:
387 try:
386 yield
388 yield
387 finally:
389 finally:
388 warn.warn = save_warn
390 warn.warn = save_warn
389
391
390 @contextmanager
392 @contextmanager
391 def make_tempfile(name):
393 def make_tempfile(name):
392 """ Create an empty, named, temporary file for the duration of the context.
394 """ Create an empty, named, temporary file for the duration of the context.
393 """
395 """
394 f = open(name, 'w')
396 f = open(name, 'w')
395 f.close()
397 f.close()
396 try:
398 try:
397 yield
399 yield
398 finally:
400 finally:
399 os.unlink(name)
401 os.unlink(name)
400
402
401
403
402 @contextmanager
404 @contextmanager
403 def monkeypatch(obj, name, attr):
405 def monkeypatch(obj, name, attr):
404 """
406 """
405 Context manager to replace attribute named `name` in `obj` with `attr`.
407 Context manager to replace attribute named `name` in `obj` with `attr`.
406 """
408 """
407 orig = getattr(obj, name)
409 orig = getattr(obj, name)
408 setattr(obj, name, attr)
410 setattr(obj, name, attr)
409 yield
411 yield
410 setattr(obj, name, orig)
412 setattr(obj, name, orig)
413
414
415 def help_output_test(subcommand=''):
416 """test that `ipython [subcommand] -h` works"""
417 cmd = ' '.join(get_ipython_cmd() + [subcommand, '-h'])
418 out, err, rc = get_output_error_code(cmd)
419 nt.assert_equal(rc, 0, err)
420 nt.assert_not_in("Traceback", err)
421 nt.assert_in("Options", out)
422 nt.assert_in("--help-all", out)
423 return out, err
424
425
426 def help_all_output_test(subcommand=''):
427 """test that `ipython [subcommand] --help-all` works"""
428 cmd = ' '.join(get_ipython_cmd() + [subcommand, '--help-all'])
429 out, err, rc = get_output_error_code(cmd)
430 nt.assert_equal(rc, 0, err)
431 nt.assert_not_in("Traceback", err)
432 nt.assert_in("Options", out)
433 nt.assert_in("Class parameters", out)
434 return out, err
435
436
437 def help(cmd=''):
438 """decorator for making a test for `ipython cmd -h`"""
439 def wrap_help_test(f):
440 def test_help_output():
441 out, err = help_output_test(cmd)
442 if inspect.getargspec(f).args:
443 return f(out, err)
444 else:
445 return f()
446 cmds = cmd + ' ' if cmd else ''
447 test_help_output.__doc__ = "ipython {cmds}--help-all works".format(cmds=cmds)
448
449 return test_help_output
450 return wrap_help_test
451
452
453 def help_all(cmd=''):
454 """decorator for making a test for `ipython [cmd] --help-all`"""
455 def wrap_help_test(f):
456 def test_help_output():
457 out, err = help_all_output_test(cmd)
458 if inspect.getargspec(f).args:
459 return f(out, err)
460 else:
461 return f()
462 cmds = cmd + ' ' if cmd else ''
463 test_help_output.__doc__ = "ipython {cmds}--help-all works".format(cmds=cmds)
464 return test_help_output
465 return wrap_help_test
General Comments 0
You need to be logged in to leave comments. Login now