pubs/tests/fake_env.py
Olivier Mangin de2a50eeb2 Fix tests and terminology.
First this brings a change to the paper API: the terminology of bibdata
and bibentry is clarified: now bibentry is a dictionary of the form
{citekey: bibdata} where bibdata corresponds to the actual dictionary of
bibliographic fields and values {author: ..., year: ...}.
Now bibentry is an attribute of the paper object that is generated from
citekey and bibdata.

This commit fixes all tests in particular an issue with citekey in
bibentry not updated.

Also removes prints in tests and deprecated assertEquals.

Usecase tests now fail if the command ask for unexpected inputs.

Removes queries for user input in attach and add commands (for deletion
of a copied document file). The input was not coherent with tests and is
annoying.
2015-05-07 13:17:44 +02:00

240 lines
6.4 KiB
Python

import sys
import io
import os
import shutil
import glob
import unittest
import dotdot
import fake_filesystem
import fake_filesystem_shutil
import fake_filesystem_glob
from pubs.p3 import input, _fake_stdio, _get_fake_stdio_ucontent
from pubs import content, filebroker
# code for fake fs
real_os = os
real_open = open
real_shutil = shutil
real_glob = glob
real_io = io
# def _mod_list():
# ml = []
# import pubs
# for importer, modname, ispkg in pkgutil.walk_packages(
# path=pubs.__path__,
# prefix=pubs.__name__ + '.',
# onerror=lambda x: None):
# # HACK to not load textnote
# if not modname.startswith('pubs.plugs.texnote'):
# ml.append((modname, __import__(modname, fromlist='dummy')))
# return ml
ENCODING = 'utf8'
class UnicodeStringIOWrapper(object):
"""This is a hack because fake_filesystem does not provide mock of io.
"""
override = ['read', 'readline', 'readlines', 'write', 'writelines']
def __init__(self, strio):
self._strio = strio # The real StringIO
def __getattr__(self, name):
if name in UnicodeStringIOWrapper.override:
return object.__getattribute__(self, name)
else:
return self._strio.__getattribute__(name)
def __iter__(self):
for l in self.readlines():
yield l
def read(self, *args):
return self._strio.read(*args).decode(ENCODING)
def readline(self, *args):
return self._strio.readline(*args).decode(ENCODING)
def readlines(self, *args):
return [l.decode(ENCODING) for l in self._strio.readlines(*args)]
def write(self, data):
self._strio.write(data.encode(ENCODING))
def writelines(self, data):
self._strio.write([l.encode(ENCODING) for l in data])
def __enter__(self):
self._strio.__enter__()
return self
def __exit__(self, *args):
return self._strio.__exit__(*args)
def _force_binary_mode(mode):
if 'b' in mode:
raise ValueError('Open should not happen in binary mode.')
return mode + 'b'
class FakeIO(object):
def __init__(self, fake_open):
self.fake_open = fake_open
def open(self, *args, **kwargs):
# Forces binary mode for FakeFileOpen
args = list(args)
if len(args) > 1:
args[1] = _force_binary_mode(args[1])
else:
kwargs['mode'] = _force_binary_mode(kwargs.get('mode', 'r'))
fakefs_stringio = self.fake_open.Call(*args, **kwargs)
return UnicodeStringIOWrapper(fakefs_stringio)
def create_fake_fs(module_list):
fake_fs = fake_filesystem.FakeFilesystem()
fake_os = fake_filesystem.FakeOsModule(fake_fs)
fake_open = fake_filesystem.FakeFileOpen(fake_fs)
fake_shutil = fake_filesystem_shutil.FakeShutilModule(fake_fs)
fake_glob = fake_filesystem_glob.FakeGlobModule(fake_fs)
fake_io = FakeIO(fake_open)
fake_fs.CreateDirectory(fake_os.path.expanduser('~'))
sys.modules['os'] = fake_os
sys.modules['shutil'] = fake_shutil
sys.modules['glob'] = fake_glob
sys.modules['io'] = fake_io
for md in module_list:
md.os = fake_os
md.shutil = fake_shutil
md.open = fake_open
md.file = None
md.io = fake_io
return {'fs': fake_fs,
'os': fake_os,
'open': fake_open,
'io': fake_io,
'shutil': fake_shutil,
'glob': fake_glob}
def unset_fake_fs(module_list):
try:
__builtins__.open = real_open
except AttributeError:
__builtins__['open'] = real_open
sys.modules['os'] = real_os
sys.modules['shutil'] = real_shutil
sys.modules['glob'] = real_glob
sys.modules['io'] = real_io
for md in module_list:
md.os = real_os
md.shutil = real_shutil
md.open = real_open
md.io = real_io
def copy_dir(fs, real_dir, fake_dir = None):
"""Copy all the data directory into the fake fs"""
if fake_dir is None:
fake_dir = real_dir
for filename in real_os.listdir(real_dir):
real_path = os.path.abspath(real_os.path.join(real_dir, filename))
fake_path = fs['os'].path.join(fake_dir, filename)
if real_os.path.isfile(real_path):
with real_open(real_path, 'rb') as f:
fs['fs'].CreateFile(fake_path, contents=f.read())
if real_os.path.isdir(real_path):
fs['fs'].CreateDirectory(fake_path)
copy_dir(fs, real_path, fake_path)
# redirecting output
def redirect(f):
def newf(*args, **kwargs):
old_stderr, old_stdout = sys.stderr, sys.stdout
stdout = _fake_stdio()
stderr = _fake_stdio()
sys.stdout, sys.stderr = stdout, stderr
try:
return f(*args, **kwargs), _get_fake_stdio_ucontent(stdout), _get_fake_stdio_ucontent(stderr)
finally:
sys.stderr, sys.stdout = old_stderr, old_stdout
return newf
# Test helpers
# automating input
real_input = input
class FakeInput():
""" Replace the input() command, and mock user input during tests
Instanciate as :
input = FakeInput(['yes', 'no'])
then replace the input command in every module of the package :
input.as_global()
Then :
input() returns 'yes'
input() returns 'no'
input() raises IndexError
"""
class UnexpectedInput(Exception):
pass
def __init__(self, inputs, module_list=tuple()):
self.inputs = list(inputs) or []
self.module_list = module_list
self._cursor = 0
def as_global(self):
for md in self.module_list:
md.input = self
md.editor_input = self
# if mdname.endswith('files'):
# md.editor_input = self
def add_input(self, inp):
self.inputs.append(inp)
def __call__(self, *args, **kwargs):
try:
inp = self.inputs[self._cursor]
self._cursor += 1
return inp
except IndexError:
raise self.UnexpectedInput('Unexpected user input in test.')
class TestFakeFs(unittest.TestCase):
"""Abstract TestCase intializing the fake filesystem."""
def setUp(self):
self.fs = create_fake_fs([content, filebroker])
def tearDown(self):
unset_fake_fs([content, filebroker])