1<?php
2/**
3 * @covers PHPUnit_Framework_MockObject_Generator
4 *
5 * @uses PHPUnit_Framework_MockObject_InvocationMocker
6 * @uses PHPUnit_Framework_MockObject_Builder_InvocationMocker
7 * @uses PHPUnit_Framework_MockObject_Invocation_Object
8 * @uses PHPUnit_Framework_MockObject_Invocation_Static
9 * @uses PHPUnit_Framework_MockObject_Matcher
10 * @uses PHPUnit_Framework_MockObject_Matcher_InvokedRecorder
11 * @uses PHPUnit_Framework_MockObject_Matcher_MethodName
12 * @uses PHPUnit_Framework_MockObject_Stub_Return
13 * @uses PHPUnit_Framework_MockObject_Matcher_InvokedCount
14 */
15class Framework_MockObject_GeneratorTest extends PHPUnit_Framework_TestCase
16{
17    /**
18     * @var PHPUnit_Framework_MockObject_Generator
19     */
20    private $generator;
21
22    protected function setUp()
23    {
24        $this->generator = new PHPUnit_Framework_MockObject_Generator;
25    }
26
27    /**
28     * @expectedException PHPUnit_Framework_MockObject_RuntimeException
29     */
30    public function testGetMockFailsWhenInvalidFunctionNameIsPassedInAsAFunctionToMock()
31    {
32        $this->generator->getMock(stdClass::class, [0]);
33    }
34
35    public function testGetMockCanCreateNonExistingFunctions()
36    {
37        $mock = $this->generator->getMock(stdClass::class, ['testFunction']);
38
39        $this->assertTrue(method_exists($mock, 'testFunction'));
40    }
41
42    /**
43     * @expectedException PHPUnit_Framework_MockObject_RuntimeException
44     * @expectedExceptionMessage duplicates: "foo, bar, foo" (duplicate: "foo")
45     */
46    public function testGetMockGeneratorFails()
47    {
48        $this->generator->getMock(stdClass::class, ['foo', 'bar', 'foo']);
49    }
50
51    /**
52     * @requires PHP 7
53     */
54    public function testGetMockBlacklistedMethodNamesPhp7()
55    {
56        $mock = $this->generator->getMock(InterfaceWithSemiReservedMethodName::class);
57
58        $this->assertTrue(method_exists($mock, 'unset'));
59        $this->assertInstanceOf(InterfaceWithSemiReservedMethodName::class, $mock);
60    }
61
62    public function testGetMockForAbstractClassDoesNotFailWhenFakingInterfaces()
63    {
64        $mock = $this->generator->getMockForAbstractClass(Countable::class);
65
66        $this->assertTrue(method_exists($mock, 'count'));
67    }
68
69    public function testGetMockForAbstractClassStubbingAbstractClass()
70    {
71        $mock = $this->generator->getMockForAbstractClass(AbstractMockTestClass::class);
72
73        $this->assertTrue(method_exists($mock, 'doSomething'));
74    }
75
76    public function testGetMockForAbstractClassWithNonExistentMethods()
77    {
78        $mock = $this->generator->getMockForAbstractClass(
79            AbstractMockTestClass::class,
80            [],
81            '',
82            true,
83            true,
84            true,
85            ['nonexistentMethod']
86        );
87
88        $this->assertTrue(method_exists($mock, 'nonexistentMethod'));
89        $this->assertTrue(method_exists($mock, 'doSomething'));
90    }
91
92    public function testGetMockForAbstractClassShouldCreateStubsOnlyForAbstractMethodWhenNoMethodsWereInformed()
93    {
94        $mock = $this->generator->getMockForAbstractClass(AbstractMockTestClass::class);
95
96        $mock->expects($this->any())
97             ->method('doSomething')
98             ->willReturn('testing');
99
100        $this->assertEquals('testing', $mock->doSomething());
101        $this->assertEquals(1, $mock->returnAnything());
102    }
103
104    /**
105     * @dataProvider getMockForAbstractClassExpectsInvalidArgumentExceptionDataprovider
106     * @expectedException PHPUnit_Framework_Exception
107     */
108    public function testGetMockForAbstractClassExpectingInvalidArgumentException($className, $mockClassName)
109    {
110        $this->generator->getMockForAbstractClass($className, [], $mockClassName);
111    }
112
113    /**
114     * @expectedException PHPUnit_Framework_MockObject_RuntimeException
115     */
116    public function testGetMockForAbstractClassAbstractClassDoesNotExist()
117    {
118        $this->generator->getMockForAbstractClass('Tux');
119    }
120
121    public function getMockForAbstractClassExpectsInvalidArgumentExceptionDataprovider()
122    {
123        return [
124            'className not a string'     => [[], ''],
125            'mockClassName not a string' => [Countable::class, new stdClass],
126        ];
127    }
128
129    public function testGetMockForTraitWithNonExistentMethodsAndNonAbstractMethods()
130    {
131        $mock = $this->generator->getMockForTrait(
132            AbstractTrait::class,
133            [],
134            '',
135            true,
136            true,
137            true,
138            ['nonexistentMethod']
139        );
140
141        $this->assertTrue(method_exists($mock, 'nonexistentMethod'));
142        $this->assertTrue(method_exists($mock, 'doSomething'));
143        $this->assertTrue($mock->mockableMethod());
144        $this->assertTrue($mock->anotherMockableMethod());
145    }
146
147    public function testGetMockForTraitStubbingAbstractMethod()
148    {
149        $mock = $this->generator->getMockForTrait(AbstractTrait::class);
150
151        $this->assertTrue(method_exists($mock, 'doSomething'));
152    }
153
154    public function testGetMockForSingletonWithReflectionSuccess()
155    {
156        $mock = $this->generator->getMock(SingletonClass::class, ['doSomething'], [], '', false);
157
158        $this->assertInstanceOf('SingletonClass', $mock);
159    }
160
161    /**
162     * @expectedException PHPUnit_Framework_MockObject_RuntimeException
163     */
164    public function testExceptionIsRaisedForMutuallyExclusiveOptions()
165    {
166        $this->generator->getMock(stdClass::class, [], [], '', false, true, true, true, true);
167    }
168
169    /**
170     * @requires PHP 7
171     */
172    public function testCanImplementInterfacesThatHaveMethodsWithReturnTypes()
173    {
174        $stub = $this->generator->getMock([AnInterfaceWithReturnType::class, AnInterface::class]);
175
176        $this->assertInstanceOf(AnInterfaceWithReturnType::class, $stub);
177        $this->assertInstanceOf(AnInterface::class, $stub);
178        $this->assertInstanceOf(PHPUnit_Framework_MockObject_MockObject::class, $stub);
179    }
180
181    public function testCanConfigureMethodsForDoubleOfNonExistentClass()
182    {
183        $className = 'X' . md5(microtime());
184
185        $mock = $this->generator->getMock($className, ['someMethod']);
186
187        $this->assertInstanceOf($className, $mock);
188    }
189
190    public function testCanInvokeMethodsOfNonExistentClass()
191    {
192        $className = 'X' . md5(microtime());
193
194        $mock = $this->generator->getMock($className, ['someMethod']);
195
196        $mock->expects($this->once())->method('someMethod');
197
198        $this->assertNull($mock->someMethod());
199    }
200}
201