|
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 os |
|
14 import unittest |
|
15 import xml |
|
16 import re |
|
17 import sys |
|
18 from optparse import OptionParser |
|
19 from cStringIO import StringIO |
|
20 from xml.etree import ElementTree as etree |
|
21 |
|
22 nmtoken_regex = re.compile("[^a-zA-Z0-9_\.]") |
|
23 |
|
24 def scan(dir): |
|
25 for root, _, files in os.walk(dir): |
|
26 for fname in files: |
|
27 yield os.path.join(root, fname) |
|
28 |
|
29 def xml_decl(): |
|
30 return """<?xml version="1.0" encoding="UTF-8"?>""" |
|
31 |
|
32 def doctype_identifier(doctype): |
|
33 """ |
|
34 Return a doctype declaration string for a given doctype. |
|
35 Understands DITA and cxxapiref DITA specialisation doctypes. |
|
36 """ |
|
37 # DITA Doctype Identifiers (no specific version number in identifier means latest DITA DTD version) |
|
38 if doctype == "map": |
|
39 return """<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">""" |
|
40 elif doctype == "topic": |
|
41 return """<!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">""" |
|
42 elif doctype == "task": |
|
43 return """<!DOCTYPE task PUBLIC "-//OASIS//DTD DITA Task//EN" "task.dtd">""" |
|
44 elif doctype == "reference": |
|
45 return """<!DOCTYPE reference PUBLIC "-//OASIS//DTD DITA Reference//EN" "reference.dtd">""" |
|
46 elif doctype == "glossary": |
|
47 return """<!DOCTYPE glossary PUBLIC "-//OASIS//DTD DITA Glossary//EN" "glossary.dtd">""" |
|
48 elif doctype == "concept": |
|
49 return """<!DOCTYPE concept PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">""" |
|
50 elif doctype == "bookmap": |
|
51 return """<!DOCTYPE bookmap PUBLIC "-//OASIS//DTD DITA BookMap//EN" "bookmap.dtd">""" |
|
52 # cxxapiref DITA specialisation Doctype Identifiers |
|
53 elif doctype == "cxxUnion": |
|
54 return """<!DOCTYPE cxxUnion PUBLIC "-//NOKIA//DTD DITA C++ API Union Reference Type v0.5.0//EN" "dtd/cxxUnion.dtd">""" |
|
55 elif doctype == "cxxStruct": |
|
56 return """<!DOCTYPE cxxStruct PUBLIC "-//NOKIA//DTD DITA C++ API Struct Reference Type v0.5.0//EN" "dtd/cxxStruct.dtd">""" |
|
57 elif doctype == "cxxPackage": |
|
58 return """<!DOCTYPE cxxPackage PUBLIC "-//NOKIA//DTD DITA cxx API Package Reference Type v0.5.0//EN" "dtd/cxxPackage.dtd">""" |
|
59 elif doctype == "cxxFile": |
|
60 return """<!DOCTYPE cxxFile PUBLIC "-//NOKIA//DTD DITA C++ API File Reference Type v0.5.0//EN" "dtd/cxxFile.dtd">""" |
|
61 elif doctype == "cxxClass": |
|
62 return """<!DOCTYPE cxxClass PUBLIC "-//NOKIA//DTD DITA C++ API Class Reference Type v0.5.0//EN" "dtd/cxxClass.dtd">""" |
|
63 elif doctype == "cxxAPIMap": |
|
64 return """<!DOCTYPE cxxAPIMap PUBLIC "-//NOKIA//DTD DITA C++ API Map Reference Type v0.5.0//EN" "dtd/cxxAPIMap.dtd" >""" |
|
65 else: |
|
66 raise Exception('Unknown Doctype \"%s\"' % doctype) |
|
67 |
|
68 def get_valid_nmtoken(attribute_value): |
|
69 new_value = attribute_value |
|
70 matches = nmtoken_regex.findall(new_value) |
|
71 for char in set(matches): |
|
72 new_value = new_value.replace(char,"") |
|
73 return new_value |
|
74 |
|
75 class XmlParser(object): |
|
76 """ |
|
77 Simple class that reads an XML and returns its id |
|
78 |
|
79 >>> xp = XmlParser() |
|
80 >>> xp.parse(StringIO("<root id='rootid'>some content</root>")) |
|
81 'rootid' |
|
82 """ |
|
83 def parse(self, xmlfile): |
|
84 try: |
|
85 root = etree.parse(xmlfile).getroot() |
|
86 except xml.parsers.expat.ExpatError, e: |
|
87 sys.stderr.write("ERROR: %s could not be parse: %s\n" % (xmlfile, str(e))) |
|
88 return "" |
|
89 if 'id' not in root.attrib: |
|
90 return "" |
|
91 return root.attrib['id'] |
|
92 |
|
93 def main(func, version): |
|
94 usage = "usage: %prog <Path to the XML content>" |
|
95 parser = OptionParser(usage, version='%prog ' + version) |
|
96 (options, args) = parser.parse_args() |
|
97 if len(args) < 1: |
|
98 parser.print_help() |
|
99 parser.error("Please supply the path to the XML content") |
|
100 func(args[0]) |
|
101 |
|
102 ###################################### |
|
103 # Test code |
|
104 ###################################### |
|
105 |
|
106 class Testxml_decl(unittest.TestCase): |
|
107 def testi_can_return_anxml_declaration(self): |
|
108 self.assertEquals(xml_decl(), """<?xml version="1.0" encoding="UTF-8"?>""") |
|
109 |
|
110 |
|
111 class Testdoctype_identifier(unittest.TestCase): |
|
112 |
|
113 def test_i_raise_an_exception_for_an_unknown_doctype(self): |
|
114 self.assertRaises(Exception, doctype_identifier, "invaliddoctype") |
|
115 |
|
116 def test_i_can_return_a_map_doctype_identifier(self): |
|
117 self.assertEquals(doctype_identifier("map"), """<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">""") |
|
118 |
|
119 def test_i_can_return_a_topic_doctype_identifier(self): |
|
120 self.assertEquals(doctype_identifier("topic"), """<!DOCTYPE topic PUBLIC "-//OASIS//DTD DITA Topic//EN" "topic.dtd">""") |
|
121 |
|
122 def test_i_can_return_a_task_doctype_identifier(self): |
|
123 self.assertEquals(doctype_identifier("task"), """<!DOCTYPE task PUBLIC "-//OASIS//DTD DITA Task//EN" "task.dtd">""") |
|
124 |
|
125 def test_i_can_return_a_reference_doctype_identifier(self): |
|
126 self.assertEquals(doctype_identifier("reference"), """<!DOCTYPE reference PUBLIC "-//OASIS//DTD DITA Reference//EN" "reference.dtd">""") |
|
127 |
|
128 def test_i_can_return_a_glossary_doctype_identifier(self): |
|
129 self.assertEquals(doctype_identifier("glossary"), """<!DOCTYPE glossary PUBLIC "-//OASIS//DTD DITA Glossary//EN" "glossary.dtd">""") |
|
130 |
|
131 def test_i_can_return_a_concept_doctype_identifier(self): |
|
132 self.assertEquals(doctype_identifier("concept"), """<!DOCTYPE concept PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">""") |
|
133 |
|
134 def test_i_can_return_a_bookmap_doctype_identifier(self): |
|
135 self.assertEquals(doctype_identifier("bookmap"), """<!DOCTYPE bookmap PUBLIC "-//OASIS//DTD DITA BookMap//EN" "bookmap.dtd">""") |
|
136 |
|
137 def test_i_can_return_a_cxxUnion_doctype_identifier(self): |
|
138 self.assertEquals(doctype_identifier("cxxUnion"), """<!DOCTYPE cxxUnion PUBLIC "-//NOKIA//DTD DITA C++ API Union Reference Type v0.5.0//EN" "dtd/cxxUnion.dtd">""") |
|
139 |
|
140 def test_i_can_return_a_cxxStruct_doctype_identifier(self): |
|
141 self.assertEquals(doctype_identifier("cxxStruct"), """<!DOCTYPE cxxStruct PUBLIC "-//NOKIA//DTD DITA C++ API Struct Reference Type v0.5.0//EN" "dtd/cxxStruct.dtd">""") |
|
142 |
|
143 def test_i_can_return_a_cxxPackage_doctype_identifier(self): |
|
144 self.assertEquals(doctype_identifier("cxxPackage"), """<!DOCTYPE cxxPackage PUBLIC "-//NOKIA//DTD DITA cxx API Package Reference Type v0.5.0//EN" "dtd/cxxPackage.dtd">""") |
|
145 |
|
146 def test_i_can_return_a_cxxFile_doctype_identifier(self): |
|
147 self.assertEquals(doctype_identifier("cxxFile"), """<!DOCTYPE cxxFile PUBLIC "-//NOKIA//DTD DITA C++ API File Reference Type v0.5.0//EN" "dtd/cxxFile.dtd">""") |
|
148 |
|
149 def test_i_can_return_a_cxxClass_doctype_identifier(self): |
|
150 self.assertEquals(doctype_identifier("cxxClass"), """<!DOCTYPE cxxClass PUBLIC "-//NOKIA//DTD DITA C++ API Class Reference Type v0.5.0//EN" "dtd/cxxClass.dtd">""") |
|
151 |
|
152 def test_i_can_return_a_cxxAPIMap_doctype_identifier(self): |
|
153 self.assertEquals(doctype_identifier("cxxAPIMap"), """<!DOCTYPE cxxAPIMap PUBLIC "-//NOKIA//DTD DITA C++ API Map Reference Type v0.5.0//EN" "dtd/cxxAPIMap.dtd" >""") |
|
154 |
|
155 |
|
156 class Testget_valid_nmtoken(unittest.TestCase): |
|
157 |
|
158 def test_i_remove_non_alpha_numeric_characters(self): |
|
159 input = "this is an alphanumeric string with non alpha numeric characters inside.()_+=-string0123456789" |
|
160 expout = "thisisanalphanumericstringwithnonalphanumericcharactersinside._string0123456789" |
|
161 output = get_valid_nmtoken(input) |
|
162 self.assertEquals(output, expout) |
|
163 |
|
164 |
|
165 class StubXmlParser(object): |
|
166 def parse(self, path): |
|
167 return "GUID-BED8A733-2ED7-31AD-A911-C1F4707C67F" |
|
168 |
|
169 |
|
170 class TestXmlParser(unittest.TestCase): |
|
171 def test_i_issue_a_warning_and_continue_if_a_file_is_invalid(self): |
|
172 xml = XmlParser() |
|
173 try: |
|
174 xml.parse(StringIO("<foo><bar</foo>")) |
|
175 except Exception, e: |
|
176 self.fail("I shouldn't have raised an exception. Exception was %s" % e) |
|
177 |
|
178 def test_i_issue_a_warning_and_continue_if_a_file_does_not_have_an_id(self): |
|
179 xml = XmlParser() |
|
180 try: |
|
181 id = xml.parse(StringIO(brokencxxclass)) |
|
182 except Exception: |
|
183 self.fail("I shouldn't have raised an exception") |
|
184 self.assertTrue(id == "") |
|
185 |
|
186 def test_i_return_a_files_id(self): |
|
187 xml = XmlParser() |
|
188 id = xml.parse(StringIO(cxxclass)) |
|
189 self.assertTrue(id == "class_c_active_scheduler") |
|
190 |
|
191 brokencxxclass = """<?xml version='1.0' encoding='UTF-8' standalone='no'?> |
|
192 <!DOCTYPE cxxClass PUBLIC "-//NOKIA//DTD DITA C++ API Class Reference Type v0.5.0//EN" "dtd/cxxClass.dtd" > |
|
193 <cxxClass> |
|
194 <apiName>CActiveScheduler</apiName> |
|
195 <shortdesc/> |
|
196 </cxxClass> |
|
197 """ |
|
198 |
|
199 cxxclass = """<?xml version='1.0' encoding='UTF-8' standalone='no'?> |
|
200 <!DOCTYPE cxxClass PUBLIC "-//NOKIA//DTD DITA C++ API Class Reference Type v0.5.0//EN" "dtd/cxxClass.dtd" > |
|
201 <cxxClass id="class_c_active_scheduler"> |
|
202 <apiName>CActiveScheduler</apiName> |
|
203 <shortdesc/> |
|
204 </cxxClass> |
|
205 """ |