1from __future__ import print_function
2## @file
3# Utility functions and classes for BaseTools unit tests
4#
5#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
6#
7#  SPDX-License-Identifier: BSD-2-Clause-Patent
8#
9
10##
11# Import Modules
12#
13import base64
14import os
15import os.path
16import random
17import shutil
18import subprocess
19import sys
20import unittest
21import codecs
22
23TestsDir = os.path.realpath(os.path.split(sys.argv[0])[0])
24BaseToolsDir = os.path.realpath(os.path.join(TestsDir, '..'))
25CSourceDir = os.path.join(BaseToolsDir, 'Source', 'C')
26PythonSourceDir = os.path.join(BaseToolsDir, 'Source', 'Python')
27TestTempDir = os.path.join(TestsDir, 'TestTempDir')
28
29if PythonSourceDir not in sys.path:
30    #
31    # Allow unit tests to import BaseTools python modules. This is very useful
32    # for writing unit tests.
33    #
34    sys.path.append(PythonSourceDir)
35
36def MakeTheTestSuite(localItems):
37    tests = []
38    for name, item in localItems.items():
39        if isinstance(item, type):
40            if issubclass(item, unittest.TestCase):
41                tests.append(unittest.TestLoader().loadTestsFromTestCase(item))
42            elif issubclass(item, unittest.TestSuite):
43                tests.append(item())
44    return lambda: unittest.TestSuite(tests)
45
46def GetBaseToolsPaths():
47    if sys.platform in ('win32', 'win64'):
48        return [ os.path.join(BaseToolsDir, 'Bin', sys.platform.title()) ]
49    else:
50        uname = os.popen('uname -sm').read().strip()
51        for char in (' ', '/'):
52            uname = uname.replace(char, '-')
53        return [
54                os.path.join(BaseToolsDir, 'Bin', uname),
55                os.path.join(BaseToolsDir, 'BinWrappers', uname),
56                os.path.join(BaseToolsDir, 'BinWrappers', 'PosixLike')
57            ]
58
59BaseToolsBinPaths = GetBaseToolsPaths()
60
61class BaseToolsTest(unittest.TestCase):
62
63    def cleanOutDir(self, dir):
64        for dirItem in os.listdir(dir):
65            if dirItem in ('.', '..'): continue
66            dirItem = os.path.join(dir, dirItem)
67            self.RemoveFileOrDir(dirItem)
68
69    def CleanUpTmpDir(self):
70        if os.path.exists(self.testDir):
71            self.cleanOutDir(self.testDir)
72
73    def HandleTreeDeleteError(self, function, path, excinfo):
74        os.chmod(path, stat.S_IWRITE)
75        function(path)
76
77    def RemoveDir(self, dir):
78        shutil.rmtree(dir, False, self.HandleTreeDeleteError)
79
80    def RemoveFileOrDir(self, path):
81        if not os.path.exists(path):
82            return
83        elif os.path.isdir(path):
84            self.RemoveDir(path)
85        else:
86            os.remove(path)
87
88    def DisplayBinaryData(self, description, data):
89        print(description, '(base64 encoded):')
90        b64data = base64.b64encode(data)
91        print(b64data)
92
93    def DisplayFile(self, fileName):
94        sys.stdout.write(self.ReadTmpFile(fileName))
95        sys.stdout.flush()
96
97    def FindToolBin(self, toolName):
98        for binPath in BaseToolsBinPaths:
99            bin = os.path.join(binPath, toolName)
100            if os.path.exists(bin):
101                break
102        assert os.path.exists(bin)
103        return bin
104
105    def RunTool(self, *args, **kwd):
106        if 'toolName' in kwd: toolName = kwd['toolName']
107        else: toolName = None
108        if 'logFile' in kwd: logFile = kwd['logFile']
109        else: logFile = None
110
111        if toolName is None: toolName = self.toolName
112        bin = self.FindToolBin(toolName)
113        if logFile is not None:
114            logFile = open(os.path.join(self.testDir, logFile), 'w')
115            popenOut = logFile
116        else:
117            popenOut = subprocess.PIPE
118
119        args = [toolName] + list(args)
120
121        Proc = subprocess.Popen(
122            args, executable=bin,
123            stdout=popenOut, stderr=subprocess.STDOUT
124            )
125
126        if logFile is None:
127            Proc.stdout.read()
128
129        return Proc.wait()
130
131    def GetTmpFilePath(self, fileName):
132        return os.path.join(self.testDir, fileName)
133
134    def OpenTmpFile(self, fileName, mode = 'r'):
135        return open(os.path.join(self.testDir, fileName), mode)
136
137    def ReadTmpFile(self, fileName):
138        f = open(self.GetTmpFilePath(fileName), 'r')
139        data = f.read()
140        f.close()
141        return data
142
143    def WriteTmpFile(self, fileName, data):
144        if isinstance(data, bytes):
145            with open(self.GetTmpFilePath(fileName), 'wb') as f:
146                f.write(data)
147        else:
148            with codecs.open(self.GetTmpFilePath(fileName), 'w', encoding='utf-8') as f:
149                f.write(data)
150
151    def GenRandomFileData(self, fileName, minlen = None, maxlen = None):
152        if maxlen is None: maxlen = minlen
153        f = self.OpenTmpFile(fileName, 'w')
154        f.write(self.GetRandomString(minlen, maxlen))
155        f.close()
156
157    def GetRandomString(self, minlen = None, maxlen = None):
158        if minlen is None: minlen = 1024
159        if maxlen is None: maxlen = minlen
160        return ''.join(
161            [chr(random.randint(0, 255))
162             for x in range(random.randint(minlen, maxlen))
163            ])
164
165    def setUp(self):
166        self.savedEnvPath = os.environ['PATH']
167        self.savedSysPath = sys.path[:]
168
169        for binPath in BaseToolsBinPaths:
170            os.environ['PATH'] = \
171                os.path.pathsep.join((os.environ['PATH'], binPath))
172
173        self.testDir = TestTempDir
174        if not os.path.exists(self.testDir):
175            os.mkdir(self.testDir)
176        else:
177            self.cleanOutDir(self.testDir)
178
179    def tearDown(self):
180        self.RemoveFileOrDir(self.testDir)
181
182        os.environ['PATH'] = self.savedEnvPath
183        sys.path = self.savedSysPath
184
185