|
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 """ |