Revision: 477
Author: roman_yakovenko
Date: 2006-08-26 23:52:22 -0700 (Sat, 26 Aug 2006)
ViewCVS: http://svn.sourceforge.net/pygccxml/?rev=477&view=rev
Log Message:
-----------
adding unit tests for algorithms cache
Modified Paths:
--------------
pygccxml_dev/pygccxml/declarations/algorithm.py
pygccxml_dev/pygccxml/declarations/algorithms_cache.py
pygccxml_dev/pygccxml/declarations/class_declaration.py
pygccxml_dev/pygccxml/declarations/declaration.py
pygccxml_dev/pygccxml/utils/__init__.py
pygccxml_dev/unittests/test_all.py
Added Paths:
-----------
pygccxml_dev/unittests/algorithms_cache_tester.py
Modified: pygccxml_dev/pygccxml/declarations/algorithm.py
===================================================================
--- pygccxml_dev/pygccxml/declarations/algorithm.py 2006-08-26 18:27:22 UTC (rev 476)
+++ pygccxml_dev/pygccxml/declarations/algorithm.py 2006-08-27 06:52:22 UTC (rev 477)
@@ -10,16 +10,19 @@
def declaration_path( decl ):
"""
returns a list of parent declarations names
-
+
@param decl: declaration for which declaration path should be calculated
@type decl: L{declaration_t}
-
- @return: [names], where first item contains top parent name and last item
+
+ @return: [names], where first item contains top parent name and last item
contains decl name
"""
+ #TODO:
+ #If parent declaration cache already has declaration_path, reuse it for
+ #calculation.
if not decl:
return []
- if not decl.cache.declaration_path:
+ if not decl.cache.declaration_path:
result = [ decl.name ]
parent = decl.parent
while parent:
@@ -27,27 +30,32 @@
parent = parent.parent
result.reverse()
decl.cache.declaration_path = result
- return decl.cache.declaration_path
+ return result
+ else:
+ return decl.cache.declaration_path
def full_name( decl ):
"""
returns full name of the declaration
- @param decl: declaration for which full name should be calculated. If decl
+ @param decl: declaration for which full name should be calculated. If decl
belongs to unnamed namespace, then L{full_name} is not valid C++ full name.
-
+
@type decl: L{declaration_t}
- @return: full name of declarations.
+ @return: full name of declarations.
"""
if None is decl:
raise RuntimeError( "Unable to generate full name for None object!" )
if not decl.cache.full_name:
decl_path = declaration_path( decl )
- ##Here I have lack of knowledge:
+ ##Here I have lack of knowledge:
##TODO: "What is the full name of declaration declared in unnamed namespace?"
result = filter( None, decl_path )
- decl.cache.full_name = result[0] + '::'.join( result[1:] )
- return decl.cache.full_name
+ result = result[0] + '::'.join( result[1:] )
+ decl.cache.full_name = result
+ return result
+ else:
+ return decl.cache.full_name
def make_flatten( decl_or_decls ):
@@ -56,7 +64,7 @@
@param decl_or_decls: reference to list of declaration's or single declaration
@type decl_or_decls: L{declaration_t} or [ L{declaration_t} ]
-
+
@return: [ all internal declarations ]
"""
import pygccxml.declarations #prevent cyclic import
@@ -78,7 +86,7 @@
decls.append( decl_or_decls )
answer = []
for decl in decls:
- answer.extend( proceed_single( decl ) )
+ answer.extend( proceed_single( decl ) )
return answer
def __make_flatten_generator( decl_or_decls ):
@@ -87,10 +95,10 @@
@param decl_or_decls: reference to list of declaration's or single declaration
@type decl_or_decls: L{declaration_t} or [ L{declaration_t} ]
-
+
@return: [ all internal declarations ]
"""
-
+
import pygccxml.declarations
def proceed_single( decl ):
yield decl
@@ -113,24 +121,24 @@
def get_global_namespace(decls):
import pygccxml.declarations
- found = filter( lambda decl: decl.name == '::'
+ found = filter( lambda decl: decl.name == '::'
and isinstance( decl, pygccxml.declarations.namespace_t )
, make_flatten( decls ) )
if len( found ) == 1:
return found[0]
raise RuntimeError( "Unable to find global namespace." )
-
+
class match_declaration_t:
"""
- helper class for different search algorithms.
-
+ helper class for different search algorithms.
+
This class will help developer to match declaration by:
- declaration type, for example L{class_t} or L{operator_t}.
- declaration name
- declaration full name
- reference to parent declaration
"""
-
+
def __init__( self, type=None, name=None, fullname=None, parent=None ):
self.type = type
self.name = name
@@ -140,10 +148,10 @@
def does_match_exist(self, inst):
"""
returns True if inst do match one of specified criteria
-
+
@param inst: declaration instance
@type inst: L{declaration_t}
-
+
@return: bool
"""
answer = True
@@ -169,12 +177,12 @@
, name=None
, parent=None
, recursive=True
- , fullname=None ):
+ , fullname=None ):
"""
returns a list of all declarations that match criteria, defined by developer
-
+
For more information about arguments see L{match_declaration_t} class.
-
+
@return: [ matched declarations ]
"""
decls = []
@@ -192,13 +200,13 @@
, recursive=True
, fullname=None ):
"""
- returns single declaration that match criteria, defined by developer.
+ returns single declaration that match criteria, defined by developer.
If more the one declaration was found None will be returned.
-
+
For more information about arguments see L{match_declaration_t} class.
-
+
@return: matched declaration L{declaration_t} or None
- """
+ """
decl = find_all_declarations( declarations, type=type, name=name, parent=parent, recursive=recursive, fullname=fullname )
if len( decl ) == 1:
return decl[0]
@@ -206,31 +214,31 @@
def find_first_declaration( declarations, type=None, name=None, parent=None, recursive=True, fullname=None ):
"""
returns first declaration that match criteria, defined by developer
-
+
For more information about arguments see L{match_declaration_t} class.
-
+
@return: matched declaration L{declaration_t} or None
"""
matcher = match_declaration_t(type, name, fullname, parent)
if recursive:
decls = make_flatten( declarations )
else:
- decls = declarations
+ decls = declarations
for decl in decls:
if matcher( decl ):
return decl
return None
-
+
def declaration_files(decl_or_decls):
"""
returns set of files
-
+
Every declaration is declared in some file. This function returns set, that
contains all file names of declarations.
-
+
@param decl_or_decls: reference to list of declaration's or single declaration
@type decl_or_decls: L{declaration_t} or [ L{declaration_t} ]
-
+
@return: set( declaration file names )
"""
files = set()
@@ -242,9 +250,9 @@
class visit_function_has_not_been_found_t( RuntimeError ):
"""
- exception that is raised, from L{apply_visitor}, when a visitor could not be
+ exception that is raised, from L{apply_visitor}, when a visitor could not be
applied.
-
+
"""
def __init__( self, visitor, decl_inst ):
RuntimeError.__init__( self )
@@ -257,7 +265,7 @@
def apply_visitor( visitor, decl_inst):
"""
applies a visitor on declaration instance
-
+
@param visitor: instance
@type visitor: L{type_visitor_t} or L{decl_visitor_t}
"""
Modified: pygccxml_dev/pygccxml/declarations/algorithms_cache.py
===================================================================
--- pygccxml_dev/pygccxml/declarations/algorithms_cache.py 2006-08-26 18:27:22 UTC (rev 476)
+++ pygccxml_dev/pygccxml/declarations/algorithms_cache.py 2006-08-27 06:52:22 UTC (rev 477)
@@ -10,24 +10,83 @@
class algorithms_cache_t( object ):
def __init__( self ):
object.__init__( self )
- self.full_name = None
- self.access_type = None
- self.declaration_path = None
-
+ self._enabled = True
+
+ def disable( self ):
+ self._enabled = False
+
+ def enable( self ):
+ self._enabled = True
+
+ @property
+ def enabled( self ):
+ return self._enabled
+
+class declaration_algs_cache_t( algorithms_cache_t ):
+ def __init__( self ):
+ algorithms_cache_t.__init__( self )
+ self._full_name = None
+ self._access_type = None
+ self._demangled_name = None
+ self._declaration_path = None
+
+ def _get_full_name( self ):
+ if self.enabled:
+ return self._full_name
+ return None
+ def _set_full_name( self, fname ):
+ self._full_name = fname
+ full_name = property( _get_full_name, _set_full_name )
+
+ def _get_access_type( self ):
+ if self.enabled:
+ return self._access_type
+ return None
+ def _set_access_type( self, access_type ):
+ self._access_type = access_type
+ access_type = property( _get_access_type, _set_access_type )
+
+ def _get_demangled_name( self ):
+ if self.enabled:
+ return self._demangled_name
+ return None
+ def _set_demangled_name( self, demangled_name ):
+ self._demangled_name = demangled_name
+ demangled_name = property( _get_demangled_name, _set_demangled_name )
+
+ def _get_declaration_path( self ):
+ if self.enabled:
+ return self._declaration_path
+ return None
+ def _set_declaration_path( self, declaration_path ):
+ self._declaration_path = declaration_path
+ declaration_path = property( _get_declaration_path, _set_declaration_path )
+
def reset( self ):
self.full_name = None
self.access_type = None
+ self.demangled_name = None
self.declaration_path = None
def reset_name_based( self ):
self.full_name = None
+ self.demangled_name = None
self.declaration_path = None
-
+
def reset_access_type( self ):
self.access_type = None
-
-class type_traits_cache_t( object ):
- def __init__( self ):
- object.__init__( self )
- self.remove_alias = None
-
+
+#Introducing next cache to the type broke unit test. I should find out why.
+#~ class type_algs_cache_t( algorithms_cache_t ):
+ #~ def __init__( self ):
+ #~ algorithms_cache_t.__init__( self )
+ #~ self._remove_alias = None
+
+ #~ def _get_remove_alias( self ):
+ #~ if self.enabled:
+ #~ return self._remove_alias
+ #~ return None
+ #~ def _set_remove_alias( self, remove_alias ):
+ #~ self._remove_alias = remove_alias
+ #~ remove_alias = property( _get_remove_alias, _set_remove_alias )
+
Modified: pygccxml_dev/pygccxml/declarations/class_declaration.py
===================================================================
--- pygccxml_dev/pygccxml/declarations/class_declaration.py 2006-08-26 18:27:22 UTC (rev 476)
+++ pygccxml_dev/pygccxml/declarations/class_declaration.py 2006-08-27 06:52:22 UTC (rev 477)
@@ -101,13 +101,12 @@
self._private_members = []
self._protected_members = []
self._aliases = []
- self.__cached_demangled_name = None # Cached value of name from get_name_impl
def _get_name_impl( self ):
if not self._name: #class with empty name
return self._name
elif class_t.USE_DEMANGLED_AS_NAME and self.demangled:
- if not self.__cached_demangled_name:
+ if not self.cache.demangled_name:
fname = algorithm.full_name( self.parent )
if fname.startswith( '::' ) and not self.demangled.startswith( '::' ):
fname = fname[2:]
@@ -115,10 +114,13 @@
tmp = self.demangled[ len( fname ): ] #demangled::name
if tmp.startswith( '::' ):
tmp = tmp[2:]
- self.__cached_demangled_name = tmp
+ self.cache.demangled_name = tmp
+ return tmp
else:
- self.__cached_demangled_name = self._name
- return self.__cached_demangled_name
+ self.cache.demangled_name = self._name
+ return self._name
+ else:
+ return self.cache.demangled_name
else:
return self._name
@@ -301,7 +303,7 @@
container = self.private_members
del container[ container.index( decl ) ]
decl.cache.reset_access_type()
-
+
def find_out_member_access_type( self, member ):
"""
returns member access type
@@ -311,16 +313,19 @@
@return: L{ACCESS_TYPES}
"""
- assert member.parent is self
+ assert member.parent is self
if not member.cache.access_type:
access_type = None
if member in self.public_members:
- member.cache.access_type = ACCESS_TYPES.PUBLIC
+ access_type = ACCESS_TYPES.PUBLIC
elif member in self.protected_members:
- member.cache.access_type = ACCESS_TYPES.PROTECTED
+ access_type = ACCESS_TYPES.PROTECTED
elif member in self.private_members:
- member.cache.access_type = ACCESS_TYPES.PRIVATE
+ access_type = ACCESS_TYPES.PRIVATE
else:
raise RuntimeError( "Unable to find member within internal members list." )
- return member.cache.access_type
-
+ member.cache.access_type = access_type
+ return access_type
+ else:
+ return member.cache.access_type
+
Modified: pygccxml_dev/pygccxml/declarations/declaration.py
===================================================================
--- pygccxml_dev/pygccxml/declarations/declaration.py 2006-08-26 18:27:22 UTC (rev 476)
+++ pygccxml_dev/pygccxml/declarations/declaration.py 2006-08-27 06:52:22 UTC (rev 477)
@@ -75,7 +75,7 @@
self._mangled = mangled
self._demangled = demangled
self._parent = None
- self._cache = algorithms_cache.algorithms_cache_t()
+ self._cache = algorithms_cache.declaration_algs_cache_t()
def __str__(self):
"""Default __str__ method.
@@ -164,9 +164,10 @@
def _set_name( self, new_name ):
previous_name = self._name
self._name = new_name
+ self.cache.reset_name_based()
if previous_name: #the was a rename and not initial "set"
self._on_rename()
-
+
name = property( _get_name, _set_name
, doc="""Declaration name
@type: str
@@ -248,4 +249,4 @@
reference to instance of L{algorithms_cache.algorithms_cache_t} class.
"""
- return self._cache
\ No newline at end of file
+ return self._cache
Modified: pygccxml_dev/pygccxml/utils/__init__.py
===================================================================
--- pygccxml_dev/pygccxml/utils/__init__.py 2006-08-26 18:27:22 UTC (rev 476)
+++ pygccxml_dev/pygccxml/utils/__init__.py 2006-08-27 06:52:22 UTC (rev 477)
@@ -13,44 +13,44 @@
import logging
import tempfile
-def _create_logger_( name ):
+def _create_logger_( name ):
"""implementation details"""
logger = logging.getLogger(name)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter( logging.Formatter( os.linesep + '%(levelname)s %(message)s' ) )
- logger.addHandler(handler)
+ logger.addHandler(handler)
logger.setLevel(logging.INFO)
return logger
class loggers:
"""class-namespace, defines few loggers classes, used in the project"""
- gccxml = _create_logger_( 'pygccxml.gccxml' )
+ gccxml = _create_logger_( 'pygccxml.gccxml' )
"""logger for gccxml functionality
-
+
If you set this logger level to DEBUG, you will be able to see the exact
command line, used to invoke GCC-XML and errors that occures during XML parsing
"""
-
+
queries_engine = _create_logger_( 'pygccxml.queries_engine' )
"""logger for query engine functionality.
-
+
If you set this logger level to DEBUG, you will be able to see what queries
you do against declarations tree, measure performance and may be even to improve it.
Query engine reports queries and whether they are optimized or not.
"""
-
+
declarations_cache = _create_logger_( 'pygccxml.declarations_cache' )
"""logger for declarations tree cache functionality
-
+
If you set this logger level to DEBUG, you will be able to see what is exactly
- happens, when you read the declarations from cache file. You will be able to
+ happens, when you read the declarations from cache file. You will be able to
decide, whether it worse for you to use this or that cache strategy.
"""
-
+
root = logging.getLogger( 'pygccxml' )
"""root logger exists for your convinience only"""
-
+
all = [ root, gccxml, queries_engine, declarations_cache ]
"""contains all logger classes, defined by the class"""
@@ -60,12 +60,12 @@
if os.path.exists(file_name):
os.remove( file_name )
except Exception, error:
- loggers.root.error( "Error ocured while removing temprorary created file('%s'): %s"
+ loggers.root.error( "Error ocured while removing temprorary created file('%s'): %s"
% ( file_name, str( error ) ) )
-def create_temp_file_name(suffix, prefix=None, dir=None):
+def create_temp_file_name(suffix, prefix=None, dir=None):
"""small convinience function that creates temporal file.
-
+
This function is a wrapper aroung Python built-in function - tempfile.mkstemp
"""
if not prefix:
@@ -79,9 +79,9 @@
"""return os.path.normpath( os.path.normcase( some_path ) )"""
return os.path.normpath( os.path.normcase( some_path ) )
-def get_architecture():
+def get_architecture():
"""returns computer architecture: 32 or 64.
-
+
The guess is based on maxint.
"""
if sys.maxint == 2147483647:
@@ -89,4 +89,5 @@
elif sys.maxint == 9223372036854775807:
return 64
else:
- raise RuntimeError( "Unknown architecture" )
\ No newline at end of file
+ raise RuntimeError( "Unknown architecture" )
+
Added: pygccxml_dev/unittests/algorithms_cache_tester.py
===================================================================
--- pygccxml_dev/unittests/algorithms_cache_tester.py (rev 0)
+++ pygccxml_dev/unittests/algorithms_cache_tester.py 2006-08-27 06:52:22 UTC (rev 477)
@@ -0,0 +1,75 @@
+# Copyright 2004 Roman Yakovenko.
+# Distributed under the Boost Software License, Version 1.0. (See
+# accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+import unittest
+import autoconfig
+import parser_test_case
+
+from pygccxml import utils
+from pygccxml import parser
+from pygccxml import declarations
+
+class algorithms_cache_tester_t( parser_test_case.parser_test_case_t ):
+ #tester source reader
+ COMPILATION_MODE = parser.COMPILATION_MODE.ALL_AT_ONCE
+ def __init__(self, *args ):
+ parser_test_case.parser_test_case_t.__init__( self, *args )
+ self.header = 'core_membership.hpp'
+ self.global_ns = None
+
+ def setUp(self):
+ decls = parser.parse( [self.header], self.config )
+ self.global_ns = declarations.get_global_namespace( decls )
+
+ def test_name_based( self ):
+ cls = self.global_ns.class_( name='class_for_nested_enums_t' )
+
+ cls_demangled_name = cls.name
+ self.failUnless( cls.cache.demangled_name == cls_demangled_name )
+
+ cls_full_name = declarations.full_name( cls )
+ self.failUnless( cls.cache.full_name == cls_full_name )
+
+ cls_declaration_path = declarations.declaration_path( cls )
+ self.failUnless( cls.cache.declaration_path == cls_declaration_path )
+
+ enum = cls.enum( 'ENestedPublic' )
+
+ enum_full_name = declarations.full_name( enum )
+ self.failUnless( enum.cache.full_name == enum_full_name )
+
+ enum_declaration_path = declarations.declaration_path( enum )
+ self.failUnless( enum.cache.declaration_path == enum_declaration_path )
+
+ #now we change class name, all internal decls cache should be cleared
+ cls.name = "new_name"
+ self.failUnless( not cls.cache.full_name )
+ self.failUnless( not cls.cache.demangled_name )
+ self.failUnless( not cls.cache.declaration_path )
+
+ self.failUnless( not enum.cache.full_name )
+ self.failUnless( not enum.cache.demangled_name )
+ self.failUnless( not enum.cache.declaration_path )
+
+ def test_access_type( self ):
+ cls = self.global_ns.class_( name='class_for_nested_enums_t' )
+ enum = cls.enum( 'ENestedPublic' )
+ self.failUnless( enum.cache.access_type == 'public' )
+ enum.cache.reset_access_type()
+ self.failUnless( not enum.cache.access_type )
+ self.failUnless( 'public' == cls.find_out_member_access_type( enum ) )
+ self.failUnless( enum.cache.access_type == 'public' )
+
+def create_suite():
+ suite = unittest.TestSuite()
+ suite.addTest( unittest.makeSuite(algorithms_cache_tester_t))
+
+ return suite
+
+def run_suite():
+ unittest.TextTestRunner(verbosity=2).run( create_suite() )
+
+if __name__ == "__main__":
+ run_suite()
Modified: pygccxml_dev/unittests/test_all.py
===================================================================
--- pygccxml_dev/unittests/test_all.py 2006-08-26 18:27:22 UTC (rev 476)
+++ pygccxml_dev/unittests/test_all.py 2006-08-27 06:52:22 UTC (rev 477)
@@ -17,7 +17,7 @@
import type_traits_tester
import core_tester
import xmlfile_reader_tester
-import filtering_tester
+import filtering_tester
import text_reader_tester
import hierarchy_traveling
import patcher_tester
@@ -31,16 +31,17 @@
import filters_tester
import cache_enums_tester
import decl_printer_tester
-import typedefs_tester
+import typedefs_tester
import demangled_tester
import unnamed_enums_bug_tester
import vector_traits_tester
import string_traits_tester
import declarations_cache_tester
import has_binary_operator_traits_tester
+import algorithms_cache_tester
def create_suite():
- testers = [
+ testers = [
decl_string_tester
, declaration_files_tester
, declarations_comparison_tester
@@ -75,14 +76,15 @@
, string_traits_tester
, declarations_cache_tester
, has_binary_operator_traits_tester
+ , algorithms_cache_tester
]
-
- main_suite = unittest.TestSuite()
+
+ main_suite = unittest.TestSuite()
for tester in testers:
main_suite.addTest( tester.create_suite() )
return main_suite
-
+
def run_suite():
result = unittest.TextTestRunner(verbosity=2).run( create_suite() )
error_desc = 'EXCEPTION IN SAFE SELECT 9'
@@ -104,4 +106,4 @@
##~ statistics = hotshot.stats.load( statistics_file )
##~ statistics.strip_dirs()
##~ statistics.sort_stats( 'time', 'calls' )
-##~ statistics.print_stats( 678 )
\ No newline at end of file
+##~ statistics.print_stats( 678 )
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|