1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# BitBake Test for lib/bb/parse/ 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Copyright (C) 2015 Richard Purdie 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 7*4882a593Smuzhiyun# 8*4882a593Smuzhiyun 9*4882a593Smuzhiyunimport unittest 10*4882a593Smuzhiyunimport tempfile 11*4882a593Smuzhiyunimport logging 12*4882a593Smuzhiyunimport bb 13*4882a593Smuzhiyunimport os 14*4882a593Smuzhiyun 15*4882a593Smuzhiyunlogger = logging.getLogger('BitBake.TestParse') 16*4882a593Smuzhiyun 17*4882a593Smuzhiyunimport bb.parse 18*4882a593Smuzhiyunimport bb.data 19*4882a593Smuzhiyunimport bb.siggen 20*4882a593Smuzhiyun 21*4882a593Smuzhiyunclass ParseTest(unittest.TestCase): 22*4882a593Smuzhiyun 23*4882a593Smuzhiyun testfile = """ 24*4882a593SmuzhiyunA = "1" 25*4882a593SmuzhiyunB = "2" 26*4882a593Smuzhiyundo_install() { 27*4882a593Smuzhiyun echo "hello" 28*4882a593Smuzhiyun} 29*4882a593Smuzhiyun 30*4882a593SmuzhiyunC = "3" 31*4882a593Smuzhiyun""" 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun def setUp(self): 34*4882a593Smuzhiyun self.origdir = os.getcwd() 35*4882a593Smuzhiyun self.d = bb.data.init() 36*4882a593Smuzhiyun bb.parse.siggen = bb.siggen.init(self.d) 37*4882a593Smuzhiyun 38*4882a593Smuzhiyun def tearDown(self): 39*4882a593Smuzhiyun os.chdir(self.origdir) 40*4882a593Smuzhiyun 41*4882a593Smuzhiyun def parsehelper(self, content, suffix = ".bb"): 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun f = tempfile.NamedTemporaryFile(suffix = suffix) 44*4882a593Smuzhiyun f.write(bytes(content, "utf-8")) 45*4882a593Smuzhiyun f.flush() 46*4882a593Smuzhiyun os.chdir(os.path.dirname(f.name)) 47*4882a593Smuzhiyun return f 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun def test_parse_simple(self): 50*4882a593Smuzhiyun f = self.parsehelper(self.testfile) 51*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 52*4882a593Smuzhiyun self.assertEqual(d.getVar("A"), "1") 53*4882a593Smuzhiyun self.assertEqual(d.getVar("B"), "2") 54*4882a593Smuzhiyun self.assertEqual(d.getVar("C"), "3") 55*4882a593Smuzhiyun 56*4882a593Smuzhiyun def test_parse_incomplete_function(self): 57*4882a593Smuzhiyun testfileB = self.testfile.replace("}", "") 58*4882a593Smuzhiyun f = self.parsehelper(testfileB) 59*4882a593Smuzhiyun with self.assertRaises(bb.parse.ParseError): 60*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun unsettest = """ 63*4882a593SmuzhiyunA = "1" 64*4882a593SmuzhiyunB = "2" 65*4882a593SmuzhiyunB[flag] = "3" 66*4882a593Smuzhiyun 67*4882a593Smuzhiyununset A 68*4882a593Smuzhiyununset B[flag] 69*4882a593Smuzhiyun""" 70*4882a593Smuzhiyun 71*4882a593Smuzhiyun def test_parse_unset(self): 72*4882a593Smuzhiyun f = self.parsehelper(self.unsettest) 73*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 74*4882a593Smuzhiyun self.assertEqual(d.getVar("A"), None) 75*4882a593Smuzhiyun self.assertEqual(d.getVarFlag("A","flag"), None) 76*4882a593Smuzhiyun self.assertEqual(d.getVar("B"), "2") 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun exporttest = """ 79*4882a593SmuzhiyunA = "a" 80*4882a593Smuzhiyunexport B = "b" 81*4882a593Smuzhiyunexport C 82*4882a593SmuzhiyunexportD = "d" 83*4882a593Smuzhiyun""" 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun def test_parse_exports(self): 86*4882a593Smuzhiyun f = self.parsehelper(self.exporttest) 87*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 88*4882a593Smuzhiyun self.assertEqual(d.getVar("A"), "a") 89*4882a593Smuzhiyun self.assertIsNone(d.getVarFlag("A", "export")) 90*4882a593Smuzhiyun self.assertEqual(d.getVar("B"), "b") 91*4882a593Smuzhiyun self.assertEqual(d.getVarFlag("B", "export"), 1) 92*4882a593Smuzhiyun self.assertIsNone(d.getVar("C")) 93*4882a593Smuzhiyun self.assertEqual(d.getVarFlag("C", "export"), 1) 94*4882a593Smuzhiyun self.assertIsNone(d.getVar("D")) 95*4882a593Smuzhiyun self.assertIsNone(d.getVarFlag("D", "export")) 96*4882a593Smuzhiyun self.assertEqual(d.getVar("exportD"), "d") 97*4882a593Smuzhiyun self.assertIsNone(d.getVarFlag("exportD", "export")) 98*4882a593Smuzhiyun 99*4882a593Smuzhiyun 100*4882a593Smuzhiyun overridetest = """ 101*4882a593SmuzhiyunRRECOMMENDS:${PN} = "a" 102*4882a593SmuzhiyunRRECOMMENDS:${PN}:libc = "b" 103*4882a593SmuzhiyunOVERRIDES = "libc:${PN}" 104*4882a593SmuzhiyunPN = "gtk+" 105*4882a593Smuzhiyun""" 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun def test_parse_overrides(self): 108*4882a593Smuzhiyun f = self.parsehelper(self.overridetest) 109*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 110*4882a593Smuzhiyun self.assertEqual(d.getVar("RRECOMMENDS"), "b") 111*4882a593Smuzhiyun bb.data.expandKeys(d) 112*4882a593Smuzhiyun self.assertEqual(d.getVar("RRECOMMENDS"), "b") 113*4882a593Smuzhiyun d.setVar("RRECOMMENDS:gtk+", "c") 114*4882a593Smuzhiyun self.assertEqual(d.getVar("RRECOMMENDS"), "c") 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun overridetest2 = """ 117*4882a593SmuzhiyunEXTRA_OECONF = "" 118*4882a593SmuzhiyunEXTRA_OECONF:class-target = "b" 119*4882a593SmuzhiyunEXTRA_OECONF:append = " c" 120*4882a593Smuzhiyun""" 121*4882a593Smuzhiyun 122*4882a593Smuzhiyun def test_parse_overrides2(self): 123*4882a593Smuzhiyun f = self.parsehelper(self.overridetest2) 124*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 125*4882a593Smuzhiyun d.appendVar("EXTRA_OECONF", " d") 126*4882a593Smuzhiyun d.setVar("OVERRIDES", "class-target") 127*4882a593Smuzhiyun self.assertEqual(d.getVar("EXTRA_OECONF"), "b c d") 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun overridetest3 = """ 130*4882a593SmuzhiyunDESCRIPTION = "A" 131*4882a593SmuzhiyunDESCRIPTION:${PN}-dev = "${DESCRIPTION} B" 132*4882a593SmuzhiyunPN = "bc" 133*4882a593Smuzhiyun""" 134*4882a593Smuzhiyun 135*4882a593Smuzhiyun def test_parse_combinations(self): 136*4882a593Smuzhiyun f = self.parsehelper(self.overridetest3) 137*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 138*4882a593Smuzhiyun bb.data.expandKeys(d) 139*4882a593Smuzhiyun self.assertEqual(d.getVar("DESCRIPTION:bc-dev"), "A B") 140*4882a593Smuzhiyun d.setVar("DESCRIPTION", "E") 141*4882a593Smuzhiyun d.setVar("DESCRIPTION:bc-dev", "C D") 142*4882a593Smuzhiyun d.setVar("OVERRIDES", "bc-dev") 143*4882a593Smuzhiyun self.assertEqual(d.getVar("DESCRIPTION"), "C D") 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun 146*4882a593Smuzhiyun classextend = """ 147*4882a593SmuzhiyunVAR_var:override1 = "B" 148*4882a593SmuzhiyunEXTRA = ":override1" 149*4882a593SmuzhiyunOVERRIDES = "nothing${EXTRA}" 150*4882a593Smuzhiyun 151*4882a593SmuzhiyunBBCLASSEXTEND = "###CLASS###" 152*4882a593Smuzhiyun""" 153*4882a593Smuzhiyun classextend_bbclass = """ 154*4882a593SmuzhiyunEXTRA = "" 155*4882a593Smuzhiyunpython () { 156*4882a593Smuzhiyun d.renameVar("VAR_var", "VAR_var2") 157*4882a593Smuzhiyun} 158*4882a593Smuzhiyun""" 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun # 161*4882a593Smuzhiyun # Test based upon a real world data corruption issue. One 162*4882a593Smuzhiyun # data store changing a variable poked through into a different data 163*4882a593Smuzhiyun # store. This test case replicates that issue where the value 'B' would 164*4882a593Smuzhiyun # become unset/disappear. 165*4882a593Smuzhiyun # 166*4882a593Smuzhiyun def test_parse_classextend_contamination(self): 167*4882a593Smuzhiyun cls = self.parsehelper(self.classextend_bbclass, suffix=".bbclass") 168*4882a593Smuzhiyun #clsname = os.path.basename(cls.name).replace(".bbclass", "") 169*4882a593Smuzhiyun self.classextend = self.classextend.replace("###CLASS###", cls.name) 170*4882a593Smuzhiyun f = self.parsehelper(self.classextend) 171*4882a593Smuzhiyun alldata = bb.parse.handle(f.name, self.d) 172*4882a593Smuzhiyun d1 = alldata[''] 173*4882a593Smuzhiyun d2 = alldata[cls.name] 174*4882a593Smuzhiyun self.assertEqual(d1.getVar("VAR_var"), "B") 175*4882a593Smuzhiyun self.assertEqual(d2.getVar("VAR_var"), None) 176*4882a593Smuzhiyun 177*4882a593Smuzhiyun addtask_deltask = """ 178*4882a593Smuzhiyunaddtask do_patch after do_foo after do_unpack before do_configure before do_compile 179*4882a593Smuzhiyunaddtask do_fetch do_patch 180*4882a593Smuzhiyun 181*4882a593SmuzhiyunMYVAR = "do_patch" 182*4882a593SmuzhiyunEMPTYVAR = "" 183*4882a593Smuzhiyundeltask do_fetch ${MYVAR} ${EMPTYVAR} 184*4882a593Smuzhiyundeltask ${EMPTYVAR} 185*4882a593Smuzhiyun""" 186*4882a593Smuzhiyun def test_parse_addtask_deltask(self): 187*4882a593Smuzhiyun import sys 188*4882a593Smuzhiyun f = self.parsehelper(self.addtask_deltask) 189*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 190*4882a593Smuzhiyun 191*4882a593Smuzhiyun stdout = sys.stdout.getvalue() 192*4882a593Smuzhiyun self.assertTrue("addtask contained multiple 'before' keywords" in stdout) 193*4882a593Smuzhiyun self.assertTrue("addtask contained multiple 'after' keywords" in stdout) 194*4882a593Smuzhiyun self.assertTrue('addtask ignored: " do_patch"' in stdout) 195*4882a593Smuzhiyun #self.assertTrue('dependent task do_foo for do_patch does not exist' in stdout) 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun broken_multiline_comment = """ 198*4882a593Smuzhiyun# First line of comment \\ 199*4882a593Smuzhiyun# Second line of comment \\ 200*4882a593Smuzhiyun 201*4882a593Smuzhiyun""" 202*4882a593Smuzhiyun def test_parse_broken_multiline_comment(self): 203*4882a593Smuzhiyun f = self.parsehelper(self.broken_multiline_comment) 204*4882a593Smuzhiyun with self.assertRaises(bb.BBHandledException): 205*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 206*4882a593Smuzhiyun 207*4882a593Smuzhiyun 208*4882a593Smuzhiyun comment_in_var = """ 209*4882a593SmuzhiyunVAR = " \\ 210*4882a593Smuzhiyun SOMEVAL \\ 211*4882a593Smuzhiyun# some comment \\ 212*4882a593Smuzhiyun SOMEOTHERVAL \\ 213*4882a593Smuzhiyun" 214*4882a593Smuzhiyun""" 215*4882a593Smuzhiyun def test_parse_comment_in_var(self): 216*4882a593Smuzhiyun f = self.parsehelper(self.comment_in_var) 217*4882a593Smuzhiyun with self.assertRaises(bb.BBHandledException): 218*4882a593Smuzhiyun d = bb.parse.handle(f.name, self.d)[''] 219*4882a593Smuzhiyun 220