Orb/python/doxygen/ditamap_link_converter.py
changeset 1 82f11024044a
equal deleted inserted replaced
0:42188c7ea2d9 1:82f11024044a
       
     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 from __future__ import with_statement
       
    14 import unittest
       
    15 import os
       
    16 import shutil
       
    17 import sys
       
    18 import xml
       
    19 import logging
       
    20 from cStringIO import StringIO
       
    21 from xml.etree import ElementTree as etree
       
    22 
       
    23 
       
    24 class DitamapLinkConverterError(Exception):
       
    25     """ Raised if an invalid toc is input """
       
    26 
       
    27 class DitamapLinkConverter():
       
    28     
       
    29     def __init__(self,out_dir, toc_path):
       
    30         self.out_dir = os.path.abspath(out_dir)
       
    31         self.toc_path = os.path.abspath(toc_path)
       
    32         self.toc_dir = os.path.dirname(self.toc_path)
       
    33         if not os.path.exists(self.out_dir):
       
    34             os.mkdir(self.out_dir)
       
    35             
       
    36     def _convert_link_to_html(self, link):
       
    37         if link.attrib["href"].endswith(".xml"):
       
    38             link.attrib["href"] = link.attrib["href"].replace(".xml", ".html")
       
    39             link.attrib["scope"] = "peer"
       
    40         return link
       
    41     
       
    42     def _convert_links(self, tree):
       
    43         for element in tree.getiterator():
       
    44             if element.attrib.get("href") != None:
       
    45                 element = self._convert_link_to_html(element)
       
    46         return tree
       
    47     
       
    48     def _handle_map(self, ditamap):
       
    49         try:
       
    50             root = etree.parse(ditamap).getroot()
       
    51         except xml.parsers.expat.ExpatError, e:
       
    52             logging.error("%s could not be parsed: %s\n" % (ditamap, str(e)))
       
    53             return
       
    54         except IOError, e:
       
    55             logging.error("Component map \"%s\" does not exist" % ditamap)
       
    56             return
       
    57         root = self._convert_links(root)
       
    58         self._write_file(root, os.path.basename(ditamap))
       
    59 
       
    60     def _write_file(self, root, file_name):
       
    61         filepath = self.out_dir+os.sep+file_name
       
    62         logging.debug('Writing file \"%s\"' % filepath)
       
    63         
       
    64         if root is not None:
       
    65             with open(filepath, 'w') as f:
       
    66                 f.write("""<?xml version="1.0" encoding="UTF-8"?>"""+'\n')
       
    67                 f.write("""<!DOCTYPE cxxAPIMap PUBLIC "-//NOKIA//DTD DITA C++ API Map Reference Type v0.5.0//EN" "dtd/cxxAPIMap.dtd" >"""+'\n')
       
    68                 f.write(etree.tostring(root))        
       
    69                 f.close()
       
    70     
       
    71     def _get_component_map_paths(self, tree):
       
    72         all_hrefs = []
       
    73         for element in tree.getiterator():
       
    74             if element.tag == "topicref":
       
    75                 all_hrefs.append(self.toc_dir+os.sep+element.attrib["href"])
       
    76         return all_hrefs
       
    77     
       
    78     def convert(self):
       
    79         try:
       
    80             tree = etree.parse(self.toc_path).getroot()
       
    81         except xml.parsers.expat.ExpatError, e:
       
    82             raise DitamapLinkConverterError("%s could not be parsed: %s\n" % (self.toc_path, str(e)))
       
    83         component_maps = self._get_component_map_paths(tree)
       
    84         for component_map in component_maps:
       
    85             self._handle_map(component_map)
       
    86         shutil.copyfile(self.toc_path, self.out_dir+os.sep+os.path.basename(self.toc_path))
       
    87         
       
    88 
       
    89 class TestDitamapLinkConverter(unittest.TestCase):
       
    90     def setUp(self):
       
    91         self._create_test_dir()
       
    92         self.dlc = DitamapLinkConverter(self.out_dir, '')
       
    93         
       
    94     def tearDown(self):
       
    95         self._clean_test_dir()
       
    96         
       
    97     def _create_test_dir(self):
       
    98         self.test_dir = "ditamap_link_converter_test_dir"
       
    99         self.out_dir = self.test_dir+os.sep+"out"
       
   100         self.cmap_path = self.test_dir+os.sep+"cmap.xml"
       
   101         os.mkdir(self.test_dir)
       
   102         f = open(self.cmap_path, "w")
       
   103         f.write(cmap)
       
   104         f.close()
       
   105         
       
   106     def _clean_test_dir(self):
       
   107         shutil.rmtree(self.test_dir)        
       
   108         
       
   109     def _write_string_to_file(self, string, filepath):
       
   110         f = open(filepath, "w")
       
   111         f.write(string)
       
   112         f.close()        
       
   113     
       
   114     def test_i_can_change_a_link_to_an_xml_file_to_link_to_an_html_file(self):
       
   115         link = etree.Element("cxxStructRef", href="GUID-AE25CF37-B862-306B-B7B3-4A1226B83DA2.xml", navtitle="_SChannels")
       
   116         link = self.dlc._convert_link_to_html(link)
       
   117         self.assertEquals(link.attrib["href"], "GUID-AE25CF37-B862-306B-B7B3-4A1226B83DA2.html")
       
   118         self.assertTrue(link.get("scope", None) and link.attrib["scope"] == "peer")
       
   119         
       
   120     def test_i_can_find_all_link_elements_in_a_tree(self):
       
   121         tree = etree.parse(StringIO(cmap))
       
   122         tree = self.dlc._convert_links(tree)
       
   123         self.assertTrue(tree.find("cxxStructRef").attrib["href"].endswith(".html"))
       
   124         self.assertTrue(tree.find("cxxFileRef").attrib["href"].endswith(".html"))
       
   125         self.assertTrue(tree.find("cxxClassRef").attrib["href"].endswith(".html"))
       
   126         
       
   127     def test_i_can_write_a_converted_map_to_an_output_directory(self):
       
   128         self.dlc._handle_map(self.cmap_path)
       
   129         self.assertTrue(os.path.exists(self.out_dir+os.sep+"cmap.xml"))
       
   130         self.assertEquals(open(self.out_dir+os.sep+"cmap.xml").read(), converted_cmap)
       
   131         
       
   132     def test_i_gracefully_handle_a_link_to_component_map_that_doesnt_exist(self):
       
   133         try:
       
   134             self.dlc._handle_map("non_existsant_ditamap.ditamap")
       
   135         except:
       
   136             self.fail("Didn't handle a component ditamap that doesn't exist")
       
   137         else:
       
   138             pass # Expected (silently handled non existant map)
       
   139         
       
   140     def test_i_parse_all_hrefs_in_a_toc(self):
       
   141         converter = DitamapLinkConverter(self.out_dir, os.getcwd()+os.sep+'toc.ditamap')
       
   142         tree = etree.parse(StringIO(toc))
       
   143         paths = converter._get_component_map_paths(tree)
       
   144         expected = [os.getcwd()+os.sep+"GUID-F59DFBA0-B60B-334A-9B18-4B4E1E756DFA.ditamap"]       
       
   145         self.assertEquals(paths, expected)
       
   146         
       
   147     def test_i_raise_an_exception_if_i_am_given_an_invalid_toc(self):        
       
   148         invalid_toc_path = self.test_dir+os.sep+"invalid_toc.xml"
       
   149         self._write_string_to_file(invalid_toc, invalid_toc_path)
       
   150         dlc = DitamapLinkConverter(self.out_dir, invalid_toc_path)
       
   151         self.assertRaises(DitamapLinkConverterError, dlc.convert)
       
   152            
       
   153 cmap = """<?xml version="1.0" encoding="UTF-8"?>
       
   154 <!DOCTYPE cxxAPIMap PUBLIC "-//NOKIA//DTD DITA C++ API Map Reference Type v0.5.0//EN" "dtd/cxxAPIMap.dtd" >
       
   155 <cxxAPIMap id="GUID-0D9E5D45-5A07-302C-BEB3-2D0252214F2E" title="wlmplatform">
       
   156     <cxxStructRef href="GUID-AE25CF37-B862-306B-B7B3-4A1226B83DA2.xml" navtitle="_SChannels" />
       
   157     <cxxFileRef href="GUID-E1984316-685F-394E-B71A-9816E1495C1F.xml" navtitle="wlanerrorcodes.h" />
       
   158     <cxxClassRef href="GUID-F795E994-BCB6-3040-872A-90F8ADFC75E7.xml" navtitle="MWlanMgmtNotifications" />
       
   159 </cxxAPIMap>
       
   160 """
       
   161                         # 
       
   162 converted_cmap = """<?xml version="1.0" encoding="UTF-8"?>
       
   163 <!DOCTYPE cxxAPIMap PUBLIC "-//NOKIA//DTD DITA C++ API Map Reference Type v0.5.0//EN" "dtd/cxxAPIMap.dtd" >
       
   164 <cxxAPIMap id="GUID-0D9E5D45-5A07-302C-BEB3-2D0252214F2E" title="wlmplatform">
       
   165     <cxxStructRef href="GUID-AE25CF37-B862-306B-B7B3-4A1226B83DA2.html" navtitle="_SChannels" scope="peer" />
       
   166     <cxxFileRef href="GUID-E1984316-685F-394E-B71A-9816E1495C1F.html" navtitle="wlanerrorcodes.h" scope="peer" />
       
   167     <cxxClassRef href="GUID-F795E994-BCB6-3040-872A-90F8ADFC75E7.html" navtitle="MWlanMgmtNotifications" scope="peer" />
       
   168 </cxxAPIMap>"""
       
   169 
       
   170         
       
   171 toc = """<?xml version="1.0" encoding="UTF-8"?>
       
   172 <!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
       
   173 <map id="GUID-445218BA-A6BF-334B-9337-5DCBD993AEB3" title="Symbian^3">
       
   174     <topichead id="GUID-6B11027F-F9AF-3FA0-8A9D-8EA68E3D0F8D" navtitle="Applications">
       
   175         <topichead id="GUID-4766FA96-56F3-3E37-9B2C-6F280673BBA1" navtitle="Camera Apps">
       
   176           <topichead id="GUID-34AB7AC3-E64C-39E0-B6B1-53FEF84566F2" navtitle="s60">
       
   177             <topichead id="GUID-4766FA96-56F3-3E37-9B2C-6F280673BBA1" navtitle="camera">
       
   178               <topicref format="ditamap" href="GUID-F59DFBA0-B60B-334A-9B18-4B4E1E756DFA.ditamap" navtitle="camera" />
       
   179             </topichead>
       
   180             <topichead id="GUID-A0EFE059-67DA-372B-AB98-9DB79584972E" navtitle="camera_help" />
       
   181           </topichead>
       
   182         </topichead>
       
   183      </topichead>
       
   184  </map>
       
   185  """
       
   186  
       
   187 invalid_toc = """<?xml version="1.0" encoding="UTF-8"?
       
   188 <!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
       
   189 <map id="GUID-445218BA-A6BF-334B-9337-5DCBD993AEB3" title="Symbian^3">
       
   190     <topichead id="GUID-6B11027F-F9AF-3FA0-8A9D-8EA68E3D0F8D" navtitle="Applications">
       
   191         <topichead id="GUID-4766FA96-56F3-3E37-9B2C-6F280673BBA1" navtitle="Camera Apps">
       
   192           <topichead id="GUID-34AB7AC3-E64C-39E0-B6B1-53FEF84566F2" navtitle="s60">
       
   193             <topichead id="GUID-4766FA96-56F3-3E37-9B2C-6F280673BBA1" navtitle="camera">
       
   194               <topicref format="ditamap" href="GUID-F59DFBA0-B60B-334A-9B18-4B4E1E756DFA.ditamap" navtitle="camera" />
       
   195             </topichead>
       
   196             <topichead id="GUID-A0EFE059-67DA-372B-AB98-9DB79584972E" navtitle="camera_help" />
       
   197           </topichead>
       
   198         </topichead>
       
   199      </topichead>
       
   200  </map>
       
   201  """