1#!/usr/bin/env python
2# Copyright 2014 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import unittest
7
8import extract_actions
9
10# Empty value to be inserted to |ACTIONS_MOCK|.
11NO_VALUE = ''
12
13ONE_OWNER = '<owner>name1@google.com</owner>\n'
14TWO_OWNERS = """
15<owner>name1@google.com</owner>\n
16<owner>name2@google.com</owner>\n
17"""
18
19DESCRIPTION = '<description>Description.</description>\n'
20TWO_DESCRIPTIONS = """
21<description>Description.</description>\n
22<description>Description2.</description>\n
23"""
24
25OBSOLETE = '<obsolete>Not used anymore. Replaced by action2.</obsolete>\n'
26TWO_OBSOLETE = '<obsolete>Obsolete1.</obsolete><obsolete>Obsolete2.</obsolete>'
27
28COMMENT = '<!--comment-->'
29
30# A format string to mock the input action.xml file.
31ACTIONS_XML = """
32{comment}
33<actions>
34
35<action name="action1">
36{owners}{obsolete}{description}
37</action>
38
39</actions>"""
40
41NO_OWNER_EXPECTED_XML = (
42    '<actions>\n\n'
43    '<action name="action1">\n'
44    '  <owner>Please list the metric\'s owners. '
45    'Add more owner tags as needed.</owner>\n'
46    '  <description>Description.</description>\n'
47    '</action>\n\n'
48    '</actions>\n'
49)
50
51ONE_OWNER_EXPECTED_XML = (
52    '<actions>\n\n'
53    '<action name="action1">\n'
54    '  <owner>name1@google.com</owner>\n'
55    '  <description>Description.</description>\n'
56    '</action>\n\n'
57    '</actions>\n'
58)
59
60TWO_OWNERS_EXPECTED_XML = (
61    '<actions>\n\n'
62    '<action name="action1">\n'
63    '  <owner>name1@google.com</owner>\n'
64    '  <owner>name2@google.com</owner>\n'
65    '  <description>Description.</description>\n'
66    '</action>\n\n'
67    '</actions>\n'
68)
69
70NO_DESCRIPTION_EXPECTED_XML = (
71    '<actions>\n\n'
72    '<action name="action1">\n'
73    '  <owner>name1@google.com</owner>\n'
74    '  <owner>name2@google.com</owner>\n'
75    '  <description>Please enter the description of the metric.</description>\n'
76    '</action>\n\n'
77    '</actions>\n'
78)
79
80OBSOLETE_EXPECTED_XML = (
81    '<actions>\n\n'
82    '<action name="action1">\n'
83    '  <owner>name1@google.com</owner>\n'
84    '  <owner>name2@google.com</owner>\n'
85    '  <description>Description.</description>\n'
86    '  <obsolete>Not used anymore. Replaced by action2.</obsolete>\n'
87    '</action>\n\n'
88    '</actions>\n'
89)
90
91ADD_ACTION_EXPECTED_XML = (
92    '<actions>\n\n'
93    '<action name="action1">\n'
94    '  <owner>name1@google.com</owner>\n'
95    '  <owner>name2@google.com</owner>\n'
96    '  <description>Description.</description>\n'
97    '</action>\n\n'
98    '<action name="action2">\n'
99    '  <owner>Please list the metric\'s owners.'
100    ' Add more owner tags as needed.</owner>\n'
101    '  <description>Please enter the description of the metric.</description>\n'
102    '</action>\n\n'
103    '</actions>\n'
104)
105
106COMMENT_EXPECTED_XML = (
107    '<!--comment-->\n\n'
108    '<actions>\n\n'
109    '<action name="action1">\n'
110    '  <owner>name1@google.com</owner>\n'
111    '  <owner>name2@google.com</owner>\n'
112    '  <description>Description.</description>\n'
113    '</action>\n\n'
114    '</actions>\n'
115)
116
117
118class ActionXmlTest(unittest.TestCase):
119
120  def _GetProcessedAction(self, owner, description, obsolete, new_actions=[],
121                          comment=NO_VALUE):
122    """Forms an actions XML string and returns it after processing.
123
124    It parses the original XML string, adds new user actions (if there is any),
125    and pretty prints it.
126
127    Args:
128      owner: the owner tag to be inserted in the original XML string.
129      description: the description tag to be inserted in the original XML
130        string.
131      obsolete: the obsolete tag to be inserted in the original XML string.
132      new_actions: optional. List of new user actions' names to be inserted.
133      comment: the comment tag to be inserted in the original XML string.
134
135    Returns:
136      An updated and pretty-printed action XML string.
137    """
138    # Form the actions.xml mock content based on the input parameters.
139    current_xml = ACTIONS_XML.format(owners=owner, description=description,
140                                     obsolete=obsolete, comment=comment)
141    actions, actions_dict, comments = extract_actions.ParseActionFile(
142        current_xml)
143    for new_action in new_actions:
144      actions.add(new_action)
145    return extract_actions.PrettyPrint(actions, actions_dict, comments)
146
147  def testNoOwner(self):
148    xml_result = self._GetProcessedAction(NO_VALUE, DESCRIPTION, NO_VALUE)
149    self.assertEqual(NO_OWNER_EXPECTED_XML, xml_result)
150
151  def testOneOwnerOneDescription(self):
152    xml_result = self._GetProcessedAction(ONE_OWNER, DESCRIPTION, NO_VALUE)
153    self.assertEqual(ONE_OWNER_EXPECTED_XML, xml_result)
154
155  def testTwoOwners(self):
156    xml_result = self._GetProcessedAction(TWO_OWNERS, DESCRIPTION, NO_VALUE)
157    self.assertEqual(TWO_OWNERS_EXPECTED_XML, xml_result)
158
159  def testNoDescription(self):
160    xml_result = self._GetProcessedAction(TWO_OWNERS, NO_VALUE, NO_VALUE)
161    self.assertEqual(NO_DESCRIPTION_EXPECTED_XML, xml_result)
162
163  def testTwoDescriptions(self):
164    current_xml = ACTIONS_XML.format(owners=TWO_OWNERS, obsolete=NO_VALUE,
165                                     description=TWO_DESCRIPTIONS,
166                                     comment=NO_VALUE)
167    # Since there are two description tags, the function ParseActionFile will
168    # raise SystemExit with exit code 1.
169    with self.assertRaises(SystemExit) as cm:
170      _, _ = extract_actions.ParseActionFile(current_xml)
171    self.assertEqual(cm.exception.code, 1)
172
173  def testObsolete(self):
174    xml_result = self._GetProcessedAction(TWO_OWNERS, DESCRIPTION, OBSOLETE)
175    self.assertEqual(OBSOLETE_EXPECTED_XML, xml_result)
176
177
178  def testTwoObsoletes(self):
179    current_xml = ACTIONS_XML.format(owners=TWO_OWNERS, obsolete=TWO_OBSOLETE,
180                                     description=DESCRIPTION, comment=NO_VALUE)
181    # Since there are two obsolete tags, the function ParseActionFile will
182    # raise SystemExit with exit code 1.
183    with self.assertRaises(SystemExit) as cm:
184      _, _ = extract_actions.ParseActionFile(current_xml)
185    self.assertEqual(cm.exception.code, 1)
186
187  def testAddNewActions(self):
188    xml_result = self._GetProcessedAction(TWO_OWNERS, DESCRIPTION, NO_VALUE,
189                                          new_actions=['action2'])
190    self.assertEqual(ADD_ACTION_EXPECTED_XML, xml_result)
191
192  def testComment(self):
193    xml_result = self._GetProcessedAction(TWO_OWNERS, DESCRIPTION, NO_VALUE,
194                                          comment=COMMENT)
195    self.assertEqual(COMMENT_EXPECTED_XML, xml_result)
196
197
198if __name__ == '__main__':
199  unittest.main()
200