1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4#############################################################################
5##
6## Copyright (C) 2016 The Qt Company Ltd.
7## Contact: https://www.qt.io/licensing/
8##
9## This file is part of the test suite of Qt for Python.
10##
11## $QT_BEGIN_LICENSE:GPL-EXCEPT$
12## Commercial License Usage
13## Licensees holding valid commercial Qt licenses may use this file in
14## accordance with the commercial license agreement provided with the
15## Software or, alternatively, in accordance with the terms contained in
16## a written agreement between you and The Qt Company. For licensing terms
17## and conditions see https://www.qt.io/terms-conditions. For further
18## information use the contact form at https://www.qt.io/contact-us.
19##
20## GNU General Public License Usage
21## Alternatively, this file may be used under the terms of the GNU
22## General Public License version 3 as published by the Free Software
23## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
24## included in the packaging of this file. Please review the following
25## information to ensure the GNU General Public License requirements will
26## be met: https://www.gnu.org/licenses/gpl-3.0.html.
27##
28## $QT_END_LICENSE$
29##
30#############################################################################
31
32'''Test cases for multiple inheritance'''
33
34import os
35import sys
36import unittest
37
38sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
39from shiboken_paths import init_paths
40init_paths()
41
42from sample import Base1, Base2, Base3, Base4, Base5, Base6
43from sample import MDerived1, MDerived2, MDerived3, MDerived4, MDerived5, SonOfMDerived1
44
45class ExtMDerived1(MDerived1):
46    def __init__(self):
47        MDerived1.__init__(self)
48        self.multiplier = 20
49        self.base2Method_called = False
50    def base2Method(self):
51        return Base2.base2Method(self) * self.multiplier
52
53class MultipleDerivedTest(unittest.TestCase):
54    '''Test cases for multiple inheritance'''
55
56    def testIsInstance(self):
57        '''MDerived1 is instance of its parents Base1 and Base2.'''
58        a = MDerived1()
59        self.assertTrue(isinstance(a, MDerived1))
60        self.assertTrue(isinstance(a, Base1))
61        self.assertTrue(isinstance(a, Base2))
62
63    def testIsSubclass(self):
64        '''MDerived1 is subclass of its parents Base1 and Base2.'''
65        self.assertTrue(issubclass(MDerived1, Base1))
66        self.assertTrue(issubclass(MDerived1, Base2))
67
68    def testCallToFunctionWithBase1ArgumentThatCastsBackToMDerived1(self):
69        '''MDerived1 is passed as an Base1 argument to a method that returns it casted back to MDerived1.'''
70        a = MDerived1()
71        b = MDerived1.transformFromBase1(a)
72        self.assertEqual(a, b)
73
74    def testCallToFunctionWithBase2ArgumentThatCastsBackToMDerived1(self):
75        '''MDerived1 is passed as an Base2 argument to a method that returns it casted back to MDerived1.'''
76        a = MDerived1()
77        b = MDerived1.transformFromBase2(a)
78        self.assertEqual(a, b)
79
80    def testPythonClassIsInstance(self):
81        '''Python defined class ExtMDerived1 is instance of its parents MDerived1, Base1 and Base2.'''
82        a = ExtMDerived1()
83        self.assertTrue(isinstance(a, ExtMDerived1))
84        self.assertTrue(isinstance(a, MDerived1))
85        self.assertTrue(isinstance(a, Base1))
86        self.assertTrue(isinstance(a, Base2))
87
88    def testPythonClassIsSubclass(self):
89        '''Python defined class ExtMDerived1 is subclass of its parents MDerived1, Base1 and Base2.'''
90        self.assertTrue(issubclass(ExtMDerived1, MDerived1))
91        self.assertTrue(issubclass(ExtMDerived1, Base1))
92        self.assertTrue(issubclass(ExtMDerived1, Base2))
93
94    def testCastFromMDerived1ToBases(self):
95        '''MDerived1 is casted by C++ to its parents and the binding must return the MDerived1 wrapper.'''
96        a = MDerived1()
97        refcnt = sys.getrefcount(a)
98        b1 = a.castToBase1()
99        b2 = a.castToBase2()
100        self.assertTrue(isinstance(b1, MDerived1))
101        self.assertTrue(isinstance(b2, MDerived1))
102        self.assertEqual(a, b1)
103        self.assertEqual(a, b2)
104        self.assertEqual(sys.getrefcount(a), refcnt + 2)
105
106    def testCastFromExtMDerived1ToMDerived1Bases(self):
107        '''Python defined class ExtMDerived1 is casted by C++ to MDerived1 parents and the binding must return the correct ExtMDerived1 instance.'''
108        a = ExtMDerived1()
109        refcnt = sys.getrefcount(a)
110        b1 = a.castToBase1()
111        self.assertTrue(isinstance(b1, MDerived1))
112        self.assertTrue(isinstance(b1, ExtMDerived1))
113        b2 = a.castToBase2()
114        self.assertTrue(isinstance(b2, MDerived1))
115        self.assertTrue(isinstance(b2, ExtMDerived1))
116        self.assertEqual(a, b1)
117        self.assertEqual(a, b2)
118        self.assertEqual(sys.getrefcount(a), refcnt + 2)
119
120    def testCastFromSonOfMDerived1ToBases(self):
121        '''SonOfMDerived1 is casted by C++ to its parents and the binding must return the SonOfMDerived1 wrapper.'''
122        a = SonOfMDerived1()
123        refcnt = sys.getrefcount(a)
124        md1 = a.castToMDerived1()
125        b1 = a.castToBase1()
126        b2 = a.castToBase2()
127        self.assertTrue(isinstance(md1, SonOfMDerived1))
128        self.assertTrue(isinstance(b2, SonOfMDerived1))
129        self.assertTrue(isinstance(b2, SonOfMDerived1))
130        self.assertEqual(a, md1)
131        self.assertEqual(a, b1)
132        self.assertEqual(a, b2)
133        self.assertEqual(sys.getrefcount(a), refcnt + 3)
134
135    def testReimplementedBase2VirtualMethodOnClassInheritingFromMDerived1(self):
136        a = ExtMDerived1()
137        value = a.base2Method()
138        self.assertTrue(value, Base2.base2Method(a) * a.multiplier)
139
140    def testCastFromMDerived2ToBases(self):
141        '''MDerived2 is casted by C++ to its parents and the binding must return the MDerived2 wrapper.'''
142        a = MDerived2()
143        refcnt = sys.getrefcount(a)
144        b3 = a.castToBase3()
145        b4 = a.castToBase4()
146        b5 = a.castToBase5()
147        b6 = a.castToBase6()
148        self.assertTrue(isinstance(b3, MDerived2))
149        self.assertTrue(isinstance(b4, MDerived2))
150        self.assertTrue(isinstance(b5, MDerived2))
151        self.assertTrue(isinstance(b6, MDerived2))
152        self.assertEqual(a, b3)
153        self.assertEqual(a, b4)
154        self.assertEqual(a, b5)
155        self.assertEqual(a, b6)
156        self.assertEqual(sys.getrefcount(a), refcnt + 4)
157
158    def testCastFromMDerived3ToBases(self):
159        '''MDerived3 is casted by C++ to its parents and the binding must return the MDerived3 wrapper.'''
160        a = MDerived3()
161        refcnt = sys.getrefcount(a)
162        md1 = a.castToMDerived1()
163        md2 = a.castToMDerived2()
164        b1 = a.castToBase1()
165        b2 = a.castToBase2()
166        b3 = a.castToBase3()
167        b4 = a.castToBase4()
168        b5 = a.castToBase5()
169        b6 = a.castToBase6()
170        self.assertTrue(isinstance(md1, MDerived3))
171        self.assertTrue(isinstance(md2, MDerived3))
172        self.assertTrue(isinstance(b1, MDerived3))
173        self.assertTrue(isinstance(b2, MDerived3))
174        self.assertTrue(isinstance(b3, MDerived3))
175        self.assertTrue(isinstance(b4, MDerived3))
176        self.assertTrue(isinstance(b5, MDerived3))
177        self.assertTrue(isinstance(b6, MDerived3))
178        self.assertEqual(a, md1)
179        self.assertEqual(a, md2)
180        self.assertEqual(a, b1)
181        self.assertEqual(a, b2)
182        self.assertEqual(a, b3)
183        self.assertEqual(a, b4)
184        self.assertEqual(a, b5)
185        self.assertEqual(a, b6)
186        self.assertEqual(sys.getrefcount(a), refcnt + 8)
187
188    def testCastFromMDerived4ToBases(self):
189        '''MDerived4 is casted by C++ to its parents and the binding must return the MDerived4 wrapper.'''
190        a = MDerived4()
191        refcnt = sys.getrefcount(a)
192        b3 = a.castToBase3()
193        b4 = a.castToBase4()
194        self.assertTrue(isinstance(b3, MDerived4))
195        self.assertTrue(isinstance(b4, MDerived4))
196        self.assertEqual(a, b3)
197        self.assertEqual(a, b4)
198        self.assertEqual(sys.getrefcount(a), refcnt + 2)
199
200    def testCastFromMDerived5ToBases(self):
201        '''MDerived5 is casted by C++ to its parents and the binding must return the MDerived5 wrapper.'''
202        a = MDerived5()
203        refcnt = sys.getrefcount(a)
204        b3 = a.castToBase3()
205        b4 = a.castToBase4()
206        self.assertTrue(isinstance(b3, MDerived5))
207        self.assertTrue(isinstance(b4, MDerived5))
208        self.assertEqual(a, b3)
209        self.assertEqual(a, b4)
210        self.assertEqual(sys.getrefcount(a), refcnt + 2)
211
212    def testCastFromMDerived3ToBase3(self):
213        '''MDerived3 is casted by C++ to Base3 grandparent using both the inherited and reimplement castToBase3 methods.'''
214        a = MDerived3()
215        refcnt = sys.getrefcount(a)
216        b3_reimplemented = a.castToBase3()
217        b3_inherited = MDerived2.castToBase3(a)
218        self.assertTrue(isinstance(b3_reimplemented, MDerived3))
219        self.assertTrue(isinstance(b3_inherited, MDerived3))
220        self.assertEqual(a, b3_reimplemented)
221        self.assertEqual(a, b3_inherited)
222        self.assertEqual(sys.getrefcount(a), refcnt + 2)
223
224if __name__ == '__main__':
225    unittest.main()
226
227