487 lines
17 KiB
Python
487 lines
17 KiB
Python
|
|
||
|
""" tests document generation
|
||
|
"""
|
||
|
|
||
|
import py
|
||
|
from StringIO import StringIO
|
||
|
|
||
|
from py.__.apigen.rest.genrest import ViewVC, RestGen, PipeWriter, \
|
||
|
DirWriter, FileWriter, \
|
||
|
DirectPaste, DirectFS, \
|
||
|
HTMLDirWriter, SourceView
|
||
|
from py.__.apigen.tracer.tracer import Tracer
|
||
|
from py.__.apigen.tracer.docstorage import DocStorage, DocStorageAccessor
|
||
|
from py.__.apigen.tracer.permastore import PermaDocStorage
|
||
|
import pickle
|
||
|
|
||
|
from py.__.apigen.tracer.testing.runtest import cut_pyc
|
||
|
from py.__.doc.conftest import genlinkchecks
|
||
|
from py.__.rest.rst import Rest, Paragraph
|
||
|
from py.__.rest.transform import HTMLHandler
|
||
|
# XXX: UUuuuuuuuuuuuuuuuuuuuuuuu, dangerous import
|
||
|
|
||
|
sorted = py.builtin.sorted
|
||
|
|
||
|
def _nl(s):
|
||
|
"""normalize newlines (converting to \n)"""
|
||
|
s = s.replace('\r\n', '\n')
|
||
|
s = s.replace('\r', '\n')
|
||
|
return s
|
||
|
|
||
|
def setup_module(mod):
|
||
|
mod.temppath = py.test.ensuretemp('restgen')
|
||
|
|
||
|
def fun_():
|
||
|
pass
|
||
|
|
||
|
class SomeClass(object):
|
||
|
"""Some class definition"""
|
||
|
|
||
|
def __init__(self, a):
|
||
|
self.a = a
|
||
|
|
||
|
def method(self, a, b, c):
|
||
|
"""method docstring"""
|
||
|
return a + b + c
|
||
|
|
||
|
class SomeSubClass(SomeClass):
|
||
|
"""Some subclass definition"""
|
||
|
|
||
|
def fun(a, b, c):
|
||
|
"""Some docstring
|
||
|
|
||
|
Let's make it span a couple of lines to be interesting...
|
||
|
|
||
|
Note:
|
||
|
|
||
|
* rest
|
||
|
* should
|
||
|
* be
|
||
|
* supported
|
||
|
* or
|
||
|
* ignored...
|
||
|
"""
|
||
|
return "d"
|
||
|
|
||
|
def test_direct_link():
|
||
|
fname = cut_pyc(__file__)
|
||
|
title, link = DirectPaste().getlink(fname, 2, "")
|
||
|
assert title == '%s:%s' % (fname, 2)
|
||
|
assert link == ''
|
||
|
|
||
|
def test_viewvc_link():
|
||
|
vcview = ViewVC("http://codespeak.net/viewvc/")
|
||
|
fname = cut_pyc(__file__)
|
||
|
title, link = vcview.getlink(fname, 0, "")
|
||
|
assert title == '%s:%s' % (fname, 0)
|
||
|
assert link == ('http://codespeak.net/viewvc/py/apigen/rest/'
|
||
|
'testing/test_rest.py?view=markup')
|
||
|
|
||
|
def test_fs_link():
|
||
|
title, link = DirectFS().getlink('/foo/bar/baz.py', 100, "func")
|
||
|
assert title == '/foo/bar/baz.py:100'
|
||
|
assert link == 'file:///foo/bar/baz.py'
|
||
|
|
||
|
class WriterTest(object):
|
||
|
def get_filled_writer(self, writerclass, *args, **kwargs):
|
||
|
dw = writerclass(*args, **kwargs)
|
||
|
dw.write_section('foo', Rest(Paragraph('foo data')))
|
||
|
dw.write_section('bar', Rest(Paragraph('bar data')))
|
||
|
return dw
|
||
|
|
||
|
class TestDirWriter(WriterTest):
|
||
|
def test_write_section(self):
|
||
|
tempdir = temppath.ensure('dirwriter', dir=True)
|
||
|
dw = self.get_filled_writer(DirWriter, tempdir)
|
||
|
fpaths = tempdir.listdir('*.txt')
|
||
|
assert len(fpaths) == 2
|
||
|
assert sorted([f.basename for f in fpaths]) == ['bar.txt', 'foo.txt']
|
||
|
assert _nl(tempdir.join('foo.txt').read()) == 'foo data\n'
|
||
|
assert _nl(tempdir.join('bar.txt').read()) == 'bar data\n'
|
||
|
|
||
|
def test_getlink(self):
|
||
|
dw = DirWriter(temppath.join('dirwriter_getlink'))
|
||
|
link = dw.getlink('function', 'Foo.bar', 'method_foo_bar')
|
||
|
assert link == 'method_foo_bar.html'
|
||
|
|
||
|
class TestFileWriter(WriterTest):
|
||
|
def test_write_section(self):
|
||
|
tempfile = temppath.ensure('filewriter', file=True)
|
||
|
fw = self.get_filled_writer(FileWriter, tempfile)
|
||
|
data = tempfile.read()
|
||
|
assert len(data)
|
||
|
|
||
|
def test_getlink(self):
|
||
|
fw = FileWriter(temppath.join('filewriter_getlink'))
|
||
|
link = fw.getlink('function', 'Foo.bar', 'method_foo_bar')
|
||
|
assert link == '#function-foo-bar'
|
||
|
# only produce the same link target once...
|
||
|
link = fw.getlink('function', 'Foo.bar', 'method_foo_bar')
|
||
|
assert link is None
|
||
|
link = fw.getlink('function', 'Foo.__init__', 'method_foo___init__')
|
||
|
assert link == '#function-foo-init'
|
||
|
|
||
|
class TestPipeWriter(WriterTest):
|
||
|
def test_write_section(self):
|
||
|
s = StringIO()
|
||
|
pw = self.get_filled_writer(PipeWriter, s)
|
||
|
data = s.getvalue()
|
||
|
assert len(data)
|
||
|
|
||
|
def test_getlink(self):
|
||
|
pw = PipeWriter(StringIO())
|
||
|
link = pw.getlink('function', 'Foo.bar', 'method_foo_bar')
|
||
|
assert link == 'method_foo_bar.txt'
|
||
|
|
||
|
class TestHTMLDirWriter(WriterTest):
|
||
|
def test_write_section(self):
|
||
|
tempdir = temppath.ensure('htmldirwriter', dir=1)
|
||
|
hdw = self.get_filled_writer(HTMLDirWriter, HTMLHandler, HTMLHandler,
|
||
|
tempdir)
|
||
|
assert tempdir.join('foo.html').check(file=1)
|
||
|
assert tempdir.join('bar.html').check(file=1)
|
||
|
assert tempdir.join('foo.html').read().startswith('<html>')
|
||
|
|
||
|
class TestRest(object):
|
||
|
def get_filled_docstorage(self):
|
||
|
descs = {'SomeClass': SomeClass,
|
||
|
'SomeSubClass': SomeSubClass,
|
||
|
'fun':fun}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
s1 = SomeClass("a")
|
||
|
fun(1, 2, s1)
|
||
|
s2 = SomeSubClass("b")
|
||
|
s2.method(1,2,3)
|
||
|
fun(1, 3, s2)
|
||
|
t.end_tracing()
|
||
|
return DocStorageAccessor(ds)
|
||
|
|
||
|
def get_filled_docstorage_modules(self):
|
||
|
import somemodule
|
||
|
import someothermodule
|
||
|
descs = {
|
||
|
'somemodule.SomeClass': somemodule.SomeClass,
|
||
|
'someothermodule.SomeSubClass': someothermodule.SomeSubClass,
|
||
|
'someothermodule.fun': someothermodule.fun,
|
||
|
}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
s1 = somemodule.SomeClass("a")
|
||
|
someothermodule.fun(1, 2, s1)
|
||
|
s2 = someothermodule.SomeSubClass("b")
|
||
|
s2.method(1, 2, 3)
|
||
|
someothermodule.fun(1, 3, s2)
|
||
|
t.end_tracing()
|
||
|
return DocStorageAccessor(ds)
|
||
|
|
||
|
def check_rest(self, tempdir):
|
||
|
from py.__.misc import rest
|
||
|
for path in tempdir.listdir('*.txt'):
|
||
|
try:
|
||
|
rest.process(path)
|
||
|
except ImportError:
|
||
|
py.test.skip('skipping rest generation because docutils is '
|
||
|
'not installed (this is a partial skip, the rest '
|
||
|
'of the test was successful)')
|
||
|
for path in tempdir.listdir('*.txt'):
|
||
|
for item, arg1, arg2, arg3 in genlinkchecks(path):
|
||
|
item(arg1, arg2, arg3)
|
||
|
|
||
|
def test_generation_simple_api(self):
|
||
|
ds = self.get_filled_docstorage()
|
||
|
lg = DirectPaste()
|
||
|
tempdir = temppath.ensure("simple_api", dir=True)
|
||
|
r = RestGen(ds, lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
basenames = [p.basename for p in tempdir.listdir('*.txt')]
|
||
|
expected = [
|
||
|
'class_SomeClass.txt',
|
||
|
'class_SomeSubClass.txt',
|
||
|
'function_fun.txt',
|
||
|
'index.txt',
|
||
|
'method_SomeClass.__init__.txt',
|
||
|
'method_SomeClass.method.txt',
|
||
|
'method_SomeSubClass.__init__.txt',
|
||
|
'method_SomeSubClass.method.txt',
|
||
|
'module_Unknown module.txt',
|
||
|
'traceback_SomeClass.__init__.0.txt',
|
||
|
'traceback_SomeSubClass.__init__.0.txt',
|
||
|
'traceback_SomeSubClass.method.0.txt',
|
||
|
'traceback_fun.0.txt',
|
||
|
'traceback_fun.1.txt',
|
||
|
]
|
||
|
print sorted(basenames)
|
||
|
assert sorted(basenames) == expected
|
||
|
# now we check out...
|
||
|
self.check_rest(tempdir)
|
||
|
tempdir = temppath.ensure("simple_api_ps", dir=True)
|
||
|
if 0:
|
||
|
ps = PermaDocStorage(ds)
|
||
|
r = RestGen(ps, lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
basenames = [p.basename for p in tempdir.listdir('*.txt')]
|
||
|
assert sorted(basenames) == expected
|
||
|
self.check_rest(tempdir)
|
||
|
pickle.dumps(ps)
|
||
|
|
||
|
def test_generation_modules(self):
|
||
|
ds = self.get_filled_docstorage_modules()
|
||
|
lg = DirectPaste()
|
||
|
tempdir = temppath.ensure('module_api', dir=True)
|
||
|
r = RestGen(ds, lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
basenames = [p.basename for p in tempdir.listdir('*.txt')]
|
||
|
expected = [
|
||
|
'class_somemodule.SomeClass.txt',
|
||
|
'class_someothermodule.SomeSubClass.txt',
|
||
|
'function_someothermodule.fun.txt',
|
||
|
'index.txt',
|
||
|
'method_somemodule.SomeClass.__init__.txt',
|
||
|
'method_somemodule.SomeClass.method.txt',
|
||
|
'method_someothermodule.SomeSubClass.__init__.txt',
|
||
|
'method_someothermodule.SomeSubClass.method.txt',
|
||
|
'module_Unknown module.txt',
|
||
|
'module_somemodule.txt',
|
||
|
'module_someothermodule.txt',
|
||
|
'traceback_somemodule.SomeClass.__init__.0.txt',
|
||
|
'traceback_someothermodule.SomeSubClass.__init__.0.txt',
|
||
|
'traceback_someothermodule.SomeSubClass.method.0.txt',
|
||
|
'traceback_someothermodule.fun.0.txt',
|
||
|
'traceback_someothermodule.fun.1.txt',
|
||
|
]
|
||
|
print sorted(basenames)
|
||
|
assert sorted(basenames) == expected
|
||
|
|
||
|
def test_check_internal_links(self):
|
||
|
ds = self.get_filled_docstorage()
|
||
|
lg = DirectFS()
|
||
|
tempdir = temppath.ensure('internal_links', dir=True)
|
||
|
r = RestGen(ds, lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
index = tempdir.join('module_Unknown module.txt')
|
||
|
assert index.check(file=True)
|
||
|
data = _nl(index.read())
|
||
|
assert data.find('.. _`fun`: function_fun.html\n') > -1
|
||
|
assert data.find('.. _`fun`: #function-fun\n') == -1
|
||
|
|
||
|
tempfile = temppath.ensure('internal_links.txt',
|
||
|
file=True)
|
||
|
r = RestGen(ds, lg, FileWriter(tempfile))
|
||
|
r.write()
|
||
|
data = _nl(tempfile.read())
|
||
|
assert data.find('.. _`fun`: #function-fun\n') > -1
|
||
|
assert data.find('.. _`fun`: function_fun.html') == -1
|
||
|
tempfile = temppath.ensure("internal_links_ps.txt", file=True)
|
||
|
if 0:
|
||
|
ps = PermaDocStorage(ds)
|
||
|
r = RestGen(ps, lg, FileWriter(tempfile))
|
||
|
r.write()
|
||
|
data = _nl(tempfile.read())
|
||
|
assert data.find('.. _`fun`: #function-fun\n') > -1
|
||
|
assert data.find('.. _`fun`: function_fun.html') == -1
|
||
|
pickle.dumps(ps)
|
||
|
|
||
|
def test_check_section_order(self):
|
||
|
# we use the previous method's data
|
||
|
tempfile = temppath.join('internal_links.txt')
|
||
|
if not tempfile.check():
|
||
|
py.test.skip('depends on previous test, which failed')
|
||
|
data = _nl(tempfile.read())
|
||
|
# index should be above the rest
|
||
|
assert data.find('classes\\:') > -1
|
||
|
assert data.find('classes\\:') < data.find('function\\: fun')
|
||
|
assert data.find('classes\\:') < data.find(
|
||
|
'class\\: SomeClass')
|
||
|
# function definitions should be above class ones
|
||
|
assert data.find('function\\: fun') > data.find('class\\: SomeClass')
|
||
|
# class method definitions should be below the class defs
|
||
|
assert data.find('class\\: SomeClass') < data.find(
|
||
|
'method\\: SomeClass.method')
|
||
|
# __init__ should be above other methods
|
||
|
assert data.find('method\\: SomeClass.\\_\\_init\\_\\_') > -1
|
||
|
assert data.find('method\\: SomeClass.\\_\\_init\\_\\_') < data.find(
|
||
|
'method\\: SomeClass.method')
|
||
|
# base class info
|
||
|
assert py.std.re.search(r'class\\\: SomeSubClass.*'
|
||
|
r'base classes\\\:\n\^+[\n ]+\* `SomeClass`_.*'
|
||
|
r'`SomeSubClass.__init__',
|
||
|
data, py.std.re.S)
|
||
|
|
||
|
def test_som_fun(self):
|
||
|
descs = {'fun_': fun_}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
fun_()
|
||
|
t.end_tracing()
|
||
|
lg = DirectPaste()
|
||
|
tempdir = temppath.ensure("some_fun", dir=True)
|
||
|
r = RestGen(DocStorageAccessor(ds), lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
self.check_rest(tempdir)
|
||
|
|
||
|
def test_function_source(self):
|
||
|
def blah():
|
||
|
a = 3
|
||
|
b = 4
|
||
|
return a + b
|
||
|
|
||
|
descs = {'blah': blah}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
blah()
|
||
|
t.end_tracing()
|
||
|
lg = DirectPaste()
|
||
|
tempdir = temppath.ensure("function_source", dir=True)
|
||
|
r = RestGen(DocStorageAccessor(ds), lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
assert tempdir.join("function_blah.txt").read().find("a = 3") != -1
|
||
|
self.check_rest(tempdir)
|
||
|
ps = DocStorageAccessor(ds)
|
||
|
r = RestGen(ps, lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
assert tempdir.join("function_blah.txt").read().find("a = 3") != -1
|
||
|
|
||
|
def test_function_arguments(self):
|
||
|
def blah(a, b, c):
|
||
|
return "axx"
|
||
|
|
||
|
class C:
|
||
|
pass
|
||
|
|
||
|
descs = {'blah':blah}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
blah(3, "x", C())
|
||
|
t.end_tracing()
|
||
|
lg = DirectPaste()
|
||
|
tempdir = temppath.ensure("function_args", dir=True)
|
||
|
r = RestGen(DocStorageAccessor(ds), lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
source = tempdir.join("function_blah.txt").read()
|
||
|
call_point = source.find("call sites\:")
|
||
|
assert call_point != -1
|
||
|
assert source.find("a \:\: <Int>") < call_point
|
||
|
assert source.find("b \:\: <String>") < call_point
|
||
|
assert source.find("c \:\: <Instance of Class C>") < call_point
|
||
|
self.check_rest(tempdir)
|
||
|
|
||
|
def test_class_typedefs(self):
|
||
|
class A(object):
|
||
|
def __init__(self, x):
|
||
|
pass
|
||
|
|
||
|
def a(self):
|
||
|
pass
|
||
|
|
||
|
class B(A):
|
||
|
def __init__(self, y):
|
||
|
pass
|
||
|
|
||
|
def xxx(x):
|
||
|
return x
|
||
|
|
||
|
descs = {'A': A, 'B': B, 'xxx':xxx}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
xxx(A(3))
|
||
|
xxx(B("f"))
|
||
|
t.end_tracing()
|
||
|
lg = DirectPaste()
|
||
|
tempdir = temppath.ensure("classargs", dir=True)
|
||
|
r = RestGen(DocStorageAccessor(ds), lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
source = tempdir.join("function_xxx.txt").read()
|
||
|
call_point = source.find("call sites\:")
|
||
|
assert call_point != -1
|
||
|
print source
|
||
|
assert -1 < source.find("x \:\: <Instance of AnyOf( `Class B`_ , "
|
||
|
"`Class A`_ )>") < call_point
|
||
|
source = tempdir.join('method_B.a.txt').read()
|
||
|
assert source.find('**origin** \: `A`_') > -1
|
||
|
self.check_rest(tempdir)
|
||
|
|
||
|
def test_exc_raising(self):
|
||
|
def x():
|
||
|
try:
|
||
|
1/0
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
descs = {'x':x}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
x()
|
||
|
t.end_tracing()
|
||
|
lg = DirectPaste()
|
||
|
tempdir = temppath.ensure("exc_raising", dir=True)
|
||
|
r = RestGen(DocStorageAccessor(ds), lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
source = tempdir.join('function_x.txt').open().read()
|
||
|
assert source.find('ZeroDivisionError') < source.find('call sites\:')
|
||
|
|
||
|
|
||
|
def test_nonexist_origin(self):
|
||
|
class A:
|
||
|
def method(self):
|
||
|
pass
|
||
|
|
||
|
class B(A):
|
||
|
pass
|
||
|
|
||
|
descs = {'B':B}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
B().method()
|
||
|
t.end_tracing()
|
||
|
lg = DirectPaste()
|
||
|
tempdir = temppath.ensure("nonexit_origin", dir=True)
|
||
|
r = RestGen(DocStorageAccessor(ds), lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
self.check_rest(tempdir)
|
||
|
|
||
|
def test_sourceview(self):
|
||
|
class A:
|
||
|
def method(self):
|
||
|
pass
|
||
|
|
||
|
descs = {'A':A}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
A().method()
|
||
|
t.end_tracing()
|
||
|
lg = SourceView('http://localhost:8000')
|
||
|
tempdir = temppath.ensure("sourceview", dir=True)
|
||
|
r = RestGen(DocStorageAccessor(ds), lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
self.check_rest(tempdir)
|
||
|
assert tempdir.join('traceback_A.method.0.txt').open().read().find(
|
||
|
'.. _`/py/apigen/rest/testing/test\_rest.py\:A.method`: http://localhost:8000/py/apigen/rest/testing/test_rest.py#A.method') != -1
|
||
|
|
||
|
def test_sourceview_fun(self):
|
||
|
def f():
|
||
|
pass
|
||
|
|
||
|
descs = {'f':f}
|
||
|
ds = DocStorage().from_dict(descs)
|
||
|
t = Tracer(ds)
|
||
|
t.start_tracing()
|
||
|
f()
|
||
|
t.end_tracing()
|
||
|
tempdir = temppath.ensure("sourceview_fun", dir=True)
|
||
|
lg = SourceView('http://localhost:8000')
|
||
|
r = RestGen(DocStorageAccessor(ds), lg, DirWriter(tempdir))
|
||
|
r.write()
|
||
|
self.check_rest(tempdir)
|
||
|
assert tempdir.join('function_f.txt').open().read().find(
|
||
|
'.. _`/py/apigen/rest/testing/test\_rest.py\:f`: http://localhost:8000/py/apigen/rest/testing/test_rest.py#f') != -1
|