Commit c34abdc0 authored by Jason Madden's avatar Jason Madden

Let tests run without having gevent installed, just on pythonpath. Fixes #1409

parent c0c91a5d
...@@ -117,7 +117,10 @@ class BaseServer(object): ...@@ -117,7 +117,10 @@ class BaseServer(object):
# XXX: FIXME: Subclasses rely on the presence or absence of the # XXX: FIXME: Subclasses rely on the presence or absence of the
# `socket` attribute to determine whether we are open/should be opened. # `socket` attribute to determine whether we are open/should be opened.
# Instead, have it be None. # Instead, have it be None.
self.pool = None # XXX: In general, the state management here is confusing. Lots of stuff is
# deferred until the various ``set_`` methods are called, and it's not documented
# when it's safe to call those
self.pool = None # can be set from ``spawn``; overrides self.full()
try: try:
self.set_listener(listener) self.set_listener(listener)
self.set_spawn(spawn) self.set_spawn(spawn)
...@@ -250,9 +253,9 @@ class BaseServer(object): ...@@ -250,9 +253,9 @@ class BaseServer(object):
self.delay = min(self.max_delay, self.delay * 2) self.delay = min(self.max_delay, self.delay * 2)
break break
def full(self): def full(self): # pylint: disable=method-hidden
# copied from self.pool # If a Pool is given for to ``set_spawn`` (the *spawn* argument
# pylint: disable=method-hidden # of the constructor) it will replace this method.
return False return False
def __repr__(self): def __repr__(self):
......
...@@ -101,6 +101,7 @@ def log(message, *args, **kwargs): ...@@ -101,6 +101,7 @@ def log(message, *args, **kwargs):
:keyword str color: One of the values from _colorscheme :keyword str color: One of the values from _colorscheme
""" """
with output_lock: # pylint:disable=not-context-manager
color = kwargs.pop('color', 'normal') color = kwargs.pop('color', 'normal')
try: try:
if args: if args:
...@@ -192,6 +193,8 @@ def kill(popen): ...@@ -192,6 +193,8 @@ def kill(popen):
IGNORED_GEVENT_ENV_KEYS = { IGNORED_GEVENT_ENV_KEYS = {
'GEVENTTEST_QUIET', 'GEVENTTEST_QUIET',
'GEVENT_DEBUG', 'GEVENT_DEBUG',
'GEVENTSETUP_EV_VERIFY',
'GEVENTSETUP_EMBED',
} }
# A set of (name, value) pairs we ignore for printing purposes. # A set of (name, value) pairs we ignore for printing purposes.
...@@ -236,10 +239,7 @@ def start(command, quiet=False, **kwargs): ...@@ -236,10 +239,7 @@ def start(command, quiet=False, **kwargs):
if preexec_fn is not None: if preexec_fn is not None:
setenv['DO_NOT_SETPGRP'] = '1' setenv['DO_NOT_SETPGRP'] = '1'
if setenv: if setenv:
if env: env = env.copy() if env else os.environ.copy()
env = env.copy()
else:
env = os.environ.copy()
env.update(setenv) env.update(setenv)
if not quiet: if not quiet:
...@@ -272,16 +272,22 @@ class RunResult(object): ...@@ -272,16 +272,22 @@ class RunResult(object):
command, command,
run_kwargs, run_kwargs,
code, code,
output=None, name=None, output=None, # type: str
error=None, # type: str
name=None,
run_count=0, skipped_count=0): run_count=0, skipped_count=0):
self.command = command self.command = command
self.run_kwargs = run_kwargs self.run_kwargs = run_kwargs
self.code = code self.code = code
self.output = output self.output = output
self.error = error
self.name = name self.name = name
self.run_count = run_count self.run_count = run_count
self.skipped_count = skipped_count self.skipped_count = skipped_count
@property
def output_lines(self):
return self.output.splitlines()
def __bool__(self): def __bool__(self):
return not bool(self.code) return not bool(self.code)
...@@ -291,6 +297,27 @@ class RunResult(object): ...@@ -291,6 +297,27 @@ class RunResult(object):
def __int__(self): def __int__(self):
return self.code return self.code
def __repr__(self):
return (
"RunResult of: %r\n"
"Code: %s\n"
"kwargs: %r\n"
"Output:\n"
"----\n"
"%s"
"----\n"
"Error:\n"
"----\n"
"%s"
"----\n"
) % (
self.command,
self.code,
self.run_kwargs,
self.output,
self.error
)
def _should_show_warning_output(out): def _should_show_warning_output(out):
if 'Warning' in out: if 'Warning' in out:
...@@ -310,6 +337,8 @@ def _should_show_warning_output(out): ...@@ -310,6 +337,8 @@ def _should_show_warning_output(out):
out = out.replace('UserWarning: libuv only supports', 'NADA') out = out.replace('UserWarning: libuv only supports', 'NADA')
# Packages on Python 2 # Packages on Python 2
out = out.replace('ImportWarning: Not importing directory', 'NADA') out = out.replace('ImportWarning: Not importing directory', 'NADA')
# Testing that U mode does the same thing
out = out.replace("DeprecationWarning: 'U' mode is deprecated", 'NADA')
return 'Warning' in out return 'Warning' in out
output_lock = threading.Lock() output_lock = threading.Lock()
...@@ -337,7 +366,11 @@ def _find_test_status(took, out): ...@@ -337,7 +366,11 @@ def _find_test_status(took, out):
def run(command, **kwargs): # pylint:disable=too-many-locals def run(command, **kwargs): # pylint:disable=too-many-locals
"Execute *command*, returning a `RunResult`" """
Execute *command*, returning a `RunResult`.
This blocks until *command* finishes or until it times out.
"""
buffer_output = kwargs.pop('buffer_output', BUFFER_OUTPUT) buffer_output = kwargs.pop('buffer_output', BUFFER_OUTPUT)
quiet = kwargs.pop('quiet', QUIET) quiet = kwargs.pop('quiet', QUIET)
verbose = not quiet verbose = not quiet
...@@ -348,6 +381,7 @@ def run(command, **kwargs): # pylint:disable=too-many-locals ...@@ -348,6 +381,7 @@ def run(command, **kwargs): # pylint:disable=too-many-locals
kwargs['stdout'] = subprocess.PIPE kwargs['stdout'] = subprocess.PIPE
popen = start(command, quiet=nested, **kwargs) popen = start(command, quiet=nested, **kwargs)
name = popen.name name = popen.name
try: try:
time_start = time.time() time_start = time.time()
out, err = popen.communicate() out, err = popen.communicate()
...@@ -358,14 +392,13 @@ def run(command, **kwargs): # pylint:disable=too-many-locals ...@@ -358,14 +392,13 @@ def run(command, **kwargs): # pylint:disable=too-many-locals
result = popen.poll() result = popen.poll()
finally: finally:
kill(popen) kill(popen)
assert not err
with output_lock: # pylint:disable=not-context-manager
failed = bool(result) failed = bool(result)
if out: if out:
out = out.strip() out = out.strip()
out = out if isinstance(out, str) else out.decode('utf-8', 'ignore') out = out if isinstance(out, str) else out.decode('utf-8', 'ignore')
if out and (failed or verbose or _should_show_warning_output(out)): if out and (failed or verbose or _should_show_warning_output(out)):
if out:
out = ' ' + out.replace('\n', '\n ') out = ' ' + out.replace('\n', '\n ')
out = out.rstrip() out = out.rstrip()
out += '\n' out += '\n'
...@@ -377,8 +410,13 @@ def run(command, **kwargs): # pylint:disable=too-many-locals ...@@ -377,8 +410,13 @@ def run(command, **kwargs): # pylint:disable=too-many-locals
log('- %s %s', name, status) log('- %s %s', name, status)
if took >= MIN_RUNTIME: if took >= MIN_RUNTIME:
runtimelog.append((-took, name)) runtimelog.append((-took, name))
return RunResult(command, kwargs, result, return RunResult(
output=out, name=name, run_count=run_count, skipped_count=skipped_count) command, kwargs, result,
output=out, error=err,
name=name,
run_count=run_count,
skipped_count=skipped_count
)
class NoSetupPyFound(Exception): class NoSetupPyFound(Exception):
...@@ -453,8 +491,33 @@ def find_stdlib_tests(): ...@@ -453,8 +491,33 @@ def find_stdlib_tests():
return directory, full_directory return directory, full_directory
def absolute_pythonpath():
"""
Return the PYTHONPATH environment variable (if set) with each
entry being an absolute path. If not set, returns None.
"""
if 'PYTHONPATH' not in os.environ:
return None
path = os.environ['PYTHONPATH']
path = [os.path.abspath(p) for p in path.split(os.path.pathsep)]
return os.path.pathsep.join(path)
class ExampleMixin(object): class ExampleMixin(object):
"Something that uses the examples/ directory" """
Something that uses the ``examples/`` directory
from the root of the gevent distribution.
The `cwd` property is set to the root of the gevent distribution.
"""
#: Arguments to pass to the example file.
example_args = []
before_delay = 3
after_delay = 0.5
#: Path of the example Python file, relative to `cwd`
example = None # subclasses define this to be the path to the server.py
#: Keyword arguments to pass to the start or run method.
start_kwargs = None
def find_setup_py(self): def find_setup_py(self):
"Return the directory containing setup.py" "Return the directory containing setup.py"
...@@ -469,31 +532,64 @@ class ExampleMixin(object): ...@@ -469,31 +532,64 @@ class ExampleMixin(object):
root = self.find_setup_py() root = self.find_setup_py()
except NoSetupPyFound as e: except NoSetupPyFound as e:
raise unittest.SkipTest("Unable to locate file/dir to run: %s" % (e,)) raise unittest.SkipTest("Unable to locate file/dir to run: %s" % (e,))
return os.path.join(root, 'examples') return os.path.join(root, 'examples')
class TestServer(ExampleMixin, @property
unittest.TestCase): def setenv(self):
args = [] """
before_delay = 3 Returns a dictionary of environment variables to set for the
after_delay = 0.5 child in addition to (or replacing) the ones already in the
popen = None environment.
server = None # subclasses define this to be the path to the server.py
start_kwargs = None Since the child is run in `cwd`, relative paths in ``PYTHONPATH``
need to be converted to absolute paths.
"""
abs_pythonpath = absolute_pythonpath()
return {'PYTHONPATH': abs_pythonpath} if abs_pythonpath else None
def _start(self, meth):
if getattr(self, 'args', None):
raise AssertionError("Invalid test", self, self.args)
if getattr(self, 'server', None):
raise AssertionError("Invalid test", self, self.server)
def start(self):
try: try:
kwargs = self.start_kwargs or {} # These could be or are properties that can raise
return start([sys.executable, '-u', self.server] + self.args, cwd=self.cwd, **kwargs) server = self.example
server_dir = self.cwd
except NoSetupPyFound as e: except NoSetupPyFound as e:
raise unittest.SkipTest("Unable to locate file/dir to run: %s" % (e,)) raise unittest.SkipTest("Unable to locate file/dir to run: %s" % (e,))
kwargs = self.start_kwargs or {}
setenv = self.setenv
if setenv:
if 'setenv' in kwargs:
kwargs['setenv'].update(setenv)
else:
kwargs['setenv'] = setenv
return meth(
[sys.executable, '-W', 'ignore', '-u', server] + self.example_args,
cwd=server_dir,
**kwargs
)
def start_example(self):
return self._start(meth=start)
def run_example(self):# run() is a unittest method.
return self._start(meth=run)
class TestServer(ExampleMixin,
unittest.TestCase):
popen = None
def running_server(self): def running_server(self):
from contextlib import contextmanager from contextlib import contextmanager
@contextmanager @contextmanager
def running_server(): def running_server():
with self.start() as popen: with self.start_example() as popen:
self.popen = popen self.popen = popen
self.before() self.before()
yield yield
...@@ -507,12 +603,18 @@ class TestServer(ExampleMixin, ...@@ -507,12 +603,18 @@ class TestServer(ExampleMixin,
def before(self): def before(self):
if self.before_delay is not None: if self.before_delay is not None:
time.sleep(self.before_delay) time.sleep(self.before_delay)
assert self.popen.poll() is None, '%s died with code %s' % (self.server, self.popen.poll(), ) self.assertIsNone(self.popen.poll(),
'%s died with code %s' % (
self.example, self.popen.poll(),
))
def after(self): def after(self):
if self.after_delay is not None: if self.after_delay is not None:
time.sleep(self.after_delay) time.sleep(self.after_delay)
assert self.popen.poll() is None, '%s died with code %s' % (self.server, self.popen.poll(), ) self.assertIsNone(self.popen.poll(),
'%s died with code %s' % (
self.example, self.popen.poll(),
))
def _run_all_tests(self): def _run_all_tests(self):
ran = False ran = False
......
...@@ -6,7 +6,7 @@ from gevent.testing import util ...@@ -6,7 +6,7 @@ from gevent.testing import util
from gevent.testing import params from gevent.testing import params
class Test(util.TestServer): class Test(util.TestServer):
server = 'echoserver.py' example = 'echoserver.py'
def _run_all_tests(self): def _run_all_tests(self):
def test_client(message): def test_client(message):
......
...@@ -13,9 +13,9 @@ from gevent.testing import util ...@@ -13,9 +13,9 @@ from gevent.testing import util
@greentest.skipOnLibuvOnCIOnPyPy("Timing issues sometimes lead to connection refused") @greentest.skipOnLibuvOnCIOnPyPy("Timing issues sometimes lead to connection refused")
class Test(util.TestServer): class Test(util.TestServer):
server = 'portforwarder.py' example = 'portforwarder.py'
# [listen on, forward to] # [listen on, forward to]
args = ['127.0.0.1:10011', '127.0.0.1:10012'] example_args = ['127.0.0.1:10011', '127.0.0.1:10012']
if greentest.WIN: if greentest.WIN:
from subprocess import CREATE_NEW_PROCESS_GROUP from subprocess import CREATE_NEW_PROCESS_GROUP
...@@ -40,7 +40,7 @@ class Test(util.TestServer): ...@@ -40,7 +40,7 @@ class Test(util.TestServer):
break break
log.append(data) log.append(data)
server = StreamServer(self.args[1], handle) server = StreamServer(self.example_args[1], handle)
server.start() server.start()
try: try:
conn = socket.create_connection(('127.0.0.1', 10011)) conn = socket.create_connection(('127.0.0.1', 10011))
......
from gevent import monkey from gevent import monkey
monkey.patch_all(subprocess=True) monkey.patch_all(subprocess=True)
import sys
from gevent.server import DatagramServer from gevent.server import DatagramServer
from gevent.testing.util import run
from gevent.testing import util from gevent.testing import util
from gevent.testing import main from gevent.testing import main
class Test_udp_client(util.TestServer): class Test_udp_client(util.TestServer):
start_kwargs = {'timeout': 10}
example = 'udp_client.py'
example_args = ['Test_udp_client']
def test(self): def test(self):
log = [] log = []
...@@ -20,8 +23,7 @@ class Test_udp_client(util.TestServer): ...@@ -20,8 +23,7 @@ class Test_udp_client(util.TestServer):
server = DatagramServer('127.0.0.1:9001', handle) server = DatagramServer('127.0.0.1:9001', handle)
server.start() server.start()
try: try:
run([sys.executable, '-W', 'ignore', '-u', 'udp_client.py', 'Test_udp_client'], self.run_example()
timeout=10, cwd=self.cwd)
finally: finally:
server.close() server.close()
self.assertEqual(log, [b'Test_udp_client']) self.assertEqual(log, [b'Test_udp_client'])
......
...@@ -5,7 +5,7 @@ from gevent.testing import main ...@@ -5,7 +5,7 @@ from gevent.testing import main
class Test(util.TestServer): class Test(util.TestServer):
server = 'udp_server.py' example = 'udp_server.py'
def _run_all_tests(self): def _run_all_tests(self):
sock = socket.socket(type=socket.SOCK_DGRAM) sock = socket.socket(type=socket.SOCK_DGRAM)
......
...@@ -9,7 +9,7 @@ from . import test__example_wsgiserver ...@@ -9,7 +9,7 @@ from . import test__example_wsgiserver
@greentest.skipOnCI("Timing issues sometimes lead to a connection refused") @greentest.skipOnCI("Timing issues sometimes lead to a connection refused")
@greentest.skipWithoutExternalNetwork("Tries to reach google.com") @greentest.skipWithoutExternalNetwork("Tries to reach google.com")
class Test_webproxy(test__example_wsgiserver.Test_wsgiserver): class Test_webproxy(test__example_wsgiserver.Test_wsgiserver):
server = 'webproxy.py' example = 'webproxy.py'
def _run_all_tests(self): def _run_all_tests(self):
status, data = self.read('/') status, data = self.read('/')
......
...@@ -16,7 +16,7 @@ from gevent.testing import params ...@@ -16,7 +16,7 @@ from gevent.testing import params
@greentest.skipOnCI("Timing issues sometimes lead to a connection refused") @greentest.skipOnCI("Timing issues sometimes lead to a connection refused")
class Test_wsgiserver(util.TestServer): class Test_wsgiserver(util.TestServer):
server = 'wsgiserver.py' example = 'wsgiserver.py'
URL = 'http://%s:8088' % (params.DEFAULT_LOCAL_HOST_ADDR,) URL = 'http://%s:8088' % (params.DEFAULT_LOCAL_HOST_ADDR,)
PORT = 8088 PORT = 8088
not_found_message = b'<h1>Not Found</h1>' not_found_message = b'<h1>Not Found</h1>'
......
...@@ -9,7 +9,7 @@ from . import test__example_wsgiserver ...@@ -9,7 +9,7 @@ from . import test__example_wsgiserver
@greentest.skipOnCI("Timing issues sometimes lead to a connection refused") @greentest.skipOnCI("Timing issues sometimes lead to a connection refused")
class Test_wsgiserver_ssl(test__example_wsgiserver.Test_wsgiserver): class Test_wsgiserver_ssl(test__example_wsgiserver.Test_wsgiserver):
server = 'wsgiserver_ssl.py' example = 'wsgiserver_ssl.py'
URL = 'https://%s:8443' % (params.DEFAULT_LOCAL_HOST_ADDR,) URL = 'https://%s:8443' % (params.DEFAULT_LOCAL_HOST_ADDR,)
PORT = 8443 PORT = 8443
_use_ssl = True _use_ssl = True
......
...@@ -11,7 +11,6 @@ most commonly the resource will be ``network``. You can use this technique to sp ...@@ -11,7 +11,6 @@ most commonly the resource will be ``network``. You can use this technique to sp
non-existant resources for things that should never be tested. non-existant resources for things that should never be tested.
""" """
import re import re
import sys
import os import os
import glob import glob
import time import time
...@@ -45,12 +44,12 @@ time_ranges = { ...@@ -45,12 +44,12 @@ time_ranges = {
class _AbstractTestMixin(util.ExampleMixin): class _AbstractTestMixin(util.ExampleMixin):
time_range = default_time_range time_range = default_time_range
filename = None example = None
def _check_resources(self): def _check_resources(self):
from gevent.testing import resources from gevent.testing import resources
with open(os.path.join(self.cwd, self.filename), 'r') as f: with open(os.path.join(self.cwd, self.example), 'r') as f:
contents = f.read() contents = f.read()
pattern = re.compile('^# gevent-test-requires-resource: (.*)$', re.MULTILINE) pattern = re.compile('^# gevent-test-requires-resource: (.*)$', re.MULTILINE)
...@@ -64,14 +63,15 @@ class _AbstractTestMixin(util.ExampleMixin): ...@@ -64,14 +63,15 @@ class _AbstractTestMixin(util.ExampleMixin):
start = time.time() start = time.time()
min_time, max_time = self.time_range min_time, max_time = self.time_range
if not util.run([sys.executable, '-u', self.filename], self.start_kwargs = {
timeout=max_time, 'timeout': max_time,
cwd=self.cwd, 'quiet': True,
quiet=True, 'buffer_output': True,
buffer_output=True, 'nested': True,
nested=True, 'setenv': {'GEVENT_DEBUG': 'error'}
setenv={'GEVENT_DEBUG': 'error'}): }
self.fail("Failed example: " + self.filename) if not self.run_example():
self.fail("Failed example: " + self.example)
else: else:
took = time.time() - start took = time.time() - start
self.assertGreaterEqual(took, min_time) self.assertGreaterEqual(took, min_time)
...@@ -94,7 +94,7 @@ def _build_test_classes(): ...@@ -94,7 +94,7 @@ def _build_test_classes():
'Test_' + bn, 'Test_' + bn,
(_AbstractTestMixin, greentest.TestCase), (_AbstractTestMixin, greentest.TestCase),
{ {
'filename': bn, 'example': bn,
'time_range': time_ranges.get(bn, _AbstractTestMixin.time_range) 'time_range': time_ranges.get(bn, _AbstractTestMixin.time_range)
} }
) )
......
...@@ -13,15 +13,15 @@ import os ...@@ -13,15 +13,15 @@ import os
import os.path import os.path
import sys import sys
from subprocess import Popen
from subprocess import PIPE
from gevent import testing as greentest from gevent import testing as greentest
from gevent.testing.util import absolute_pythonpath
from gevent.testing.util import run
class TestRun(greentest.TestCase): class TestRun(greentest.TestCase):
maxDiff = None maxDiff = None
def setUp(self): def setUp(self):
self.abs_pythonpath = absolute_pythonpath() # before we cd
self.cwd = os.getcwd() self.cwd = os.getcwd()
os.chdir(os.path.dirname(__file__)) os.chdir(os.path.dirname(__file__))
...@@ -31,29 +31,42 @@ class TestRun(greentest.TestCase): ...@@ -31,29 +31,42 @@ class TestRun(greentest.TestCase):
def _run(self, script, module=False): def _run(self, script, module=False):
env = os.environ.copy() env = os.environ.copy()
env['PYTHONWARNINGS'] = 'ignore' env['PYTHONWARNINGS'] = 'ignore'
if self.abs_pythonpath:
env['PYTHONPATH'] = self.abs_pythonpath
run_kwargs = dict(
buffer_output=True,
quiet=True,
nested=True,
env=env,
timeout=10,
)
args = [sys.executable, '-m', 'gevent.monkey'] args = [sys.executable, '-m', 'gevent.monkey']
if module: if module:
args.append('--module') args.append('--module')
args += [script, 'patched'] args += [script, 'patched']
p = Popen(args, stdout=PIPE, stderr=PIPE, env=env) monkey_result = run(
monkey_out, monkey_err = p.communicate() args,
self.assertEqual(0, p.returncode, (p.returncode, monkey_out, monkey_err)) **run_kwargs
)
self.assertTrue(monkey_result)
if module: if module:
args = [sys.executable, "-m", script, 'stdlib'] args = [sys.executable, "-m", script, 'stdlib']
else: else:
args = [sys.executable, script, 'stdlib'] args = [sys.executable, script, 'stdlib']
p = Popen(args, stdout=PIPE, stderr=PIPE) std_result = run(
args,
std_out, std_err = p.communicate() **run_kwargs
self.assertEqual(0, p.returncode, (p.returncode, std_out, std_err)) )
self.assertTrue(std_result)
monkey_out_lines = monkey_out.decode("utf-8").splitlines()
std_out_lines = std_out.decode('utf-8').splitlines() monkey_out_lines = monkey_result.output_lines
std_out_lines = std_result.output_lines
self.assertEqual(monkey_out_lines, std_out_lines) self.assertEqual(monkey_out_lines, std_out_lines)
self.assertEqual(monkey_err, std_err) self.assertEqual(monkey_result.error, std_result.error)
return monkey_out_lines, monkey_err return monkey_out_lines, monkey_result.error
def test_run_simple(self): def test_run_simple(self):
self._run(os.path.join('monkey_package', 'script.py')) self._run(os.path.join('monkey_package', 'script.py'))
...@@ -61,8 +74,8 @@ class TestRun(greentest.TestCase): ...@@ -61,8 +74,8 @@ class TestRun(greentest.TestCase):
def _run_package(self, module): def _run_package(self, module):
lines, _ = self._run('monkey_package', module=module) lines, _ = self._run('monkey_package', module=module)
self.assertTrue(lines[0].endswith('__main__.py'), lines[0]) self.assertTrue(lines[0].endswith(u'__main__.py'), lines[0])
self.assertEqual(lines[1], '__main__') self.assertEqual(lines[1].strip(), u'__main__')
def test_run_package(self): def test_run_package(self):
# Run a __main__ inside a package, even without specifying -m # Run a __main__ inside a package, even without specifying -m
...@@ -75,10 +88,10 @@ class TestRun(greentest.TestCase): ...@@ -75,10 +88,10 @@ class TestRun(greentest.TestCase):
def test_issue_302(self): def test_issue_302(self):
lines, _ = self._run(os.path.join('monkey_package', 'issue302monkey.py')) lines, _ = self._run(os.path.join('monkey_package', 'issue302monkey.py'))
self.assertEqual(lines[0], 'True') self.assertEqual(lines[0].strip(), u'True')
lines[1] = lines[1].replace('\\', '/') # windows path lines[1] = lines[1].replace(u'\\', u'/') # windows path
self.assertEqual(lines[1], 'monkey_package/issue302monkey.py') self.assertEqual(lines[1].strip(), u'monkey_package/issue302monkey.py')
self.assertEqual(lines[2], 'True', lines) self.assertEqual(lines[2].strip(), u'True', lines)
# These three tests all sometimes fail on Py2 on CI, writing # These three tests all sometimes fail on Py2 on CI, writing
# to stderr: # to stderr:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment