Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
23 | final class GenericEntityRemoveControllerTest extends TestCase |
||
24 | { |
||
25 | |||
26 | private GenericEntityRemoveController $controller; |
||
|
|||
27 | |||
28 | private ControllerHelperInterface $controllerHelper; |
||
29 | |||
30 | public function setUp() |
||
31 | { |
||
32 | $this->controllerHelper = $this->createMock(ControllerHelperInterface::class); |
||
33 | |||
34 | $this->controller = new GenericEntityRemoveController($this->controllerHelper, [ |
||
35 | 'entity-class' => SampleEntity::class |
||
36 | ]); |
||
37 | } |
||
38 | |||
39 | /** |
||
40 | * @test |
||
41 | */ |
||
42 | public function shouldRejectMissingEntityClass() |
||
43 | { |
||
44 | $this->expectException(InvalidArgumentException::class); |
||
45 | |||
46 | new GenericEntityRemoveController($this->controllerHelper, []); |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * @test |
||
51 | */ |
||
52 | public function shouldThrowExceptionIfEntityNotFound() |
||
53 | { |
||
54 | $this->expectException(InvalidArgumentException::class); |
||
55 | |||
56 | $this->controller->removeEntity("some-id"); |
||
57 | } |
||
58 | |||
59 | /** |
||
60 | * @test |
||
61 | */ |
||
62 | public function shouldRemoveEntity() |
||
63 | { |
||
64 | $entity = new SampleEntity(); |
||
65 | |||
66 | $this->controllerHelper->expects($this->once())->method('findEntity')->with( |
||
67 | $this->equalTo(SampleEntity::class), |
||
68 | $this->equalTo('some-id') |
||
69 | )->willReturn($entity); |
||
70 | |||
71 | $this->controllerHelper->expects($this->once())->method('removeEntity')->with( |
||
72 | $this->identicalTo($entity) |
||
73 | ); |
||
74 | |||
75 | /** @var Response $response */ |
||
76 | $response = $this->controller->removeEntity("some-id"); |
||
77 | |||
78 | $this->assertEquals(200, $response->getStatusCode()); |
||
79 | $this->assertEquals('Entity removed!', $response->getContent()); |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * @test |
||
84 | */ |
||
85 | public function shouldCheckIfAccessIsGranted() |
||
86 | { |
||
87 | $this->expectException(AccessDeniedException::class); |
||
88 | |||
89 | $entity = new SampleEntity(); |
||
90 | |||
91 | $this->controllerHelper->expects($this->once())->method('findEntity')->with( |
||
92 | $this->equalTo(SampleEntity::class), |
||
93 | $this->equalTo("some-id") |
||
94 | )->willReturn($entity); |
||
95 | |||
96 | $this->controllerHelper->expects($this->once())->method('denyAccessUnlessGranted')->with( |
||
97 | $this->equalTo('some-attribute'), |
||
98 | $this->identicalTo($entity) |
||
99 | )->will($this->returnCallback( |
||
100 | function () { |
||
101 | throw new AccessDeniedException('Lorem ipsum!'); |
||
102 | } |
||
103 | )); |
||
104 | |||
105 | $controller = new GenericEntityRemoveController($this->controllerHelper, [ |
||
106 | 'entity-class' => SampleEntity::class, |
||
107 | 'authorization-attribute' => 'some-attribute', |
||
108 | ]); |
||
109 | |||
110 | $controller->removeEntity("some-id"); |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * @test |
||
115 | */ |
||
116 | public function shouldBeCallableByInvokingController() |
||
117 | { |
||
118 | $entity = new SampleEntity(); |
||
119 | |||
120 | $this->controllerHelper->expects($this->once())->method('findEntity')->with( |
||
121 | $this->equalTo(SampleEntity::class), |
||
122 | $this->equalTo('some-id') |
||
123 | )->willReturn($entity); |
||
124 | $this->controllerHelper->expects($this->once())->method('dispatchEvent')->with( |
||
125 | $this->equalTo("symfony_generics.entity_interaction"), |
||
126 | $this->equalTo(new EntityInteractionEvent( |
||
127 | SampleEntity::class, |
||
128 | 'some-id', |
||
129 | $entity, |
||
130 | "__destruct" |
||
131 | )) |
||
132 | ); |
||
133 | |||
134 | $this->controllerHelper->expects($this->once())->method('removeEntity')->with( |
||
135 | $this->identicalTo($entity) |
||
136 | ); |
||
137 | |||
138 | /** @var Request $request */ |
||
139 | $request = $this->createMock(Request::class); |
||
140 | $request->method("get")->willReturn('some-id'); |
||
141 | |||
142 | $this->controllerHelper->method('getCurrentRequest')->willReturn($request); |
||
143 | |||
144 | /** @var Response $actualResponse */ |
||
145 | $actualResponse = ($this->controller)(); |
||
146 | |||
147 | $this->assertEquals(200, $actualResponse->getStatusCode()); |
||
148 | $this->assertEquals('Entity removed!', $actualResponse->getContent()); |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * @test |
||
153 | */ |
||
154 | public function shouldRejectCallWithoutRequest() |
||
155 | { |
||
156 | $this->expectException(InvalidArgumentException::class); |
||
157 | |||
158 | $controller = new GenericEntityRemoveController($this->controllerHelper, [ |
||
159 | 'entity-class' => SampleEntity::class, |
||
160 | ]); |
||
161 | |||
162 | $this->controllerHelper->method('getCurrentRequest')->willReturn(null); |
||
163 | |||
164 | $controller(); |
||
165 | } |
||
166 | |||
167 | } |
||
168 |