1""" Test suite for the code in msilib """
2import os
3import unittest
4from test.support.import_helper import import_module
5from test.support.os_helper import TESTFN, unlink
6import warnings
7with warnings.catch_warnings():
8    warnings.simplefilter("ignore", DeprecationWarning)
9    msilib = import_module('msilib')
10import msilib.schema
11
12
13def init_database():
14    path = TESTFN + '.msi'
15    db = msilib.init_database(
16        path,
17        msilib.schema,
18        'Python Tests',
19        'product_code',
20        '1.0',
21        'PSF',
22    )
23    return db, path
24
25
26class MsiDatabaseTestCase(unittest.TestCase):
27
28    def test_view_fetch_returns_none(self):
29        db, db_path = init_database()
30        properties = []
31        view = db.OpenView('SELECT Property, Value FROM Property')
32        view.Execute(None)
33        while True:
34            record = view.Fetch()
35            if record is None:
36                break
37            properties.append(record.GetString(1))
38        view.Close()
39        db.Close()
40        self.assertEqual(
41            properties,
42            [
43                'ProductName', 'ProductCode', 'ProductVersion',
44                'Manufacturer', 'ProductLanguage',
45            ]
46        )
47        self.addCleanup(unlink, db_path)
48
49    def test_view_non_ascii(self):
50        db, db_path = init_database()
51        view = db.OpenView("SELECT 'ß-розпад' FROM Property")
52        view.Execute(None)
53        record = view.Fetch()
54        self.assertEqual(record.GetString(1), 'ß-розпад')
55        view.Close()
56        db.Close()
57        self.addCleanup(unlink, db_path)
58
59    def test_summaryinfo_getproperty_issue1104(self):
60        db, db_path = init_database()
61        try:
62            sum_info = db.GetSummaryInformation(99)
63            title = sum_info.GetProperty(msilib.PID_TITLE)
64            self.assertEqual(title, b"Installation Database")
65
66            sum_info.SetProperty(msilib.PID_TITLE, "a" * 999)
67            title = sum_info.GetProperty(msilib.PID_TITLE)
68            self.assertEqual(title, b"a" * 999)
69
70            sum_info.SetProperty(msilib.PID_TITLE, "a" * 1000)
71            title = sum_info.GetProperty(msilib.PID_TITLE)
72            self.assertEqual(title, b"a" * 1000)
73
74            sum_info.SetProperty(msilib.PID_TITLE, "a" * 1001)
75            title = sum_info.GetProperty(msilib.PID_TITLE)
76            self.assertEqual(title, b"a" * 1001)
77        finally:
78            db = None
79            sum_info = None
80            os.unlink(db_path)
81
82    def test_database_open_failed(self):
83        with self.assertRaises(msilib.MSIError) as cm:
84            msilib.OpenDatabase('non-existent.msi', msilib.MSIDBOPEN_READONLY)
85        self.assertEqual(str(cm.exception), 'open failed')
86
87    def test_database_create_failed(self):
88        db_path = os.path.join(TESTFN, 'test.msi')
89        with self.assertRaises(msilib.MSIError) as cm:
90            msilib.OpenDatabase(db_path, msilib.MSIDBOPEN_CREATE)
91        self.assertEqual(str(cm.exception), 'create failed')
92
93    def test_get_property_vt_empty(self):
94        db, db_path = init_database()
95        summary = db.GetSummaryInformation(0)
96        self.assertIsNone(summary.GetProperty(msilib.PID_SECURITY))
97        db.Close()
98        self.addCleanup(unlink, db_path)
99
100    def test_directory_start_component_keyfile(self):
101        db, db_path = init_database()
102        self.addCleanup(unlink, db_path)
103        self.addCleanup(db.Close)
104        self.addCleanup(msilib._directories.clear)
105        feature = msilib.Feature(db, 0, 'Feature', 'A feature', 'Python')
106        cab = msilib.CAB('CAB')
107        dir = msilib.Directory(db, cab, None, TESTFN, 'TARGETDIR',
108                               'SourceDir', 0)
109        dir.start_component(None, feature, None, 'keyfile')
110
111    def test_getproperty_uninitialized_var(self):
112        db, db_path = init_database()
113        self.addCleanup(unlink, db_path)
114        self.addCleanup(db.Close)
115        si = db.GetSummaryInformation(0)
116        with self.assertRaises(msilib.MSIError):
117            si.GetProperty(-1)
118
119    def test_FCICreate(self):
120        filepath = TESTFN + '.txt'
121        cabpath = TESTFN + '.cab'
122        self.addCleanup(unlink, filepath)
123        with open(filepath, 'wb'):
124            pass
125        self.addCleanup(unlink, cabpath)
126        msilib.FCICreate(cabpath, [(filepath, 'test.txt')])
127        self.assertTrue(os.path.isfile(cabpath))
128
129
130class Test_make_id(unittest.TestCase):
131    #http://msdn.microsoft.com/en-us/library/aa369212(v=vs.85).aspx
132    """The Identifier data type is a text string. Identifiers may contain the
133    ASCII characters A-Z (a-z), digits, underscores (_), or periods (.).
134    However, every identifier must begin with either a letter or an
135    underscore.
136    """
137
138    def test_is_no_change_required(self):
139        self.assertEqual(
140            msilib.make_id("short"), "short")
141        self.assertEqual(
142            msilib.make_id("nochangerequired"), "nochangerequired")
143        self.assertEqual(
144            msilib.make_id("one.dot"), "one.dot")
145        self.assertEqual(
146            msilib.make_id("_"), "_")
147        self.assertEqual(
148            msilib.make_id("a"), "a")
149        #self.assertEqual(
150        #    msilib.make_id(""), "")
151
152    def test_invalid_first_char(self):
153        self.assertEqual(
154            msilib.make_id("9.short"), "_9.short")
155        self.assertEqual(
156            msilib.make_id(".short"), "_.short")
157
158    def test_invalid_any_char(self):
159        self.assertEqual(
160            msilib.make_id(".s\x82ort"), "_.s_ort")
161        self.assertEqual(
162            msilib.make_id(".s\x82o?*+rt"), "_.s_o___rt")
163
164
165if __name__ == '__main__':
166    unittest.main()
167