Orb/python/doxygen/linkinserter.py
changeset 0 42188c7ea2d9
child 1 82f11024044a
equal deleted inserted replaced
-1:000000000000 0:42188c7ea2d9
       
     1 # Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved.
       
     2 # This component and the accompanying materials are made available under the terms of the License 
       
     3 # "Eclipse Public License v1.0" which accompanies this distribution, 
       
     4 # and is available at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     5 #
       
     6 # Initial Contributors:
       
     7 # Nokia Corporation - initial contribution.
       
     8 #
       
     9 # Contributors:
       
    10 #
       
    11 # Description:
       
    12 #
       
    13 import unittest
       
    14 import sys
       
    15 from cStringIO import StringIO
       
    16 from optparse import OptionParser
       
    17 from xml.etree import ElementTree as etree
       
    18 import os.path
       
    19 import logging
       
    20 import shutil
       
    21 
       
    22 __version__ = "0.1"
       
    23 
       
    24 
       
    25 class LinkFile(object):
       
    26     """
       
    27     Parses string representations of cxxapiref XML files and returns an updated
       
    28     string representation with inserted ids for linking to cxxFunctions.
       
    29     """
       
    30     
       
    31     def _get_cxxfunction_elems(self, elem):
       
    32         """
       
    33         Takes an elements and generates a list of all child elements that are called cxxFunction 
       
    34         """
       
    35         return [e for e in elem.getiterator() if e.tag == "cxxFunction"]
       
    36     
       
    37     def _get_funcs_with_no_params(self, func_elem_list):
       
    38         """
       
    39         Takes a list of cxxFunction elements and returns a list of those with no parameters.
       
    40         """
       
    41         no_params = []
       
    42         for func in func_elem_list:
       
    43             apiname = func.find("apiName").text
       
    44             params_elem = func.find("cxxFunctionDetail/cxxFunctionDefinition/cxxFunctionParameters")
       
    45             # if cxxFunctionParameters has no children
       
    46             if len(params_elem.getiterator()) == 1:
       
    47                 no_params.append(apiname)            
       
    48         return no_params
       
    49     
       
    50     
       
    51     def _filter_funcs_with_no_params(self, func_elem_list):
       
    52         """
       
    53         Takes a list of cxxFunction elements and returns a list with parameterless functions
       
    54         and all of their overloads removed.
       
    55         """
       
    56         no_param_funcs = self._get_funcs_with_no_params(func_elem_list)
       
    57         return [func_elem for func_elem in func_elem_list if not func_elem.find("apiName").text in no_param_funcs]
       
    58     
       
    59     def _filter_duplicate_funcs(self, func_elem_list):
       
    60         """
       
    61         Takes a list of cxxFunction elements and returns a list ones with unique apiName text.
       
    62         In the case of overloads the first instance found is taken and the rest are filtered.
       
    63         """
       
    64         seen_func_names = []
       
    65         filtered = []
       
    66         for func_elem in func_elem_list:
       
    67             this_apiname = func_elem.find("apiName").text
       
    68             if not this_apiname in seen_func_names:
       
    69                 filtered.append(func_elem)
       
    70                 seen_func_names.append(this_apiname)
       
    71         return filtered
       
    72     
       
    73     def _insert_id_into_cxxfunction_apiname(self, func_elem):
       
    74         """
       
    75         Takes a cxxFunction element. Returns the element with an id inserted into the child apiName element.
       
    76         """
       
    77         function_scoped_name=func_elem.find("cxxFunctionDetail/cxxFunctionDefinition/cxxFunctionScopedName").text
       
    78         
       
    79         if function_scoped_name == None:
       
    80             function_scoped_name = ""
       
    81         else:
       
    82             function_scoped_name+="::"
       
    83         
       
    84         apiname_id = "".join([function_scoped_name,func_elem.find("apiName").text,"()"])
       
    85 
       
    86         func_elem.find("apiName").attrib["id"] = apiname_id
       
    87         return func_elem
       
    88         
       
    89     def get_func_elems_to_linkify(self, root):
       
    90         cxxfunction_elems = self._get_cxxfunction_elems(root)
       
    91         cxxfunction_elems = self._filter_funcs_with_no_params(cxxfunction_elems)
       
    92         cxxfunction_elems = self._filter_duplicate_funcs(cxxfunction_elems)
       
    93         return cxxfunction_elems
       
    94     
       
    95     def get_linkified(self, file_as_string):
       
    96         """
       
    97         Takes a string representation of a cxxapiref file and returns the string
       
    98         with inserted cxxFunction ids for any functions that fit the insertion rule.
       
    99         
       
   100         The id insertion rule is:
       
   101         
       
   102         If a function and none of its overloads have no arguments then insert an
       
   103         id that represents a function with no arguments over the first function definition encountered.
       
   104         The id is inserted into the apiName child element of the function.
       
   105         """
       
   106         try:
       
   107             root = etree.fromstring(file_as_string)
       
   108         except Exception, e:
       
   109             raise Exception("Failed to parse string as xml file error was %s" % e)
       
   110         funcs_to_linkify = self.get_func_elems_to_linkify(root)
       
   111         for index in xrange(0, len(funcs_to_linkify)):
       
   112             func = self._insert_id_into_cxxfunction_apiname(funcs_to_linkify[index])
       
   113         return etree.tostring(root)
       
   114         
       
   115 
       
   116 class LinkInserter(object):
       
   117     
       
   118     def __init__(self, link_file):
       
   119         self.link_file = link_file
       
   120         
       
   121     def _handle_xml_file(self, xml_file):
       
   122         """
       
   123         Runs linkify function on each file and writes the result to disk
       
   124         """
       
   125         logging.info("Inserting links into %s" % xml_file)
       
   126         content = open(xml_file, "r").read()
       
   127         try:
       
   128             linkified_contents = self.link_file.get_linkified(content)
       
   129         except Exception,e:
       
   130             logging.error("%s %s" %(e, xml_file))
       
   131             return
       
   132 
       
   133         try:
       
   134             f = open(xml_file, "w")
       
   135         except Exception, e:
       
   136             raise IOError("Could not open xml file %s for writing, error was: %s" % (xml_file, e))
       
   137         else:
       
   138             f.write(linkified_contents)
       
   139             f.close()
       
   140         
       
   141     def _handle_xml_files(self, xml_files):
       
   142         """
       
   143         Iterates over a list of files and calls _handle_xml_file on them
       
   144         """
       
   145         for xml_file in xml_files:
       
   146             self._handle_xml_file(xml_file)
       
   147             
       
   148     def _do_linkifying(self, dir):
       
   149         """
       
   150         Takes a directory and calls a handler function on a list of xml files in that and sub directories.
       
   151         """
       
   152         for root, dirs, files in os.walk(dir):
       
   153             xml_file_paths = [os.path.join(root, f) for f in os.listdir(root) if os.path.splitext(f)[1].lower() == (".xml")]
       
   154             self._handle_xml_files(xml_file_paths)
       
   155             
       
   156     def linkify_dir(self, dir):
       
   157         if not os.path.exists(os.path.abspath(dir)):
       
   158             raise IOError("Directory to linkify does not exist: %s" % dir) 
       
   159         self._do_linkifying(dir)
       
   160         
       
   161 
       
   162 def insertlinks(xml_dir):
       
   163     link_inserter = LinkInserter(LinkFile())
       
   164     link_inserter.linkify_dir(xml_dir)
       
   165 
       
   166 
       
   167 def main():
       
   168     usage = "usage: %prog <Path to the XML content>"
       
   169     parser = OptionParser(usage, version='%prog ' + __version__)
       
   170     (options, args) = parser.parse_args()
       
   171     if len(args) < 1:
       
   172         parser.print_help()
       
   173         parser.error("Please supply the path to the XML content")
       
   174     insertlinks(args[0])
       
   175 
       
   176 
       
   177 if __name__ == '__main__':
       
   178     sys.exit(main())
       
   179 
       
   180     
       
   181 ######################################
       
   182 # Test code
       
   183 ######################################
       
   184 
       
   185 class TestLinkFile(unittest.TestCase):
       
   186 
       
   187     def setUp(self):
       
   188         self.link_file = LinkFile()
       
   189         
       
   190     def test__get_funcs_with_no_params(self):
       
   191         func = """    
       
   192         <cxxClass><cxxFunction id="class_b_trace_1a7217f2fa88e99af3dbb5827fdc8507b7">
       
   193         <apiName>Init0</apiName>
       
   194         <cxxFunctionDetail>
       
   195             <cxxFunctionDefinition>
       
   196                 <cxxFunctionParameters/>
       
   197             </cxxFunctionDefinition>
       
   198         </cxxFunctionDetail>
       
   199     </cxxFunction></cxxClass>
       
   200 """
       
   201         root = etree.fromstring(func)
       
   202         func_list = [e for e in root.getiterator() if e.tag == "cxxFunction"]
       
   203         expected = ["Init0"]
       
   204         returned = self.link_file._get_funcs_with_no_params(func_list)
       
   205         self.assertEqual(expected, returned)
       
   206         
       
   207     def test__get_funcs_with_no_params_ignores_a_func_with_params(self):
       
   208         func = """    
       
   209         <cxxClass><cxxFunction id="class_b_trace_1a7217f2fa88e99af3dbb5827fdc8507b7">
       
   210         <apiName>Init0</apiName>
       
   211         <cxxFunctionDetail>
       
   212             <cxxFunctionDefinition>
       
   213                 <cxxFunctionParameters>
       
   214                     <cxxFunctionParameter>
       
   215                     <cxxFunctionParameterDeclaredType>
       
   216                         <apiRelation keyref="_always_online_manager_client_8cpp_1a8240e11f17c80b6b222fc2af50234da4">TUint32</apiRelation>
       
   217                         </cxxFunctionParameterDeclaredType>
       
   218                         <cxxFunctionParameterDeclarationName>a0</cxxFunctionParameterDeclarationName>
       
   219                         <apiDefNote/>
       
   220                     </cxxFunctionParameter>
       
   221                 </cxxFunctionParameters>
       
   222             </cxxFunctionDefinition>
       
   223         </cxxFunctionDetail>
       
   224     </cxxFunction></cxxClass>
       
   225 """
       
   226         root = etree.fromstring(func)
       
   227         func_list = [e for e in root.getiterator() if e.tag == "cxxFunction"]
       
   228         expected = []
       
   229         returned = self.link_file._get_funcs_with_no_params(func_list)
       
   230         self.assertEqual(expected, returned)    
       
   231     
       
   232     def test_filter_duplicate_funcs_ignores_duplicate_funcs(self):
       
   233         func = """    
       
   234         <cxxClass>
       
   235             <cxxFunction id="class_b_trace_1a7217f2fa88e99af3dbb5827fdc8507b7">
       
   236                 <apiName>Init0</apiName>
       
   237             </cxxFunction>
       
   238             <cxxFunction id="class_b_trace_1a7217f2fa88e99af3dbb5827fdc8507b7">
       
   239                 <apiName>Init0</apiName>
       
   240             </cxxFunction>
       
   241         </cxxClass>
       
   242 """     
       
   243         root = etree.fromstring(func)   
       
   244         func_list = [e for e in root.getiterator() if e.tag == "cxxFunction"]
       
   245         expected = [func_list[0]]
       
   246         returned = self.link_file._filter_duplicate_funcs(func_list)
       
   247         self.assertEqual(expected, returned)  
       
   248         
       
   249     def test__filter_funcs_with_no_params_filters_funcs_with_no_params(self):
       
   250         func = """    
       
   251         <cxxClass>
       
   252             <cxxFunction id="class_b_trace_1a7217f2fa88e99af3dbb5827fdc8507b7">
       
   253                 <apiName>Init0</apiName>
       
   254                 <cxxFunctionDetail>
       
   255                     <cxxFunctionDefinition>
       
   256                         <cxxFunctionParameters/>
       
   257                     </cxxFunctionDefinition>
       
   258                 </cxxFunctionDetail>
       
   259             </cxxFunction>
       
   260             <cxxFunction id="class_b_trace_1a7217f2fa88e99af3dbb5827fdc8507b7">
       
   261                 <apiName>Init1</apiName>
       
   262                 <cxxFunctionDetail>
       
   263                     <cxxFunctionDefinition>
       
   264                         <cxxFunctionParameters>
       
   265                             <cxxFunctionParameter>
       
   266                                 <cxxFunctionParameterDeclaredType>
       
   267                                     <apiRelation keyref="_always_online_manager_client_8cpp_1a8240e11f17c80b6b222fc2af50234da4">TUint32</apiRelation>
       
   268                                 </cxxFunctionParameterDeclaredType>
       
   269                                 <cxxFunctionParameterDeclarationName>a0</cxxFunctionParameterDeclarationName>
       
   270                                 <apiDefNote/>
       
   271                             </cxxFunctionParameter>
       
   272                         </cxxFunctionParameters>
       
   273                     </cxxFunctionDefinition>
       
   274                 </cxxFunctionDetail>
       
   275             </cxxFunction>
       
   276         </cxxClass>
       
   277 """     
       
   278         root = etree.fromstring(func)   
       
   279         func_list = [e for e in root.getiterator() if e.tag == "cxxFunction"]
       
   280         expected = [func_list[1]]
       
   281         returned = self.link_file._filter_funcs_with_no_params(func_list)
       
   282         self.assertEqual(expected, returned)
       
   283         
       
   284     def test__insert_id_into_cxxfunction_apiname(self):
       
   285         func_str = """<cxxFunction id="class_b_trace_1a7217f2fa88e99af3dbb5827fdc8507b7">
       
   286         <apiName>Init0</apiName>
       
   287         <shortdesc/>
       
   288         <cxxFunctionDetail>
       
   289             <cxxFunctionDefinition>
       
   290                 <cxxFunctionAccessSpecifier value="public"/>
       
   291                 <cxxFunctionStorageClassSpecifierStatic/>
       
   292                 <cxxFunctionDeclaredType>void</cxxFunctionDeclaredType>
       
   293                 <cxxFunctionScopedName>BTrace</cxxFunctionScopedName>
       
   294                 <cxxFunctionPrototype>static void Init0(TUint32 a0)</cxxFunctionPrototype>
       
   295                 <cxxFunctionNameLookup>BTrace::Init0(TUint32 a0)</cxxFunctionNameLookup>
       
   296                 <cxxFunctionParameters>
       
   297                     <cxxFunctionParameter>
       
   298                         <cxxFunctionParameterDeclaredType>
       
   299                             <apiRelation keyref="_always_online_manager_client_8cpp_1a8240e11f17c80b6b222fc2af50234da4">TUint32</apiRelation>
       
   300                         </cxxFunctionParameterDeclaredType>
       
   301                         <cxxFunctionParameterDeclarationName>a0</cxxFunctionParameterDeclarationName>
       
   302                         <apiDefNote/>
       
   303                     </cxxFunctionParameter>
       
   304                 </cxxFunctionParameters>
       
   305                 <cxxFunctionAPIItemLocation>
       
   306                     <cxxFunctionDeclarationFile name="filePath" value="D:/epoc32/include/e32btrace.h"/>
       
   307                     <cxxFunctionDeclarationFileLine name="lineNumber" value="3882"/>
       
   308                     <cxxFunctionDefinitionFile name="filePath" value="D:/EPOC/master/sf/mw/messagingmw/messagingfw/alwaysonline/AlwaysOnlineManager/src/AlwaysOnlineManagerClient.cpp"/>
       
   309                     <cxxFunctionDefinitionFileLineStart name="lineNumber" value="-1"/>
       
   310                     <cxxFunctionDefinitionFileLineEnd name="lineNumber" value="-1"/>
       
   311                 </cxxFunctionAPIItemLocation>
       
   312             </cxxFunctionDefinition>
       
   313             <apiDesc/>
       
   314         </cxxFunctionDetail>
       
   315     </cxxFunction>"""
       
   316         func_elem = etree.fromstring(func_str)
       
   317         returned = self.link_file._insert_id_into_cxxfunction_apiname(func_elem)
       
   318         self.assertEquals(returned.find("apiName").attrib["id"], "BTrace::Init0()")
       
   319 
       
   320     def test__insert_id_into_cxxfunction_apiname_when_the_cxxfunction_has_no_scoped_name(self):
       
   321         func_str = """<cxxFunction id="class_b_trace_1a7217f2fa88e99af3dbb5827fdc8507b7">
       
   322         <apiName>Init0</apiName>
       
   323         <shortdesc/>
       
   324         <cxxFunctionDetail>
       
   325             <cxxFunctionDefinition>
       
   326                 <cxxFunctionAccessSpecifier value="public"/>
       
   327                 <cxxFunctionStorageClassSpecifierStatic/>
       
   328                 <cxxFunctionDeclaredType>void</cxxFunctionDeclaredType>
       
   329                 <cxxFunctionScopedName/>
       
   330                 <cxxFunctionPrototype>static void Init0(TUint32 a0)</cxxFunctionPrototype>
       
   331                 <cxxFunctionNameLookup>BTrace::Init0(TUint32 a0)</cxxFunctionNameLookup>
       
   332                 <cxxFunctionParameters>
       
   333                     <cxxFunctionParameter>
       
   334                         <cxxFunctionParameterDeclaredType>
       
   335                             <apiRelation keyref="_always_online_manager_client_8cpp_1a8240e11f17c80b6b222fc2af50234da4">TUint32</apiRelation>
       
   336                         </cxxFunctionParameterDeclaredType>
       
   337                         <cxxFunctionParameterDeclarationName>a0</cxxFunctionParameterDeclarationName>
       
   338                         <apiDefNote/>
       
   339                     </cxxFunctionParameter>
       
   340                 </cxxFunctionParameters>
       
   341                 <cxxFunctionAPIItemLocation>
       
   342                     <cxxFunctionDeclarationFile name="filePath" value="D:/epoc32/include/e32btrace.h"/>
       
   343                     <cxxFunctionDeclarationFileLine name="lineNumber" value="3882"/>
       
   344                     <cxxFunctionDefinitionFile name="filePath" value="D:/EPOC/master/sf/mw/messagingmw/messagingfw/alwaysonline/AlwaysOnlineManager/src/AlwaysOnlineManagerClient.cpp"/>
       
   345                     <cxxFunctionDefinitionFileLineStart name="lineNumber" value="-1"/>
       
   346                     <cxxFunctionDefinitionFileLineEnd name="lineNumber" value="-1"/>
       
   347                 </cxxFunctionAPIItemLocation>
       
   348             </cxxFunctionDefinition>
       
   349             <apiDesc/>
       
   350         </cxxFunctionDetail>
       
   351     </cxxFunction>"""
       
   352         func_elem = etree.fromstring(func_str)
       
   353         returned = self.link_file._insert_id_into_cxxfunction_apiname(func_elem)
       
   354         self.assertEquals(returned.find("apiName").attrib["id"], "Init0()")
       
   355         
       
   356     def test_i_can_insert_an_id_to_a_cxxfunction_apiname(self):
       
   357         file_as_string = """    
       
   358         <cxxClass>
       
   359 <cxxFunction id="class_b_trace_1a7217f2fa88e99af3dbb5827fdc8507b7">
       
   360         <apiName>Init0</apiName>
       
   361         <shortdesc/>
       
   362         <cxxFunctionDetail>
       
   363             <cxxFunctionDefinition>
       
   364                 <cxxFunctionAccessSpecifier value="public"/>
       
   365                 <cxxFunctionStorageClassSpecifierStatic/>
       
   366                 <cxxFunctionDeclaredType>void</cxxFunctionDeclaredType>
       
   367                 <cxxFunctionScopedName>BTrace</cxxFunctionScopedName>
       
   368                 <cxxFunctionPrototype>static void Init0(TUint32 a0)</cxxFunctionPrototype>
       
   369                 <cxxFunctionNameLookup>BTrace::Init0(TUint32 a0)</cxxFunctionNameLookup>
       
   370                 <cxxFunctionParameters>
       
   371                     <cxxFunctionParameter>
       
   372                         <cxxFunctionParameterDeclaredType>
       
   373                             <apiRelation keyref="_always_online_manager_client_8cpp_1a8240e11f17c80b6b222fc2af50234da4">TUint32</apiRelation>
       
   374                         </cxxFunctionParameterDeclaredType>
       
   375                         <cxxFunctionParameterDeclarationName>a0</cxxFunctionParameterDeclarationName>
       
   376                         <apiDefNote/>
       
   377                     </cxxFunctionParameter>
       
   378                 </cxxFunctionParameters>
       
   379                 <cxxFunctionAPIItemLocation>
       
   380                     <cxxFunctionDeclarationFile name="filePath" value="D:/epoc32/include/e32btrace.h"/>
       
   381                     <cxxFunctionDeclarationFileLine name="lineNumber" value="3882"/>
       
   382                     <cxxFunctionDefinitionFile name="filePath" value="D:/EPOC/master/sf/mw/messagingmw/messagingfw/alwaysonline/AlwaysOnlineManager/src/AlwaysOnlineManagerClient.cpp"/>
       
   383                     <cxxFunctionDefinitionFileLineStart name="lineNumber" value="-1"/>
       
   384                     <cxxFunctionDefinitionFileLineEnd name="lineNumber" value="-1"/>
       
   385                 </cxxFunctionAPIItemLocation>
       
   386             </cxxFunctionDefinition>
       
   387             <apiDesc/>
       
   388         </cxxFunctionDetail>
       
   389     </cxxFunction>
       
   390         </cxxClass>"""
       
   391         returned = self.link_file.get_linkified(file_as_string)
       
   392         self.assertEquals(etree.fromstring(returned).find("cxxFunction/apiName").attrib["id"], "BTrace::Init0()")
       
   393 
       
   394 
       
   395 basic_class_file_str = """\    
       
   396 <cxxClass>
       
   397     <cxxFunction id="function_id">
       
   398         <apiName>Init0</apiName>
       
   399         <shortdesc/>
       
   400         <cxxFunctionDetail>
       
   401             <cxxFunctionDefinition>
       
   402                 <cxxFunctionAccessSpecifier value="public"/>
       
   403                 <cxxFunctionStorageClassSpecifierStatic/>
       
   404                 <cxxFunctionDeclaredType>void</cxxFunctionDeclaredType>
       
   405                 <cxxFunctionScopedName>BTrace</cxxFunctionScopedName>
       
   406                 <cxxFunctionPrototype>static void Init0()</cxxFunctionPrototype>
       
   407                 <cxxFunctionNameLookup>BTrace::Init0()</cxxFunctionNameLookup>
       
   408                 <cxxFunctionParameters/>
       
   409                 <cxxFunctionAPIItemLocation>
       
   410                     <cxxFunctionDeclarationFile name="filePath" value="D:/epoc32/include/e32btrace.h"/>
       
   411                     <cxxFunctionDeclarationFileLine name="lineNumber" value="3882"/>
       
   412                     <cxxFunctionDefinitionFile name="filePath" value="D:/EPOC/master/sf/mw/messagingmw/messagingfw/alwaysonline/AlwaysOnlineManager/src/AlwaysOnlineManagerClient.cpp"/>
       
   413                     <cxxFunctionDefinitionFileLineStart name="lineNumber" value="-1"/>
       
   414                     <cxxFunctionDefinitionFileLineEnd name="lineNumber" value="-1"/>
       
   415                 </cxxFunctionAPIItemLocation>
       
   416             </cxxFunctionDefinition>
       
   417             <apiDesc/>
       
   418         </cxxFunctionDetail>
       
   419     </cxxFunction>
       
   420 </cxxClass>"""
       
   421 
       
   422 
       
   423 xml_files = {
       
   424                "basic_xml_file_1.xml": """<tag1></tag1>""",
       
   425                "basic_xml_file_2.xml": """<tag2></tag2>""",
       
   426                }
       
   427 no_xml_files = {
       
   428                "non_xml_file.txt": """Some text""",                     
       
   429                }
       
   430 
       
   431 
       
   432 class DummyLinkFile(object):
       
   433     
       
   434     def __init__(self):
       
   435         self.visited_files = []
       
   436     
       
   437     def get_linkified(self, file_as_string):
       
   438         self.visited_files.append(file_as_string)
       
   439         return file_as_string
       
   440         
       
   441 class TestLinkInserter(unittest.TestCase):
       
   442     
       
   443     def setUp(self):
       
   444         self.dummy_link_file = DummyLinkFile()
       
   445         self.inserter = LinkInserter(self.dummy_link_file)
       
   446         
       
   447     def test__handle_xml_file_writes_to_a_file(self):
       
   448         tmp_file_path = os.getcwd() + os.sep + "tmp_file.xml"
       
   449         tmp_file = open(tmp_file_path, "w")
       
   450         tmp_file.write(basic_class_file_str)
       
   451         tmp_file.close()
       
   452         self.inserter._handle_xml_file(tmp_file_path)
       
   453         self.assertEquals(self.dummy_link_file.visited_files, [basic_class_file_str])
       
   454         os.remove(tmp_file_path)
       
   455         
       
   456     def test_i_raise_an_exception_when_dir_doesnt_exist(self):
       
   457         self.assertRaises(IOError, self.inserter.linkify_dir, "non_existant_dir")
       
   458         
       
   459     def test_i_call_linkify_on_each_file_xml_file_in_a_dir(self):
       
   460         basic_files = {}
       
   461         basic_files.update(xml_files)
       
   462         basic_files.update(no_xml_files)
       
   463         test_dir = os.path.join(os.getcwd(), "test_dir")
       
   464         os.mkdir(test_dir)
       
   465         for filename,file_content in basic_files.items():
       
   466             handle = open(os.path.join(test_dir, filename),"w")
       
   467             handle.write(file_content)
       
   468             handle.close()
       
   469         self.inserter._do_linkifying(test_dir)
       
   470         self.dummy_link_file.visited_files.sort()
       
   471         xml_files_input = xml_files.values()
       
   472         xml_files_input.sort()
       
   473         self.assertEquals(self.dummy_link_file.visited_files, xml_files_input)      
       
   474         shutil.rmtree(test_dir)