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