xref: /aosp_15_r20/build/make/tools/test_post_process_props.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*9e94795aSAndroid Build Coastguard Worker#
3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2020 The Android Open Source Project
4*9e94795aSAndroid Build Coastguard Worker#
5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*9e94795aSAndroid Build Coastguard Worker#
9*9e94795aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*9e94795aSAndroid Build Coastguard Worker#
11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*9e94795aSAndroid Build Coastguard Worker# limitations under the License.
16*9e94795aSAndroid Build Coastguard Worker
17*9e94795aSAndroid Build Coastguard Workerimport contextlib
18*9e94795aSAndroid Build Coastguard Workerimport io
19*9e94795aSAndroid Build Coastguard Workerimport unittest
20*9e94795aSAndroid Build Coastguard Worker
21*9e94795aSAndroid Build Coastguard Workerfrom unittest.mock import *
22*9e94795aSAndroid Build Coastguard Workerfrom post_process_props import *
23*9e94795aSAndroid Build Coastguard Worker
24*9e94795aSAndroid Build Coastguard Workerclass PropTestCase(unittest.TestCase):
25*9e94795aSAndroid Build Coastguard Worker  def test_createFromLine(self):
26*9e94795aSAndroid Build Coastguard Worker    p = Prop.from_line("# this is comment")
27*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(p.is_comment())
28*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("", p.name)
29*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("", p.value)
30*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(p.is_optional())
31*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("# this is comment", str(p))
32*9e94795aSAndroid Build Coastguard Worker
33*9e94795aSAndroid Build Coastguard Worker    for line in ["a=b", "a = b", "a= b", "a =b", "  a=b   "]:
34*9e94795aSAndroid Build Coastguard Worker      p = Prop.from_line(line)
35*9e94795aSAndroid Build Coastguard Worker      self.assertFalse(p.is_comment())
36*9e94795aSAndroid Build Coastguard Worker      self.assertEqual("a", p.name)
37*9e94795aSAndroid Build Coastguard Worker      self.assertEqual("b", p.value)
38*9e94795aSAndroid Build Coastguard Worker      self.assertFalse(p.is_optional())
39*9e94795aSAndroid Build Coastguard Worker      self.assertEqual("a=b", str(p))
40*9e94795aSAndroid Build Coastguard Worker
41*9e94795aSAndroid Build Coastguard Worker    for line in ["a?=b", "a ?= b", "a?= b", "a ?=b", "  a?=b   "]:
42*9e94795aSAndroid Build Coastguard Worker      p = Prop.from_line(line)
43*9e94795aSAndroid Build Coastguard Worker      self.assertFalse(p.is_comment())
44*9e94795aSAndroid Build Coastguard Worker      self.assertEqual("a", p.name)
45*9e94795aSAndroid Build Coastguard Worker      self.assertEqual("b", p.value)
46*9e94795aSAndroid Build Coastguard Worker      self.assertTrue(p.is_optional())
47*9e94795aSAndroid Build Coastguard Worker      self.assertEqual("a?=b", str(p))
48*9e94795aSAndroid Build Coastguard Worker
49*9e94795aSAndroid Build Coastguard Worker  def test_makeAsComment(self):
50*9e94795aSAndroid Build Coastguard Worker    p = Prop.from_line("a=b")
51*9e94795aSAndroid Build Coastguard Worker    p.comments.append("# a comment")
52*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(p.is_comment())
53*9e94795aSAndroid Build Coastguard Worker
54*9e94795aSAndroid Build Coastguard Worker    p.make_as_comment()
55*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(p.is_comment())
56*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("# a comment\n#a=b", str(p))
57*9e94795aSAndroid Build Coastguard Worker
58*9e94795aSAndroid Build Coastguard Workerclass PropListTestcase(unittest.TestCase):
59*9e94795aSAndroid Build Coastguard Worker  def setUp(self):
60*9e94795aSAndroid Build Coastguard Worker    content = """
61*9e94795aSAndroid Build Coastguard Worker    # comment
62*9e94795aSAndroid Build Coastguard Worker    foo=true
63*9e94795aSAndroid Build Coastguard Worker    bar=false
64*9e94795aSAndroid Build Coastguard Worker    qux?=1
65*9e94795aSAndroid Build Coastguard Worker    # another comment
66*9e94795aSAndroid Build Coastguard Worker    foo?=false
67*9e94795aSAndroid Build Coastguard Worker    """
68*9e94795aSAndroid Build Coastguard Worker    self.patcher = patch("post_process_props.open", mock_open(read_data=content))
69*9e94795aSAndroid Build Coastguard Worker    self.mock_open = self.patcher.start()
70*9e94795aSAndroid Build Coastguard Worker    self.props = PropList("file")
71*9e94795aSAndroid Build Coastguard Worker
72*9e94795aSAndroid Build Coastguard Worker  def tearDown(self):
73*9e94795aSAndroid Build Coastguard Worker    self.patcher.stop()
74*9e94795aSAndroid Build Coastguard Worker    self.props = None
75*9e94795aSAndroid Build Coastguard Worker
76*9e94795aSAndroid Build Coastguard Worker  def test_readFromFile(self):
77*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(4, len(self.props.get_all_props()))
78*9e94795aSAndroid Build Coastguard Worker    expected = [
79*9e94795aSAndroid Build Coastguard Worker        ("foo", "true", False),
80*9e94795aSAndroid Build Coastguard Worker        ("bar", "false", False),
81*9e94795aSAndroid Build Coastguard Worker        ("qux", "1", True),
82*9e94795aSAndroid Build Coastguard Worker        ("foo", "false", True)
83*9e94795aSAndroid Build Coastguard Worker    ]
84*9e94795aSAndroid Build Coastguard Worker    for i,p in enumerate(self.props.get_all_props()):
85*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(expected[i][0], p.name)
86*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(expected[i][1], p.value)
87*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(expected[i][2], p.is_optional())
88*9e94795aSAndroid Build Coastguard Worker      self.assertFalse(p.is_comment())
89*9e94795aSAndroid Build Coastguard Worker
90*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(set(["foo", "bar", "qux"]), self.props.get_all_names())
91*9e94795aSAndroid Build Coastguard Worker
92*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("true", self.props.get_value("foo"))
93*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("false", self.props.get_value("bar"))
94*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("1", self.props.get_value("qux"))
95*9e94795aSAndroid Build Coastguard Worker
96*9e94795aSAndroid Build Coastguard Worker    # there are two assignments for 'foo'
97*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(2, len(self.props.get_props("foo")))
98*9e94795aSAndroid Build Coastguard Worker
99*9e94795aSAndroid Build Coastguard Worker  def test_putNewProp(self):
100*9e94795aSAndroid Build Coastguard Worker    self.props.put("new", "30")
101*9e94795aSAndroid Build Coastguard Worker
102*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(5, len(self.props.get_all_props()))
103*9e94795aSAndroid Build Coastguard Worker    last_prop = self.props.get_all_props()[-1]
104*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("new", last_prop.name)
105*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("30", last_prop.value)
106*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(last_prop.is_optional())
107*9e94795aSAndroid Build Coastguard Worker
108*9e94795aSAndroid Build Coastguard Worker  def test_putExistingNonOptionalProp(self):
109*9e94795aSAndroid Build Coastguard Worker    self.props.put("foo", "NewValue")
110*9e94795aSAndroid Build Coastguard Worker
111*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(4, len(self.props.get_all_props()))
112*9e94795aSAndroid Build Coastguard Worker    foo_prop = self.props.get_props("foo")[0]
113*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("foo", foo_prop.name)
114*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("NewValue", foo_prop.value)
115*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(foo_prop.is_optional())
116*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("# Value overridden by post_process_props.py. " +
117*9e94795aSAndroid Build Coastguard Worker                     "Original value: true\nfoo=NewValue", str(foo_prop))
118*9e94795aSAndroid Build Coastguard Worker
119*9e94795aSAndroid Build Coastguard Worker  def test_putExistingOptionalProp(self):
120*9e94795aSAndroid Build Coastguard Worker    self.props.put("qux", "2")
121*9e94795aSAndroid Build Coastguard Worker
122*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(5, len(self.props.get_all_props()))
123*9e94795aSAndroid Build Coastguard Worker    last_prop = self.props.get_all_props()[-1]
124*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("qux", last_prop.name)
125*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("2", last_prop.value)
126*9e94795aSAndroid Build Coastguard Worker    self.assertFalse(last_prop.is_optional())
127*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("# Auto-added by post_process_props.py\nqux=2",
128*9e94795aSAndroid Build Coastguard Worker                     str(last_prop))
129*9e94795aSAndroid Build Coastguard Worker
130*9e94795aSAndroid Build Coastguard Worker  def test_deleteNonOptionalProp(self):
131*9e94795aSAndroid Build Coastguard Worker    props_to_delete = self.props.get_props("foo")[0]
132*9e94795aSAndroid Build Coastguard Worker    props_to_delete.delete(reason="testing")
133*9e94795aSAndroid Build Coastguard Worker
134*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(3, len(self.props.get_all_props()))
135*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("# Removed by post_process_props.py because testing\n" +
136*9e94795aSAndroid Build Coastguard Worker                     "#foo=true", str(props_to_delete))
137*9e94795aSAndroid Build Coastguard Worker
138*9e94795aSAndroid Build Coastguard Worker  def test_deleteOptionalProp(self):
139*9e94795aSAndroid Build Coastguard Worker    props_to_delete = self.props.get_props("qux")[0]
140*9e94795aSAndroid Build Coastguard Worker    props_to_delete.delete(reason="testing")
141*9e94795aSAndroid Build Coastguard Worker
142*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(3, len(self.props.get_all_props()))
143*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("# Removed by post_process_props.py because testing\n" +
144*9e94795aSAndroid Build Coastguard Worker                     "#qux?=1", str(props_to_delete))
145*9e94795aSAndroid Build Coastguard Worker
146*9e94795aSAndroid Build Coastguard Worker  def test_overridingNonOptional(self):
147*9e94795aSAndroid Build Coastguard Worker    props_to_be_overridden = self.props.get_props("foo")[1]
148*9e94795aSAndroid Build Coastguard Worker    self.assertTrue("true", props_to_be_overridden.value)
149*9e94795aSAndroid Build Coastguard Worker
150*9e94795aSAndroid Build Coastguard Worker    self.assertTrue(override_optional_props(self.props))
151*9e94795aSAndroid Build Coastguard Worker
152*9e94795aSAndroid Build Coastguard Worker    # size reduced to 3 because foo?=false was overridden by foo=true
153*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(3, len(self.props.get_all_props()))
154*9e94795aSAndroid Build Coastguard Worker
155*9e94795aSAndroid Build Coastguard Worker    self.assertEqual(1, len(self.props.get_props("foo")))
156*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("true", self.props.get_props("foo")[0].value)
157*9e94795aSAndroid Build Coastguard Worker
158*9e94795aSAndroid Build Coastguard Worker    self.assertEqual("# Removed by post_process_props.py because " +
159*9e94795aSAndroid Build Coastguard Worker                     "overridden by foo=true\n#foo?=false",
160*9e94795aSAndroid Build Coastguard Worker                     str(props_to_be_overridden))
161*9e94795aSAndroid Build Coastguard Worker
162*9e94795aSAndroid Build Coastguard Worker  def test_overridingOptional(self):
163*9e94795aSAndroid Build Coastguard Worker    content = """
164*9e94795aSAndroid Build Coastguard Worker    # comment
165*9e94795aSAndroid Build Coastguard Worker    qux?=2
166*9e94795aSAndroid Build Coastguard Worker    foo=true
167*9e94795aSAndroid Build Coastguard Worker    bar=false
168*9e94795aSAndroid Build Coastguard Worker    qux?=1
169*9e94795aSAndroid Build Coastguard Worker    # another comment
170*9e94795aSAndroid Build Coastguard Worker    foo?=false
171*9e94795aSAndroid Build Coastguard Worker    """
172*9e94795aSAndroid Build Coastguard Worker    with patch('post_process_props.open', mock_open(read_data=content)) as m:
173*9e94795aSAndroid Build Coastguard Worker      props = PropList("hello")
174*9e94795aSAndroid Build Coastguard Worker
175*9e94795aSAndroid Build Coastguard Worker      props_to_be_overridden = props.get_props("qux")[0]
176*9e94795aSAndroid Build Coastguard Worker      self.assertEqual("2", props_to_be_overridden.value)
177*9e94795aSAndroid Build Coastguard Worker
178*9e94795aSAndroid Build Coastguard Worker      self.assertTrue(override_optional_props(props))
179*9e94795aSAndroid Build Coastguard Worker
180*9e94795aSAndroid Build Coastguard Worker      self.assertEqual(1, len(props.get_props("qux")))
181*9e94795aSAndroid Build Coastguard Worker      self.assertEqual("1", props.get_props("qux")[0].value)
182*9e94795aSAndroid Build Coastguard Worker      # the only left optional assignment becomes non-optional
183*9e94795aSAndroid Build Coastguard Worker      self.assertFalse(props.get_props("qux")[0].is_optional())
184*9e94795aSAndroid Build Coastguard Worker
185*9e94795aSAndroid Build Coastguard Worker      self.assertEqual("# Removed by post_process_props.py because " +
186*9e94795aSAndroid Build Coastguard Worker                       "overridden by qux?=1\n#qux?=2",
187*9e94795aSAndroid Build Coastguard Worker                       str(props_to_be_overridden))
188*9e94795aSAndroid Build Coastguard Worker
189*9e94795aSAndroid Build Coastguard Worker  def test_overridingDuplicated(self):
190*9e94795aSAndroid Build Coastguard Worker    content = """
191*9e94795aSAndroid Build Coastguard Worker    # comment
192*9e94795aSAndroid Build Coastguard Worker    foo=true
193*9e94795aSAndroid Build Coastguard Worker    bar=false
194*9e94795aSAndroid Build Coastguard Worker    qux?=1
195*9e94795aSAndroid Build Coastguard Worker    foo=false
196*9e94795aSAndroid Build Coastguard Worker    # another comment
197*9e94795aSAndroid Build Coastguard Worker    foo?=false
198*9e94795aSAndroid Build Coastguard Worker    """
199*9e94795aSAndroid Build Coastguard Worker    with patch("post_process_props.open", mock_open(read_data=content)) as m:
200*9e94795aSAndroid Build Coastguard Worker      stderr_redirect = io.StringIO()
201*9e94795aSAndroid Build Coastguard Worker      with contextlib.redirect_stderr(stderr_redirect):
202*9e94795aSAndroid Build Coastguard Worker        props = PropList("hello")
203*9e94795aSAndroid Build Coastguard Worker
204*9e94795aSAndroid Build Coastguard Worker        # fails due to duplicated foo=true and foo=false
205*9e94795aSAndroid Build Coastguard Worker        self.assertFalse(override_optional_props(props))
206*9e94795aSAndroid Build Coastguard Worker
207*9e94795aSAndroid Build Coastguard Worker        self.assertEqual("error: found duplicate sysprop assignments:\n" +
208*9e94795aSAndroid Build Coastguard Worker                         "foo=true\nfoo=false\n", stderr_redirect.getvalue())
209*9e94795aSAndroid Build Coastguard Worker
210*9e94795aSAndroid Build Coastguard Worker  def test_overridingDuplicatedWithSameValue(self):
211*9e94795aSAndroid Build Coastguard Worker    content = """
212*9e94795aSAndroid Build Coastguard Worker    # comment
213*9e94795aSAndroid Build Coastguard Worker    foo=true
214*9e94795aSAndroid Build Coastguard Worker    bar=false
215*9e94795aSAndroid Build Coastguard Worker    qux?=1
216*9e94795aSAndroid Build Coastguard Worker    foo=true
217*9e94795aSAndroid Build Coastguard Worker    # another comment
218*9e94795aSAndroid Build Coastguard Worker    foo?=false
219*9e94795aSAndroid Build Coastguard Worker    """
220*9e94795aSAndroid Build Coastguard Worker    with patch("post_process_props.open", mock_open(read_data=content)) as m:
221*9e94795aSAndroid Build Coastguard Worker      stderr_redirect = io.StringIO()
222*9e94795aSAndroid Build Coastguard Worker      with contextlib.redirect_stderr(stderr_redirect):
223*9e94795aSAndroid Build Coastguard Worker        props = PropList("hello")
224*9e94795aSAndroid Build Coastguard Worker        optional_prop = props.get_props("foo")[2] # the last foo?=false one
225*9e94795aSAndroid Build Coastguard Worker
226*9e94795aSAndroid Build Coastguard Worker        # we have duplicated foo=true and foo=true, but that's allowed
227*9e94795aSAndroid Build Coastguard Worker        # since they have the same value
228*9e94795aSAndroid Build Coastguard Worker        self.assertTrue(override_optional_props(props))
229*9e94795aSAndroid Build Coastguard Worker
230*9e94795aSAndroid Build Coastguard Worker        # foo?=false should be commented out
231*9e94795aSAndroid Build Coastguard Worker        self.assertEqual("# Removed by post_process_props.py because " +
232*9e94795aSAndroid Build Coastguard Worker                         "overridden by foo=true\n#foo?=false",
233*9e94795aSAndroid Build Coastguard Worker                         str(optional_prop))
234*9e94795aSAndroid Build Coastguard Worker
235*9e94795aSAndroid Build Coastguard Worker  def test_allowDuplicates(self):
236*9e94795aSAndroid Build Coastguard Worker    content = """
237*9e94795aSAndroid Build Coastguard Worker    # comment
238*9e94795aSAndroid Build Coastguard Worker    foo=true
239*9e94795aSAndroid Build Coastguard Worker    bar=false
240*9e94795aSAndroid Build Coastguard Worker    qux?=1
241*9e94795aSAndroid Build Coastguard Worker    foo=false
242*9e94795aSAndroid Build Coastguard Worker    # another comment
243*9e94795aSAndroid Build Coastguard Worker    foo?=false
244*9e94795aSAndroid Build Coastguard Worker    """
245*9e94795aSAndroid Build Coastguard Worker    with patch("post_process_props.open", mock_open(read_data=content)) as m:
246*9e94795aSAndroid Build Coastguard Worker      stderr_redirect = io.StringIO()
247*9e94795aSAndroid Build Coastguard Worker      with contextlib.redirect_stderr(stderr_redirect):
248*9e94795aSAndroid Build Coastguard Worker        props = PropList("hello")
249*9e94795aSAndroid Build Coastguard Worker
250*9e94795aSAndroid Build Coastguard Worker        # we have duplicated foo=true and foo=false, but that's allowed
251*9e94795aSAndroid Build Coastguard Worker        # because it's explicitly allowed
252*9e94795aSAndroid Build Coastguard Worker        self.assertTrue(override_optional_props(props, allow_dup=True))
253*9e94795aSAndroid Build Coastguard Worker
254*9e94795aSAndroid Build Coastguard Worker  def test_validateGrfProps(self):
255*9e94795aSAndroid Build Coastguard Worker    stderr_redirect = io.StringIO()
256*9e94795aSAndroid Build Coastguard Worker    with contextlib.redirect_stderr(stderr_redirect):
257*9e94795aSAndroid Build Coastguard Worker      props = PropList("hello")
258*9e94795aSAndroid Build Coastguard Worker      props.put("ro.board.first_api_level","202504")
259*9e94795aSAndroid Build Coastguard Worker      props.put("ro.build.version.codename", "REL")
260*9e94795aSAndroid Build Coastguard Worker
261*9e94795aSAndroid Build Coastguard Worker      # manually set ro.board.api_level to an invalid value
262*9e94795aSAndroid Build Coastguard Worker      props.put("ro.board.api_level","202404")
263*9e94795aSAndroid Build Coastguard Worker      self.assertFalse(validate_grf_props(props))
264*9e94795aSAndroid Build Coastguard Worker
265*9e94795aSAndroid Build Coastguard Worker      props.get_all_props()[-1].make_as_comment()
266*9e94795aSAndroid Build Coastguard Worker      # manually set ro.board.api_level to a valid value
267*9e94795aSAndroid Build Coastguard Worker      props.put("ro.board.api_level","202504")
268*9e94795aSAndroid Build Coastguard Worker      self.assertTrue(validate_grf_props(props))
269*9e94795aSAndroid Build Coastguard Worker
270*9e94795aSAndroid Build Coastguard Workerif __name__ == '__main__':
271*9e94795aSAndroid Build Coastguard Worker    unittest.main(verbosity=2)
272