summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Th?nault <sylvain.thenault@logilab.fr>2013-12-20 15:12:50 +0100
committerSylvain Th?nault <sylvain.thenault@logilab.fr>2013-12-20 15:12:50 +0100
commitf24227aae012740653e8708379b7e9c22f938400 (patch)
treed334468d560e36f3c2cf04d16da386e3e108c05e
parent7ecac59ebc534e869a772efa6dbd973fb8843f44 (diff)
downloadpylint-f24227aae012740653e8708379b7e9c22f938400.tar.gz
[pyreverse] more refactoring to get actually predicable results (take 2)
simplify pyreverse related test code on the way.
-rw-r--r--pyreverse/diagrams.py12
-rw-r--r--pyreverse/writer.py13
-rw-r--r--test/data/classes_No_Name.dot16
-rw-r--r--test/data/packages_No_Name.dot8
-rw-r--r--test/unittest_pyreverse_diadefs.py25
-rw-r--r--test/unittest_pyreverse_writer.py106
-rw-r--r--test/utils.py98
7 files changed, 113 insertions, 165 deletions
diff --git a/pyreverse/diagrams.py b/pyreverse/diagrams.py
index a53427a..288ce0f 100644
--- a/pyreverse/diagrams.py
+++ b/pyreverse/diagrams.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2004-2012 LOGILAB S.A. (Paris, FRANCE).
+# Copyright (c) 2004-2013 LOGILAB S.A. (Paris, FRANCE).
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This program is free software; you can redistribute it and/or modify it under
@@ -19,16 +19,8 @@
import astroid
from pylint.pyreverse.utils import is_interface, FilterMixIn
-def set_counter(value):
- """Figure counter (re)set"""
- Figure._UID_COUNT = value
-
-class Figure:
+class Figure(object):
"""base class for counter handling"""
- _UID_COUNT = 0
- def __init__(self):
- Figure._UID_COUNT += 1
- self.fig_id = Figure._UID_COUNT
class Relationship(Figure):
"""a relation ship from an object in the diagram to another
diff --git a/pyreverse/writer.py b/pyreverse/writer.py
index b41deb6..446d6d6 100644
--- a/pyreverse/writer.py
+++ b/pyreverse/writer.py
@@ -45,9 +45,9 @@ class DiagramWriter(object):
def write_packages(self, diagram):
"""write a package diagram"""
# sorted to get predictable (hence testable) results
- for label, obj in sorted( (self.get_title(obj), obj)
- for obj in diagram.modules() ):
- self.printer.emit_node(obj.fig_id, label=label, shape='box')
+ for i, obj in enumerate(sorted(diagram.modules(), key=lambda x: x.title)):
+ self.printer.emit_node(i, label=self.get_title(obj), shape='box')
+ obj.fig_id = i
# package dependencies
for rel in diagram.get_relationships('depends'):
self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
@@ -56,8 +56,9 @@ class DiagramWriter(object):
def write_classes(self, diagram):
"""write a class diagram"""
# sorted to get predictable (hence testable) results
- for obj in sorted(diagram.objects, key=lambda x: x.fig_id):
- self.printer.emit_node(obj.fig_id, **self.get_values(obj) )
+ for i, obj in enumerate(sorted(diagram.objects, key=lambda x: x.title)):
+ self.printer.emit_node(i, **self.get_values(obj) )
+ obj.fig_id = i
# inheritance links
for rel in diagram.get_relationships('specialization'):
self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
@@ -116,7 +117,7 @@ class DotWriter(DiagramWriter):
The label contains all attributes and methods
"""
- label = obj.title
+ label = obj.title
if obj.shape == 'interface':
label = u"«interface»\\n%s" % label
if not self.config.only_classnames:
diff --git a/test/data/classes_No_Name.dot b/test/data/classes_No_Name.dot
index ba4fa08..e75553e 100644
--- a/test/data/classes_No_Name.dot
+++ b/test/data/classes_No_Name.dot
@@ -1,12 +1,12 @@
digraph "classes_No_Name" {
charset="utf-8"
rankdir=BT
-"4" [label="{Ancestor|attr : str\lcls_member\l|set_value()\lget_value()\l}", shape="record"];
-"5" [label="{Specialization|relation\ltop : str\lTYPE : str\l|}", shape="record"];
-"8" [label="{«interface»\nInterface|\l|get_value()\lset_value()\l}", shape="record"];
-"9" [label="{DoNothing|\l|}", shape="record"];
-"5" -> "4" [arrowhead="empty", arrowtail="none"];
-"4" -> "8" [arrowhead="empty", arrowtail="node", style="dashed"];
-"9" -> "4" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="cls_member", style="solid"];
-"9" -> "5" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="relation", style="solid"];
+"0" [label="{Ancestor|attr : str\lcls_member\l|set_value()\lget_value()\l}", shape="record"];
+"1" [label="{DoNothing|\l|}", shape="record"];
+"2" [label="{«interface»\nInterface|\l|get_value()\lset_value()\l}", shape="record"];
+"3" [label="{Specialization|relation\ltop : str\lTYPE : str\l|}", shape="record"];
+"3" -> "0" [arrowhead="empty", arrowtail="none"];
+"0" -> "2" [arrowhead="empty", arrowtail="node", style="dashed"];
+"1" -> "0" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="cls_member", style="solid"];
+"1" -> "3" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="relation", style="solid"];
}
diff --git a/test/data/packages_No_Name.dot b/test/data/packages_No_Name.dot
index dba6ac2..1ceeb72 100644
--- a/test/data/packages_No_Name.dot
+++ b/test/data/packages_No_Name.dot
@@ -1,8 +1,8 @@
digraph "packages_No_Name" {
charset="utf-8"
rankdir=BT
-"6" [label="data", shape="box"];
-"3" [label="data.clientmodule_test", shape="box"];
-"7" [label="data.suppliermodule_test", shape="box"];
-"3" -> "7" [arrowhead="open", arrowtail="none"];
+"0" [label="data", shape="box"];
+"1" [label="data.clientmodule_test", shape="box"];
+"2" [label="data.suppliermodule_test", shape="box"];
+"1" -> "2" [arrowhead="open", arrowtail="none"];
}
diff --git a/test/unittest_pyreverse_diadefs.py b/test/unittest_pyreverse_diadefs.py
index ebcf371..a42d73a 100644
--- a/test/unittest_pyreverse_diadefs.py
+++ b/test/unittest_pyreverse_diadefs.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2000-2004 LOGILAB S.A. (Paris, FRANCE).
+# Copyright (c) 2000-2013 LOGILAB S.A. (Paris, FRANCE).
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This program is free software; you can redistribute it and/or modify it under
@@ -26,15 +26,10 @@ from astroid.inspector import Linker
from pylint.pyreverse.diadefslib import *
-from utils import Config
+from unittest_pyreverse_writer import Config, get_project
-def astroid_wrapper(func, modname):
- return func(modname)
-
-PROJECT = MANAGER.project_from_files(['data'], astroid_wrapper)
-
-CONFIG = Config()
-HANDLER = DiadefsHandler(CONFIG)
+PROJECT = get_project('data')
+HANDLER = DiadefsHandler(Config())
def _process_classes(classes):
"""extract class names of a list"""
@@ -43,7 +38,7 @@ def _process_classes(classes):
def _process_relations(relations):
"""extract relation indices from a relation list"""
result = []
- for rel_type, rels in relations.iteritems():
+ for rel_type, rels in relations.iteritems():
for rel in rels:
result.append( (rel_type, rel.from_object.title,
rel.to_object.title) )
@@ -54,7 +49,7 @@ def _process_relations(relations):
class DiaDefGeneratorTC(unittest.TestCase):
def test_option_values(self):
"""test for ancestor, associated and module options"""
- handler = DiadefsHandler( Config())
+ handler = DiadefsHandler(Config())
df_h = DiaDefGenerator(Linker(PROJECT), handler)
cl_config = Config()
cl_config.classes = ['Specialization']
@@ -125,15 +120,15 @@ class DefaultDiadefGeneratorTC(unittest.TestCase):
different classes possibly in different modules"""
# XXX should be catching pyreverse environnement problem but doesn't
# pyreverse doesn't extracts the relations but this test ok
- project = MANAGER.project_from_files(['data'], astroid_wrapper)
- handler = DiadefsHandler( Config() )
+ project = get_project('data')
+ handler = DiadefsHandler(Config())
diadefs = handler.get_diadefs(project, Linker(project, tag=True) )
cd = diadefs[1]
relations = _process_relations(cd.relationships)
self.assertEqual(relations, self._should_rels)
def test_known_values2(self):
- project = MANAGER.project_from_files(['data.clientmodule_test'], astroid_wrapper)
+ project = get_project('data.clientmodule_test')
dd = DefaultDiadefGenerator(Linker(project), HANDLER).visit(project)
self.assertEqual(len(dd), 1)
keys = [d.TYPE for d in dd]
@@ -158,7 +153,7 @@ class ClassDiadefGeneratorTC(unittest.TestCase):
(True, special),
(True, 'data.suppliermodule_test.DoNothing'),
])
-
+
def test_known_values2(self):
HANDLER.config.module_names = False
cd = ClassDiadefGenerator(Linker(PROJECT), HANDLER).class_diagram(PROJECT, 'data.clientmodule_test.Specialization')
diff --git a/test/unittest_pyreverse_writer.py b/test/unittest_pyreverse_writer.py
index 5d4e4e3..b850679 100644
--- a/test/unittest_pyreverse_writer.py
+++ b/test/unittest_pyreverse_writer.py
@@ -17,39 +17,96 @@
unittest for visitors.diadefs and extensions.diadefslib modules
"""
-from os.path import abspath, dirname, join
-from astroid.inspector import Linker
+
+import os
+import sys
+import codecs
+from os.path import join, dirname, abspath
+from difflib import unified_diff
+
from logilab.common.testlib import TestCase, unittest_main
+from astroid import MANAGER
+from astroid.inspector import Linker
+
from pylint.pyreverse.diadefslib import DefaultDiadefGenerator, DiadefsHandler
-from pylint.pyreverse.diagrams import set_counter
from pylint.pyreverse.writer import DotWriter
-
from pylint.pyreverse.utils import get_visibility
-from utils import FileTC, build_file_case, get_project, Config
-project = get_project(join(dirname(abspath(__file__)), 'data'))
-linker = Linker(project)
-set_counter(0)
-config = Config()
+_DEFAULTS = {
+ 'all_ancestors': None, 'show_associated': None,
+ 'module_names': None,
+ 'output_format': 'dot', 'diadefs_file': None, 'quiet': 0,
+ 'show_ancestors': None, 'classes': (), 'all_associated': None,
+ 'mode': 'PUB_ONLY', 'show_builtin': False, 'only_classnames': False
+ }
+
+class Config(object):
+ """config object for tests"""
+ def __init__(self):
+ for attr, value in _DEFAULTS.items():
+ setattr(self, attr, value)
+
+
+def _file_lines(path):
+ # we don't care about the actual encoding, but python3 forces us to pick one
+ lines = [line.strip() for line in codecs.open(path, encoding='latin1').readlines()
+ if (line.find('squeleton generated by ') == -1 and
+ not line.startswith('__revision__ = "$Id:'))]
+ return [line for line in lines if line]
+
+def get_project(module, name=None):
+ """return a astroid project representation"""
+ # flush cache
+ MANAGER._modules_by_name = {}
+ def _astroid_wrapper(func, modname):
+ return func(modname)
+ return MANAGER.project_from_files([module], _astroid_wrapper,
+ project_name=name)
+
+CONFIG = Config()
+
+class DotWriterTC(TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ project = get_project(cls.datadir)
+ linker = Linker(project)
+ handler = DiadefsHandler(CONFIG)
+ dd = DefaultDiadefGenerator(linker, handler).visit(project)
+ for diagram in dd:
+ diagram.extract_relationships()
+ writer = DotWriter(CONFIG)
+ writer.write(dd)
-handler = DiadefsHandler(config)
-dd = DefaultDiadefGenerator(linker, handler).visit(project)
-for diagram in dd:
- diagram.extract_relationships()
+ @classmethod
+ def tearDownClass(cls):
+ for fname in ('packages_No_Name.dot', 'classes_No_Name.dot',):
+ try:
+ os.remove(fname)
+ except:
+ continue
-class DotWriterTC(FileTC):
+ def _test_same_file(self, generated_file):
+ expected_file = self.datapath(generated_file)
+ generated = _file_lines(generated_file)
+ expected = _file_lines(expected_file)
+ generated = '\n'.join(generated)
+ expected = '\n'.join(expected)
+ files = "\n *** expected : %s, generated : %s \n" % (
+ expected_file, generated_file)
+ self.assertEqual(expected, generated, '%s%s' % (
+ files, '\n'.join(line for line in unified_diff(
+ expected.splitlines(), generated.splitlines() ))) )
+ os.remove(generated_file)
- generated_files = ('packages_No_Name.dot', 'classes_No_Name.dot',)
- sort = False
+ def test_package_diagram(self):
+ self._test_same_file('packages_No_Name.dot')
- def setUp(self):
- FileTC.setUp(self)
- writer = DotWriter(config)
- writer.write(dd)
+ def test_class_diagram(self):
+ self._test_same_file('classes_No_Name.dot')
-build_file_case(DotWriterTC)
class GetVisibilityTC(TestCase):
@@ -62,16 +119,17 @@ class GetVisibilityTC(TestCase):
for name in ["__g_", "____dsf", "__23_9"]:
got = get_visibility(name)
self.assertEqual(got, 'private',
- 'got %s instead of private for value %s' % (got, name))
+ 'got %s instead of private for value %s' % (got, name))
def test_public(self):
self.assertEqual(get_visibility('simple'), 'public')
def test_protected(self):
- for name in ["_","__", "___", "____", "_____", "___e__", "_nextsimple", "_filter_it_"]:
+ for name in ["_","__", "___", "____", "_____", "___e__",
+ "_nextsimple", "_filter_it_"]:
got = get_visibility(name)
self.assertEqual(got, 'protected',
- 'got %s instead of protected for value %s' % (got, name))
+ 'got %s instead of protected for value %s' % (got, name))
if __name__ == '__main__':
diff --git a/test/utils.py b/test/utils.py
deleted file mode 100644
index e7f80e8..0000000
--- a/test/utils.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
-# http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-"""some pylint test utilities
-"""
-
-import os
-import sys
-import codecs
-from os.path import join, dirname, abspath
-from difflib import unified_diff
-
-from logilab.common.testlib import TestCase
-from astroid import MANAGER
-
-
-def _astroid_wrapper(func, modname):
- return func(modname)
-
-def _file_lines(path):
- # we don't care about the actual encoding, but python3 forces us to pick one
- lines = [line.strip() for line in codecs.open(path, encoding='latin1').readlines()
- if (line.find('squeleton generated by ') == -1 and
- not line.startswith('__revision__ = "$Id:'))]
- return [line for line in lines if line]
-
-def get_project(module, name=None):
- """return a astroid project representation
- """
- manager = MANAGER
- # flush cache
- manager._modules_by_name = {}
- return manager.project_from_files([module], _astroid_wrapper,
- project_name=name)
-
-DEFAULTS = {'all_ancestors': None, 'show_associated': None,
- 'module_names': None,
- 'output_format': 'dot', 'diadefs_file': None, 'quiet': 0,
- 'show_ancestors': None, 'classes': (), 'all_associated': None,
- 'mode': 'PUB_ONLY', 'show_builtin': False, 'only_classnames': False}
-
-class Config(object):
- """config object for tests"""
- def __init__(self):
- for attr, value in DEFAULTS.items():
- setattr(self, attr, value)
-
-class FileTC(TestCase):
- """base test case for testing file output"""
-
- generated_files = ()
- sort = True
-
- def setUp(self):
- self.expected_files = [join(dirname(abspath(__file__)), 'data', file)
- for file in self.generated_files]
-
- def tearDown(self):
- for fname in self.generated_files:
- try:
- os.remove(fname)
- except:
- continue
-
- def _test_same_file(self, index):
- generated_file = self.generated_files[index]
- expected_file = self.expected_files[index]
- generated = _file_lines(generated_file)
- expected = _file_lines(expected_file)
- if self.sort:
- generated = sorted(generated)
- expected = sorted(expected)
- generated = '\n'.join(generated)
- expected = '\n'.join(expected)
- files = "\n *** expected : %s, generated : %s \n" % (
- expected_file, generated_file)
- self.assertEqual(expected, generated, '%s%s' % (
- files, '\n'.join(line for line in unified_diff(
- expected.splitlines(), generated.splitlines() ))) )
- os.remove(generated_file)
-
-
-def build_file_case(filetc):
- for i in range(len(filetc.generated_files)):
- setattr(filetc, 'test_same_file_%s' %i,
- lambda self, index=i: self._test_same_file(index))