From 47eb487f23404347d080b1bb7307c75ddb58f8e7 Mon Sep 17 00:00:00 2001 From: romanetar Date: Fri, 2 Oct 2026 18:07:30 +0200 Subject: [PATCH 1/4] fix(audit): log many-to-many collection changes on presentation types allowed_ticket_types now reports added and removed ids through PresentationTypeAuditLogFormatter instead of being dropped (ADR-004). --- .../PresentationTypeAuditLogFormatter.php | 4 + ...ionTypeManyToManyAuditLogFormatterTest.php | 155 ++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 tests/OpenTelemetry/Formatters/PresentationTypeManyToManyAuditLogFormatterTest.php diff --git a/app/Audit/ConcreteFormatters/PresentationTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/PresentationTypeAuditLogFormatter.php index 9c5b92e8f..791f0285d 100644 --- a/app/Audit/ConcreteFormatters/PresentationTypeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/PresentationTypeAuditLogFormatter.php @@ -66,6 +66,10 @@ public function format($subject, array $change_set): ?string $summit_name, $this->getUserInfo() ); + + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE: + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE: + return $this->formatManyToManyCollectionChange($change_set, sprintf("Presentation Type '%s' (%s) for Summit '%s'", $type_name, $id, $summit_name)); } } catch (\Exception $ex) { Log::warning("PresentationTypeAuditLogFormatter error: " . $ex->getMessage()); diff --git a/tests/OpenTelemetry/Formatters/PresentationTypeManyToManyAuditLogFormatterTest.php b/tests/OpenTelemetry/Formatters/PresentationTypeManyToManyAuditLogFormatterTest.php new file mode 100644 index 000000000..9fa95be6b --- /dev/null +++ b/tests/OpenTelemetry/Formatters/PresentationTypeManyToManyAuditLogFormatterTest.php @@ -0,0 +1,155 @@ +makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [10, 11], [11, 12]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " allowed_ticket_types (SummitTicketType) updated: Added IDs: [12], Removed IDs: [10] by user ", + $result + ); + } + + public function testUpdateEventReportsAddedIds(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], [5, 6]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " allowed_ticket_types (SummitTicketType) updated: Added IDs: [5,6] by user ", + $result + ); + } + + public function testDeleteEventReportsRemovedIdsFromPayload(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], []), + 'deleted_ids' => [3, 4], + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " allowed_ticket_types (SummitTicketType) deleted: Removed IDs: [3,4] by user ", + $result + ); + } + + public function testUpdateEventWithoutDiffIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [3], [3]), + ]); + + $this->assertNull($result); + } + + public function testDeleteEventWithNothingToRemoveIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], []), + 'deleted_ids' => [], + ]); + + $this->assertNull($result); + } + + public function testManyToManyEventWithoutCollectionReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format($this->makeSubject(), [])); + } + + public function testManyToManyEventWithInvalidSubjectReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format(new \stdClass(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], [7]), + ])); + } + + private function makeFormatter(string $eventType): PresentationTypeAuditLogFormatter + { + $formatter = new PresentationTypeAuditLogFormatter($eventType); + $formatter->setContext(AuditContextBuilder::default()->build()); + return $formatter; + } + + private function makeCollection(string $field, string $targetEntity, array $snapshotIds, array $currentIds) + { + return PersistentCollectionTestHelper::buildManyToManyCollection( + PresentationType::class, + $field, + $targetEntity, + $snapshotIds, + $currentIds + ); + } + + private function makeSubject(): PresentationType + { + $summit = Mockery::mock(Summit::class); + $summit->shouldReceive('getName')->andReturn('Test Summit'); + + $type = Mockery::mock(PresentationType::class); + $type->shouldReceive('getId')->andReturn(8); + $type->shouldReceive('getType')->andReturn('Talk'); + $type->shouldReceive('getMaxSpeakers')->andReturn(3); + $type->shouldReceive('isUseSpeakers')->andReturn(true); + $type->shouldReceive('getSummit')->andReturn($summit); + + return $type; + } +} From cf6fc4e6af44bd89803ef601cb15f8d32783dc88 Mon Sep 17 00:00:00 2001 From: romanetar Date: Fri, 2 Oct 2026 18:07:30 +0200 Subject: [PATCH 2/4] fix(audit): log many-to-many collection changes on event types allowed_ticket_types now reports added and removed ids through SummitEventTypeAuditLogFormatter instead of being dropped (ADR-004). --- .../SummitEventTypeAuditLogFormatter.php | 4 + ...entTypeManyToManyAuditLogFormatterTest.php | 156 ++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 tests/OpenTelemetry/Formatters/SummitEventTypeManyToManyAuditLogFormatterTest.php diff --git a/app/Audit/ConcreteFormatters/SummitEventTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/SummitEventTypeAuditLogFormatter.php index 13b387716..9cef6c1a6 100644 --- a/app/Audit/ConcreteFormatters/SummitEventTypeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/SummitEventTypeAuditLogFormatter.php @@ -70,6 +70,10 @@ public function format($subject, array $change_set): ?string $color, $this->getUserInfo() ); + + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE: + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE: + return $this->formatManyToManyCollectionChange($change_set, sprintf("Event Type '%s' (%s) for Summit '%s'", $type, $id, $summit_name)); } } catch (\Exception $ex) { Log::warning("SummitEventTypeAuditLogFormatter error: " . $ex->getMessage()); diff --git a/tests/OpenTelemetry/Formatters/SummitEventTypeManyToManyAuditLogFormatterTest.php b/tests/OpenTelemetry/Formatters/SummitEventTypeManyToManyAuditLogFormatterTest.php new file mode 100644 index 000000000..1da877858 --- /dev/null +++ b/tests/OpenTelemetry/Formatters/SummitEventTypeManyToManyAuditLogFormatterTest.php @@ -0,0 +1,156 @@ +makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [10, 11], [11, 12]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " allowed_ticket_types (SummitTicketType) updated: Added IDs: [12], Removed IDs: [10] by user ", + $result + ); + } + + public function testUpdateEventReportsAddedIds(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], [5, 6]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " allowed_ticket_types (SummitTicketType) updated: Added IDs: [5,6] by user ", + $result + ); + } + + public function testDeleteEventReportsRemovedIdsFromPayload(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], []), + 'deleted_ids' => [3, 4], + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " allowed_ticket_types (SummitTicketType) deleted: Removed IDs: [3,4] by user ", + $result + ); + } + + public function testUpdateEventWithoutDiffIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [3], [3]), + ]); + + $this->assertNull($result); + } + + public function testDeleteEventWithNothingToRemoveIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], []), + 'deleted_ids' => [], + ]); + + $this->assertNull($result); + } + + public function testManyToManyEventWithoutCollectionReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format($this->makeSubject(), [])); + } + + public function testManyToManyEventWithInvalidSubjectReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format(new \stdClass(), [ + 'collection' => $this->makeCollection('allowed_ticket_types', SummitTicketType::class, [], [7]), + ])); + } + + private function makeFormatter(string $eventType): SummitEventTypeAuditLogFormatter + { + $formatter = new SummitEventTypeAuditLogFormatter($eventType); + $formatter->setContext(AuditContextBuilder::default()->build()); + return $formatter; + } + + private function makeCollection(string $field, string $targetEntity, array $snapshotIds, array $currentIds) + { + return PersistentCollectionTestHelper::buildManyToManyCollection( + SummitEventType::class, + $field, + $targetEntity, + $snapshotIds, + $currentIds + ); + } + + private function makeSubject(): SummitEventType + { + $summit = Mockery::mock(Summit::class); + $summit->shouldReceive('getName')->andReturn('Test Summit'); + + $type = Mockery::mock(SummitEventType::class); + $type->shouldReceive('getId')->andReturn(4); + $type->shouldReceive('getType')->andReturn('Break'); + $type->shouldReceive('getColor')->andReturn('#fff'); + $type->shouldReceive('isDefault')->andReturn(false); + $type->shouldReceive('isPrivate')->andReturn(false); + $type->shouldReceive('getSummit')->andReturn($summit); + + return $type; + } +} From 0e91cf246b41a41d3321a9819ade0578be9cc1a7 Mon Sep 17 00:00:00 2001 From: romanetar Date: Fri, 2 Oct 2026 18:07:31 +0200 Subject: [PATCH 3/4] fix(audit): log many-to-many collection changes on media upload types presentation_types now reports added and removed ids through SummitMediaUploadTypeAuditLogFormatter instead of being dropped (ADR-004). --- ...SummitMediaUploadTypeAuditLogFormatter.php | 4 + ...oadTypeManyToManyAuditLogFormatterTest.php | 153 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 tests/OpenTelemetry/Formatters/SummitMediaUploadTypeManyToManyAuditLogFormatterTest.php diff --git a/app/Audit/ConcreteFormatters/SummitMediaUploadTypeAuditLogFormatter.php b/app/Audit/ConcreteFormatters/SummitMediaUploadTypeAuditLogFormatter.php index 5557f4f7d..d9cdfc61b 100644 --- a/app/Audit/ConcreteFormatters/SummitMediaUploadTypeAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/SummitMediaUploadTypeAuditLogFormatter.php @@ -62,6 +62,10 @@ public function format($subject, array $change_set): ?string $summit_name, $this->getUserInfo() ); + + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE: + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE: + return $this->formatManyToManyCollectionChange($change_set, sprintf("Media Upload Type '%s' (%s) for Summit '%s'", $name, $id, $summit_name)); } } catch (\Exception $ex) { Log::warning("SummitMediaUploadTypeAuditLogFormatter error: " . $ex->getMessage()); diff --git a/tests/OpenTelemetry/Formatters/SummitMediaUploadTypeManyToManyAuditLogFormatterTest.php b/tests/OpenTelemetry/Formatters/SummitMediaUploadTypeManyToManyAuditLogFormatterTest.php new file mode 100644 index 000000000..3b852537d --- /dev/null +++ b/tests/OpenTelemetry/Formatters/SummitMediaUploadTypeManyToManyAuditLogFormatterTest.php @@ -0,0 +1,153 @@ +makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('presentation_types', PresentationType::class, [10, 11], [11, 12]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " presentation_types (PresentationType) updated: Added IDs: [12], Removed IDs: [10] by user ", + $result + ); + } + + public function testUpdateEventReportsAddedIds(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('presentation_types', PresentationType::class, [], [5, 6]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " presentation_types (PresentationType) updated: Added IDs: [5,6] by user ", + $result + ); + } + + public function testDeleteEventReportsRemovedIdsFromPayload(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('presentation_types', PresentationType::class, [], []), + 'deleted_ids' => [3, 4], + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " presentation_types (PresentationType) deleted: Removed IDs: [3,4] by user ", + $result + ); + } + + public function testUpdateEventWithoutDiffIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('presentation_types', PresentationType::class, [3], [3]), + ]); + + $this->assertNull($result); + } + + public function testDeleteEventWithNothingToRemoveIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('presentation_types', PresentationType::class, [], []), + 'deleted_ids' => [], + ]); + + $this->assertNull($result); + } + + public function testManyToManyEventWithoutCollectionReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format($this->makeSubject(), [])); + } + + public function testManyToManyEventWithInvalidSubjectReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format(new \stdClass(), [ + 'collection' => $this->makeCollection('presentation_types', PresentationType::class, [], [7]), + ])); + } + + private function makeFormatter(string $eventType): SummitMediaUploadTypeAuditLogFormatter + { + $formatter = new SummitMediaUploadTypeAuditLogFormatter($eventType); + $formatter->setContext(AuditContextBuilder::default()->build()); + return $formatter; + } + + private function makeCollection(string $field, string $targetEntity, array $snapshotIds, array $currentIds) + { + return PersistentCollectionTestHelper::buildManyToManyCollection( + SummitMediaUploadType::class, + $field, + $targetEntity, + $snapshotIds, + $currentIds + ); + } + + private function makeSubject(): SummitMediaUploadType + { + $summit = Mockery::mock(Summit::class); + $summit->shouldReceive('getName')->andReturn('Test Summit'); + + $type = Mockery::mock(SummitMediaUploadType::class); + $type->shouldReceive('getId')->andReturn(15); + $type->shouldReceive('getName')->andReturn('Slides'); + $type->shouldReceive('getSummit')->andReturn($summit); + + return $type; + } +} From 2e63ca95f082975c3ecf9146ca8d6ed53942162f Mon Sep 17 00:00:00 2001 From: romanetar Date: Fri, 2 Oct 2026 18:07:31 +0200 Subject: [PATCH 4/4] fix(audit): log many-to-many collection changes on summit documents event_types now reports added and removed ids through SummitDocumentAuditLogFormatter instead of being dropped (ADR-004). --- .../SummitDocumentAuditLogFormatter.php | 4 + ...ocumentManyToManyAuditLogFormatterTest.php | 154 ++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 tests/OpenTelemetry/Formatters/SummitDocumentManyToManyAuditLogFormatterTest.php diff --git a/app/Audit/ConcreteFormatters/SummitDocumentAuditLogFormatter.php b/app/Audit/ConcreteFormatters/SummitDocumentAuditLogFormatter.php index f958074d2..a819698bd 100644 --- a/app/Audit/ConcreteFormatters/SummitDocumentAuditLogFormatter.php +++ b/app/Audit/ConcreteFormatters/SummitDocumentAuditLogFormatter.php @@ -64,6 +64,10 @@ public function format($subject, array $change_set): ?string $summit_name, $this->getUserInfo() ); + + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE: + case IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE: + return $this->formatManyToManyCollectionChange($change_set, sprintf("Summit Document '%s' (%s) for Summit '%s'", $name, $id, $summit_name)); } } catch (\Exception $ex) { Log::warning("SummitDocumentAuditLogFormatter error: " . $ex->getMessage()); diff --git a/tests/OpenTelemetry/Formatters/SummitDocumentManyToManyAuditLogFormatterTest.php b/tests/OpenTelemetry/Formatters/SummitDocumentManyToManyAuditLogFormatterTest.php new file mode 100644 index 000000000..ea414f593 --- /dev/null +++ b/tests/OpenTelemetry/Formatters/SummitDocumentManyToManyAuditLogFormatterTest.php @@ -0,0 +1,154 @@ +makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('event_types', SummitEventType::class, [10, 11], [11, 12]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " event_types (SummitEventType) updated: Added IDs: [12], Removed IDs: [10] by user ", + $result + ); + } + + public function testUpdateEventReportsAddedIds(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('event_types', SummitEventType::class, [], [5, 6]), + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " event_types (SummitEventType) updated: Added IDs: [5,6] by user ", + $result + ); + } + + public function testDeleteEventReportsRemovedIdsFromPayload(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('event_types', SummitEventType::class, [], []), + 'deleted_ids' => [3, 4], + ]); + + $this->assertStringStartsWith( + self::MESSAGE_PREFIX . " event_types (SummitEventType) deleted: Removed IDs: [3,4] by user ", + $result + ); + } + + public function testUpdateEventWithoutDiffIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('event_types', SummitEventType::class, [3], [3]), + ]); + + $this->assertNull($result); + } + + public function testDeleteEventWithNothingToRemoveIsSuppressed(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_DELETE); + + $result = $formatter->format($this->makeSubject(), [ + 'collection' => $this->makeCollection('event_types', SummitEventType::class, [], []), + 'deleted_ids' => [], + ]); + + $this->assertNull($result); + } + + public function testManyToManyEventWithoutCollectionReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format($this->makeSubject(), [])); + } + + public function testManyToManyEventWithInvalidSubjectReturnsNull(): void + { + $formatter = $this->makeFormatter(IAuditStrategy::EVENT_COLLECTION_MANYTOMANY_UPDATE); + + $this->assertNull($formatter->format(new \stdClass(), [ + 'collection' => $this->makeCollection('event_types', SummitEventType::class, [], [7]), + ])); + } + + private function makeFormatter(string $eventType): SummitDocumentAuditLogFormatter + { + $formatter = new SummitDocumentAuditLogFormatter($eventType); + $formatter->setContext(AuditContextBuilder::default()->build()); + return $formatter; + } + + private function makeCollection(string $field, string $targetEntity, array $snapshotIds, array $currentIds) + { + return PersistentCollectionTestHelper::buildManyToManyCollection( + SummitDocument::class, + $field, + $targetEntity, + $snapshotIds, + $currentIds + ); + } + + private function makeSubject(): SummitDocument + { + $summit = Mockery::mock(Summit::class); + $summit->shouldReceive('getName')->andReturn('Test Summit'); + + $doc = Mockery::mock(SummitDocument::class); + $doc->shouldReceive('getId')->andReturn(21); + $doc->shouldReceive('getName')->andReturn('Code of Conduct'); + $doc->shouldReceive('getLabel')->andReturn('CoC'); + $doc->shouldReceive('getSummit')->andReturn($summit); + + return $doc; + } +}