jenkins-bot has submitted this change and it was merged. Change subject: \SMW\ObservableDispatcher dispatches state changes from a source to an Observer ......................................................................
\SMW\ObservableDispatcher dispatches state changes from a source to an Observer Code coverage: 100% CRAP: 2 Instead of using the inheritance model or implementing an Observable interface to communicate with attached Observers, the ObservableDispatcher can be used as intermediary transmitter to notify Observers. The dispatcher inherits all methods necessary (ObservableSubject) to communicate with an Observer, and freeing the emitter of the state change from being an ObservableSubject itself. This also allows an Observer to become a DispatchableSource which can inform other Observers independently from its own status. ## Example Previous to this change PropertyChangeNotifier was a ObservableSubject which would communicate/initiate direct communiction with Observers, now that PropertyChangeNotifier is injected with an ObservableDispatcher it does no longer need to establish any link rather expects state changes to be dispatchd through ObservableSubjectDispatcher to those Observers that are registered with it (in this case with ChangeObserver()). - Before $changeNotifier = new PropertyChangeNotifier( ... ); $changeNotifier->attach( new ChangeObserver() ); - After $changeNotifier = new PropertyChangeNotifier( ... ); $changeNotifier->setDispatcher( new ObservableSubjectDispatcher( new ChangeObserver() ) ); Doing so avoids PropertyChangeNotifier being directly linked to the Observer/Subject pattern and instead using a setter injection to establish a connection such as: SMW\ParserData->updateStore( ) SMW\PropertyChangeNotifier->detectChanges( ) SMW\PropertyChangeNotifier->compareConversionFactors( ) SMW\PropertyChangeNotifier->addDispatchJob( ) SMW\ObservableSubject->setState( ) SMW\ObservableSubject->notify( ) SMW\Observer->update( ) SMW\ChangeObserver->runUpdateDispatcher( ) Change-Id: I64c156006e9340aba57aba6b86d3b3c93a4b5c82 --- M docs/doxygen.group.definitions.php M includes/BasePropertyAnnotator.php A includes/ObservableSubject.php A includes/ObservableSubjectDispatcher.php M includes/Observer.php M includes/ParserData.php M includes/PropertyChangeNotifier.php D includes/Publisher.php M includes/Setup.php D includes/Subject.php D includes/Subscriber.php A tests/phpunit/includes/ObservableSubjectDispatcherTest.php M tests/phpunit/includes/ObserverTest.php M tests/phpunit/includes/PropertyChangeNotifierTest.php 14 files changed, 693 insertions(+), 337 deletions(-) Approvals: Mwjames: Looks good to me, approved jenkins-bot: Verified diff --git a/docs/doxygen.group.definitions.php b/docs/doxygen.group.definitions.php index 0aa00f4..16b1dfb 100644 --- a/docs/doxygen.group.definitions.php +++ b/docs/doxygen.group.definitions.php @@ -10,102 +10,9 @@ */ /** - * This group contains members that are related to message, error, and parameter - * formatting - * - * @defgroup Formatter Formatter - * @ingroup SMW - */ - -/** - * This group contains members that are related to jobs - * - * @defgroup Job Job - * @ingroup SMW - */ - -/** - * This group contains members that are related to special pages - * - * @see https://www.mediawiki.org/wiki/Manual:Special_pages - * - * @defgroup SpecialPage SpecialPage - * @ingroup SMW - */ - -/** - * This group contains members that are related to hooks, hook events, and - * hook registrations - * - * @see https://www.mediawiki.org/wiki/Manual:Hooks - * @see https://semantic-mediawiki.org/wiki/Hooks - * - * @defgroup Hook Hook - * @ingroup SMW - */ - -/** - * This group contains members that are related to accessors - * - * @defgroup Accessor Accessor - * @ingroup SMW - */ - -/** - * This group contains members that are related to parser hooks and functions - * - * @defgroup ParserFunction ParserFunction - * @ingroup SMW - */ - -/** - * This group contains members that are related to unit tests - * - * @defgroup Test Test - * @ingroup SMW - */ - -/** - * This group contains members that are related to the QueryPrinter unit tests - * - * @defgroup QueryPrinterTest QueryPrinterTest - * @ingroup Test - */ - -/** - * This group contains members that are related to the Store unit tests - * - * @defgroup StoreTest StoreTest - * @ingroup Test - */ - -/** - * This group contains members that are related to the SQLStore unit tests - * - * @defgroup SQLStoreTest SQLStoreTest - * @ingroup StoreTest - */ - -/** * This group contains members that are related to the Semantic MediaWiki Api * * @defgroup Api Api - * @ingroup SMW - */ - -/** - * This group contains members that are related to handler classes (including - * object handler, hooks handler, instance handler etc.) - * - * @defgroup Handler Handler - * @ingroup SMW - */ - -/** - * This group contains members that are related to utility classes and support - * functions - * - * @defgroup Utility Utility * @ingroup SMW */ @@ -128,4 +35,120 @@ * * @defgroup Collector Collector * @ingroup Store - */ \ No newline at end of file + */ + +/** + * This group contains members that are related to message, error, and parameter + * formatting + * + * @defgroup Formatter Formatter + * @ingroup SMW + */ + +/** + * This group contains members that are related to hooks, hook events, and + * hook registrations + * + * @see https://www.mediawiki.org/wiki/Manual:Hooks + * @see https://semantic-mediawiki.org/wiki/Hooks + * + * @defgroup Hook Hook + * @ingroup SMW + */ + +/** + * This group contains members that are related to parser hooks and functions + * + * @defgroup ParserFunction ParserFunction + * @ingroup SMW + */ + +/** + * This group contains members that are related to special pages + * + * @see https://www.mediawiki.org/wiki/Manual:Special_pages + * + * @defgroup SpecialPage SpecialPage + * @ingroup SMW + */ + +/** + * This group contains members that are related to jobs + * + * @defgroup Job Job + * @ingroup SMW + */ + +/** + * This group contains members that are related to maintenance scripts + * + * @defgroup Maintenance Maintenance + * @ingroup SMW + */ + +/** + * This group contains members that are related to utility classes and support + * functions + * + * @defgroup Utility Utility + * @ingroup SMW + */ + +/** + * This group contains members that are related to supporting the Observer + * + * @defgroup Observer Observer + * @ingroup Utility + */ + +/** + * This group contains members that are related to handler classes (including + * object handler, hooks handler, instance handler etc.) + * + * @defgroup Handler Handler + * @ingroup Utility + */ + +/** + * This group contains members that are related to accessors + * + * @defgroup Accessor Accessor + * @ingroup Utility + */ + + +/** + * This group contains members that are related to unit tests + * + * @defgroup Test Test + * @ingroup SMW + */ + +/** + * This group contains members that are related to the QueryPrinter unit tests + * + * @defgroup QueryPrinterTest QueryPrinterTest + * @ingroup Test + */ + +/** + * This group contains members that are related to the maintenance script unit + * tests + * + * @defgroup MaintenanceTest MaintenanceTest + * @ingroup Test + */ + +/** + * This group contains members that are related to the Store unit tests + * + * @defgroup StoreTest StoreTest + * @ingroup Test + */ + +/** + * This group contains members that are related to the SQLStore unit tests + * + * @defgroup SQLStoreTest SQLStoreTest + * @ingroup StoreTest + */ diff --git a/includes/BasePropertyAnnotator.php b/includes/BasePropertyAnnotator.php index 9c12be4..fc0d5de 100644 --- a/includes/BasePropertyAnnotator.php +++ b/includes/BasePropertyAnnotator.php @@ -28,7 +28,7 @@ * * @ingroup Annotator */ -class BasePropertyAnnotator extends Subject { +class BasePropertyAnnotator extends ObservableSubject { /** @var SemanticData */ protected $semanticData; diff --git a/includes/ObservableSubject.php b/includes/ObservableSubject.php new file mode 100644 index 0000000..1ef9e4c --- /dev/null +++ b/includes/ObservableSubject.php @@ -0,0 +1,222 @@ +<?php + +namespace SMW; + +/** + * Interface and abstract class defining the operations for + * attaching and de-attaching observers + * + * @file + * + * @license GNU GPL v2+ + * @since 1.9 + * + * @author mwjames + */ + +/** + * Base Publisher interface + * + * @ingroup Observer + */ +interface Publisher { + + /** + * Attaches a Subscriber + * + * @since 1.9 + * + * @param Subscriber $subscriber + */ + public function attach( Subscriber $subscriber ); + + /** + * Detaches a Subscriber + * + * @since 1.9 + * + * @param Subscriber $subscriber + */ + public function detach( Subscriber $subscriber ); + + /** + * Notifies attached Subscribers + * + * @since 1.9 + */ + public function notify(); + +} + +/** + * Extended Publisher interface specifying access to + * source and state changes + * + * @ingroup Observer + */ +interface Observable extends Publisher { + + /** + * Returns the invoked state change + * + * @since 1.9 + */ + public function getState(); + + /** + * Registers a state change + * + * @since 1.9 + */ + public function setState( $state ); + + /** + * Returns the emitter of the state change + * + * @since 1.9 + */ + public function getSource(); + +} + +/** + * Implements the Pubisher/Observable interface as base class + * + * @note In the GOF book this class/interface is known as Subject + * + * @note We will avoid referring to it as Subject otherwise it could be + * mistaken with Semantic MediaWiki's own "Subject" (DIWikiPage) object + * + * @ingroup Observer + */ +abstract class ObservableSubject implements Observable { + + /** @var Subscriber[] */ + protected $observers = array(); + + /** string */ + protected $state = null; + + /** + * @since 1.9 + * + * @param Subscriber|null $subject + */ + public function __construct( Subscriber $observer = null ) { + if ( $observer instanceof Subscriber ) { + $this->attach( $observer ); + } + } + + /** + * @see Observable::attach + * + * @since 1.9 + * + * @param Subscriber $observer + */ + public function attach( Subscriber $observer ) { + + if ( $this->contains( $observer ) === null ) { + $this->observers[] = $observer; + } + + return $this; + } + + /** + * @see Observable::attach + * + * @since 1.9 + * + * @param Subscriber $observer + */ + public function detach( Subscriber $observer ) { + + $index = $this->contains( $observer ); + + if ( $index !== null ) { + unset( $this->observers[$index] ); + } + + return $this; + } + + /** + * @see Observable::getState + * + * @since 1.9 + * + * @return string + */ + public function getState() { + return $this->state; + } + + /** + * Set a state variable state and initiates to notify + * the attached Subscribers (Observers) + * + * @since 1.9 + * + * @param string $state + */ + public function setState( $state ) { + $this->state = $state; + $this->notify(); + } + + /** + * @see Observable::getSource + * + * @since 1.9 + * + * @return Observable + */ + public function getSource() { + return $this; + } + + /** + * Notifies the updater of all invoked Subscribers + * + * @since 1.9 + */ + public function notify() { + foreach ( $this->observers as $observer ) { + $observer->update( $this ); + } + } + + /** + * Returns registered Observers + * + * @since 1.9 + * + * @return array + */ + public function getObservers() { + return $this->observers; + } + + /** + * Returns an index (or null) of a registered Observer + * + * @since 1.9 + * + * @param Subscriber $observer + * + * @return integer|null + */ + private function contains( Subscriber $observer ) { + + foreach ( $this->observers as $key => $obs ) { + if ( $obs === $observer ) { + return $key; + } + } + + return null; + } + +} diff --git a/includes/ObservableSubjectDispatcher.php b/includes/ObservableSubjectDispatcher.php new file mode 100644 index 0000000..f8e5d29 --- /dev/null +++ b/includes/ObservableSubjectDispatcher.php @@ -0,0 +1,104 @@ +<?php + +namespace SMW; + +/** + * Dispatches notifification (state changes) from a client to registered + * Observers + * + * @file + * + * @license GNU GPL v2+ + * @since 1.9 + * + * @author mwjames + */ + +/** + * Interface describing a source that is dispatchable + * + * @ingroup Observer + */ +interface DispatchableSource { + + /** + * Frowards requests fo + * + * @since 1.9 + * + * @param Dispatchable $dispatcher + */ + public function setDispatcher( ObservableDispatcher $dispatcher ); + +} + +/** + * Extends the Observable interface to forward the source + * + * This ObservableDispatcher enables the emitter (client) of an event not being + * directly linked to an Observer, freeing it from implementing methods to + * communicate with it while maintaining capabability to transmitt state changes + * to Observers that are registered with this dispatcher. + * + * @ingroup Observer + */ +interface ObservableDispatcher extends Observable { + + /** + * Specifies the source from which events are transmitted + * + * @since 1.9 + * + * @param mixed $source + */ + public function setSource( $source ); + +} + +/** + * Implementation of the ObservableDispatcher + * + * ObservableDispatcher inherits all methods from ObservableSubject in order to + * communicate with its Observers. + * + * @par Example: + * @code + * $changeNotifier = new PropertyChangeNotifier( ... ); + * $changeNotifier->setDispatcher( new ObservableSubjectDispatcher( new ChangeObserver() ) ); + * @endcode + * + * @ingroup Observer + */ +class ObservableSubjectDispatcher extends ObservableSubject implements ObservableDispatcher { + + /** @var mixed */ + protected $source = null; + + /** + * Registeres the DispatchableSource + * + * @since 1.9 + * + * @param $source + * + * @return ObservableSubjectDispatcher + */ + public function setSource( $source ) { + $this->source = $source; + return $this; + } + + /** + * Overrides ObservableSubject::getSource to ensure that the emitting client + * is identified as source and not the ObservableDispatcher, in order for + * the Observer to act on the clients behalf + * + * @since 1.9 + * + * @return mixed + */ + public function getSource() { + return $this->source; + } + +} diff --git a/includes/Observer.php b/includes/Observer.php index 9f0d0ac..90b3617 100644 --- a/includes/Observer.php +++ b/includes/Observer.php @@ -3,10 +3,8 @@ namespace SMW; /** - * Contains interfaces and implementation classes to - * enable a Observer-Subject (or Publisher-Subcriber) pattern where - * objects can indepentanly be notfied about a state change and initiate - * an update of its registered Publisher + * Specifies interface and abstract class for operations that are used to execute + * registered operations * * @file * @@ -17,8 +15,26 @@ */ /** - * Implement the Subsriber interface resutling in an Observer base class - * that accomodates necessary methods to update an invoked publisher + * Interface describing a Subsriber + * + * @ingroup Observer + */ +interface Subscriber { + + /** + * Receive update from a publishable source + * + * @since 1.9 + * + * @param Observable $source + */ + public function update( Observable $source ); + +} + +/** + * Implements the Subsriber interface resutling in an Observer base class + * that accomodates necessary methods to operate according the invoked state * * @ingroup Observer */ @@ -27,26 +43,31 @@ /** * @since 1.9 * - * @param Publisher|null $subject + * @param Observable|null $subject */ - public function __construct( Publisher $subject = null ) { - if ( $subject instanceof Publisher ) { + public function __construct( Observable $subject = null ) { + + if ( $subject instanceof Observable ) { $subject->attach( $this ); } + } /** - * Update handling of an invoked publisher by relying - * on the state object to carry out the task + * Operates according the invoked state and source * * @since 1.9 * - * @param Publisher|null $subject + * @param Observable|null $subject */ - public function update( Publisher $subject ) { + public function update( Observable $subject ) { if ( method_exists( $this, $subject->getState() ) ) { - call_user_func_array( array( $this, $subject->getState() ), array( $subject ) ); + call_user_func_array( + array( $this, $subject->getState() ), + array( $subject->getSource() ) + ); } } + } diff --git a/includes/ParserData.php b/includes/ParserData.php index 19c5937..9b7b401 100644 --- a/includes/ParserData.php +++ b/includes/ParserData.php @@ -405,8 +405,7 @@ // even finding uses of a property fails after its type was changed. if ( $this->updateJobs ) { $changeNotifier = new PropertyChangeNotifier( $store, $this->semanticData, Settings::newFromGlobals() ); - $changeNotifier->attach( new ChangeObserver() ); - $changeNotifier->detectChanges(); + $changeNotifier->setDispatcher( new ObservableSubjectDispatcher( new ChangeObserver() ) )->detectChanges(); } // Actually store semantic data, or at least clear it if needed diff --git a/includes/PropertyChangeNotifier.php b/includes/PropertyChangeNotifier.php index 22b7ab9..072e0b4 100644 --- a/includes/PropertyChangeNotifier.php +++ b/includes/PropertyChangeNotifier.php @@ -19,7 +19,7 @@ * * @ingroup SMW */ -class PropertyChangeNotifier extends Subject implements TitleAccess { +class PropertyChangeNotifier implements TitleAccess, DispatchableSource { /** @var Store */ protected $store; @@ -29,6 +29,9 @@ /** @var Settings */ protected $settings; + + /** @var ObservableDispatcher */ + protected $dispatcher; /** @var boolean */ protected $hasDisparity = false; @@ -55,6 +58,18 @@ */ public function getTitle() { return $this->semanticData->getSubject()->getTitle(); + } + + /** + * Invokes an ObservableDispatcher object to deploy state changes to an Observer + * + * @since 1.9 + * + * @param ObservableDispatcher $dispatcher + */ + public function setDispatcher( ObservableDispatcher $dispatcher ) { + $this->dispatcher = $dispatcher->setSource( $this ); + return $this; } /** @@ -89,7 +104,7 @@ } /** - * Compare and find change related to the property type + * Compare and find changes related to the property type * * @since 1.9 */ @@ -133,7 +148,7 @@ } /** - * Compare and find change related to conversion factor + * Compare and find changes related to conversion factor * * @since 1.9 */ @@ -142,11 +157,11 @@ $pconversion = new DIProperty( DIProperty::TYPE_CONVERSION ); + $newfactors = $this->semanticData->getPropertyValues( $pconversion ); $oldfactors = $this->store->getPropertyValues( $this->semanticData->getSubject(), $pconversion ); - $newfactors = $this->semanticData->getPropertyValues( $pconversion ); $this->addDispatchJob( !$this->isEqual( $oldfactors, $newfactors ) ); @@ -162,7 +177,7 @@ */ protected function addDispatchJob( $addJob = true ) { if ( $addJob && !$this->hasDisparity ) { - $this->setState( 'runUpdateDispatcher' ); + $this->dispatcher->setState( 'runUpdateDispatcher' ); $this->hasDisparity = true; } } @@ -200,4 +215,5 @@ return ( $oldDataValueHash == $newDataValueHash ); } + } diff --git a/includes/Publisher.php b/includes/Publisher.php deleted file mode 100644 index 234db51..0000000 --- a/includes/Publisher.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php - -namespace SMW; - -/** - * Contains interfaces and implementation classes to - * enable a Observer-Subject (or Publisher-Subcriber) pattern where - * objects can indepentanly be notfied about a state change and initiate - * an update of its registered Publisher - * - * @file - * - * @license GNU GPL v2+ - * @since 1.9 - * - * @author mwjames - */ - -/** - * Interface describing a Publisher - * - * @ingroup Observer - */ -interface Publisher { - - /** - * Attach an Subscriber - * - * @since 1.9 - * - * @param Subscriber $subscriber - */ - public function attach( Subscriber $subscriber ); - - /** - * Detach an Subscriber - * - * @since 1.9 - * - * @param Subscriber $subscriber - */ - public function detach( Subscriber $subscriber ); - - /** - * Notify an Subscriber - * - * @since 1.9 - */ - public function notify(); - -} diff --git a/includes/Setup.php b/includes/Setup.php index dac5534..eb6f5cb 100644 --- a/includes/Setup.php +++ b/includes/Setup.php @@ -161,10 +161,16 @@ $wgAutoloadClasses['SMW\ChangeObserver'] = $incDir . 'ChangeObserver.php'; $wgAutoloadClasses['SMW\TitleAccess'] = $incDir . 'TitleAccess.php'; - $wgAutoloadClasses['SMW\Publisher'] = $incDir . 'Publisher.php'; - $wgAutoloadClasses['SMW\Subject'] = $incDir . 'Subject.php'; + $wgAutoloadClasses['SMW\Observable'] = $incDir . 'ObservableSubject.php'; + $wgAutoloadClasses['SMW\Publisher'] = $incDir . 'ObservableSubject.php'; + $wgAutoloadClasses['SMW\ObservableSubject'] = $incDir . 'ObservableSubject.php'; + $wgAutoloadClasses['SMW\Observer'] = $incDir . 'Observer.php'; - $wgAutoloadClasses['SMW\Subscriber'] = $incDir . 'Subscriber.php'; + $wgAutoloadClasses['SMW\Subscriber'] = $incDir . 'Observer.php'; + + $wgAutoloadClasses['SMW\ObservableDispatcher'] = $incDir . 'ObservableSubjectDispatcher.php'; + $wgAutoloadClasses['SMW\DispatchableSource'] = $incDir . 'ObservableSubjectDispatcher.php'; + $wgAutoloadClasses['SMW\ObservableSubjectDispatcher'] = $incDir . 'ObservableSubjectDispatcher.php'; $wgAutoloadClasses['SMW\Cacheable'] = $incDir . 'Cacheable.php'; $wgAutoloadClasses['SMW\Configurable'] = $incDir . 'Configurable.php'; diff --git a/includes/Subject.php b/includes/Subject.php deleted file mode 100644 index 5b70349..0000000 --- a/includes/Subject.php +++ /dev/null @@ -1,122 +0,0 @@ -<?php - -namespace SMW; - -/** - * Contains interfaces and implementation classes to - * enable a Observer-Subject (or Publisher-Subcriber) pattern where - * objects can indepentanly be notfied about a state change and initiate - * an update of its registered Publisher - * - * @file - * - * @license GNU GPL v2+ - * @since 1.9 - * - * @author mwjames - */ - -/** - * Implement the Publisher interface resulting in an Subject base class - * - * @ingroup Observer - */ -abstract class Subject implements Publisher { - - /** @var Subscriber[] */ - protected $observers = array(); - - /** string */ - protected $state = null; - - /** - * @see Publisher::attach - * - * @since 1.9 - * - * @param Subscriber $observer - */ - public function attach( Subscriber $observer ) { - if ( $this->contains( $observer ) === null ) { - $this->observers[] = $observer; - } - } - - /** - * @since 1.9 - * - * @param Subscriber $observer - */ - public function detach( Subscriber $observer ) { - $index = $this->contains( $observer ); - if ( $index !== null ) { - unset( $this->observers[$index] ); - } - } - - /** - * Returns a string which represents an updateable - * Publisher object method - * - * @since 1.9 - * - * @return string - */ - public function getState() { - return $this->state; - } - - /** - * Set a state variable state and initiates to notify - * the attached Subscribers - * - * @since 1.9 - * - * @param string $state - */ - public function setState( $state ) { - $this->state = $state; - $this->notify(); - } - - /** - * Notifies the updater of all invoked Subscribers - * - * @since 1.9 - */ - public function notify() { - foreach ( $this->observers as $observer ) { - $observer->update( $this ); - } - } - - /** - * Returns registered Observers - * - * @since 1.9 - * - * @return array - */ - public function getObservers() { - return $this->observers; - } - - /** - * Returns an index (or null) of a registered Observer - * - * @since 1.9 - * - * @param Subscriber $observer - * - * @return integer|null - */ - protected function contains( Subscriber $observer ) { - foreach ( $this->observers as $key => $obs ) { - if ( $obs === $observer ) { - return $key; - } - } - return null; - } - -} diff --git a/includes/Subscriber.php b/includes/Subscriber.php deleted file mode 100644 index 1f6476f..0000000 --- a/includes/Subscriber.php +++ /dev/null @@ -1,35 +0,0 @@ -<?php - -namespace SMW; - -/** - * Contains interfaces and implementation classes to - * enable a Observer-Subject (or Publisher-Subcriber) pattern where - * objects can indepentanly be notfied about a state change and initiate - * an update of its registered Publisher - * - * @file - * - * @license GNU GPL v2+ - * @since 1.9 - * - * @author mwjames - */ - -/** - * Interface describing a Subsriber - * - * @ingroup Observer - */ -interface Subscriber { - - /** - * Receive update from a Publisher - * - * @since 1.9 - * - * @param Publisher $publisher - */ - public function update( Publisher $publisher ); - -} diff --git a/tests/phpunit/includes/ObservableSubjectDispatcherTest.php b/tests/phpunit/includes/ObservableSubjectDispatcherTest.php new file mode 100644 index 0000000..575a66f --- /dev/null +++ b/tests/phpunit/includes/ObservableSubjectDispatcherTest.php @@ -0,0 +1,170 @@ +<?php + +namespace SMW\Test; + +use SMW\ObservableSubjectDispatcher; +use SMW\ObservableDispatcher; + +/** + * Tests for the Observer/Subject pattern + * + * @file + * + * @license GNU GPL v2+ + * @since 1.9 + * + * @author mwjames + */ + +/** + * @covers \SMW\Observer + * @covers \SMW\ObservableSubject + * @covers \SMW\ObservableSubjectDispatcher + * + * @ingroup Test + * + * @group SMW + * @group SMWExtension + */ +class ObservableSubjectDispatcherTest extends SemanticMediaWikiTestCase { + + /** + * Returns the name of the class to be tested + * + * @return string|false + */ + public function getClass() { + return '\SMW\ObservableSubjectDispatcher'; + } + + /** + * Helper method that returns a DispatchableSource object + * + * @since 1.9 + * + * @param $data + * + * @return DispatchableSource + */ + private function newDispatchableSource() { + + $source = $this->getMockBuilder( '\SMW\DispatchableSource' ) + ->setMethods( array( 'setDispatcher' ) ) + ->getMock(); + + $source->expects( $this->any() ) + ->method( 'setDispatcher' ) + ->will( $this->returnCallback( array( $this, 'setDispatcherCallback' ) ) ); + + return $source; + + } + + /** + * Helper method that returns a Observer object + * + * @since 1.9 + * + * @param $data + * + * @return Observer + */ + private function newObserver() { + + $observer = $this->getMockBuilder( '\SMW\Observer' ) + ->setMethods( array( 'lila' ) ) + ->getMock(); + + $observer->expects( $this->any() ) + ->method( 'lila' ) + ->will( $this->returnCallback( array( $this, 'lilaObserverCallback' ) ) ); + + return $observer; + + } + + /** + * Helper method that returns a ObservableSubjectDispatcher object + * + * @since 1.9 + * + * @param $data + * + * @return ObservableSubjectDispatcher + */ + private function getInstance( $observer = null ) { + return new ObservableSubjectDispatcher( $observer ); + + } + + /** + * @since 1.9 + */ + public function testConstructor() { + $this->assertInstanceOf( $this->getClass(), $this->getInstance() ); + } + + /** + * @since 1.9 + */ + public function testAttachDetach() { + + $dispatcher = $this->getInstance(); + + $observer = $this->newObserver(); + $dispatcher->attach( $observer ); + + $this->assertCount( 1, $dispatcher->getObservers() ); + $dispatcher->detach( $observer ); + $this->assertCount( 0, $dispatcher->getObservers() ); + + $dispatcher = $this->getInstance( $this->newObserver() ); + $this->assertCount( 1, $dispatcher->getObservers() ); + + } + + /** + * @since 1.9 + */ + public function testSourceDispatching() { + + // Register Observer with the dispatcher + $dispatcher = $this->getInstance( $this->newObserver() ); + + // Register dispatcher with a source + $source = $this->newDispatchableSource(); + $source->setDispatcher( $dispatcher ); + + // Rather being the source itself, the dispatcher returns the invoked instance + $this->assertEquals( $this, $dispatcher->getSource() ); + + // The dipatchers forwards a registered state change but the Observer + // is using the invoked source ($this) as means to communicate + $dispatcher->setState( 'lila' ); + $this->assertEquals( 'lilaObserver was informed by source', $this->ObserverSentAMessage ); + + } + + /** + * Verifies that the Observer was acting on the invoked Subject + * + * @since 1.9 + * + * @param $subject + */ + public function lilaObserverCallback( $subject ) { + return $subject->ObserverSentAMessage = 'lilaObserver was informed by source'; + } + + /** + * Sets the source + * + * @since 1.9 + * + * @param ObservableDispatcher $dispatcher + */ + public function setDispatcherCallback( ObservableDispatcher $dispatcher ) { + $dispatcher->setSource( $this ); + } + +} diff --git a/tests/phpunit/includes/ObserverTest.php b/tests/phpunit/includes/ObserverTest.php index 31c11d8..4efe1f3 100644 --- a/tests/phpunit/includes/ObserverTest.php +++ b/tests/phpunit/includes/ObserverTest.php @@ -15,7 +15,7 @@ /** * @covers \SMW\Observer - * @covers \SMW\Subject + * @covers \SMW\ObservableSubject * * @ingroup Test * @@ -57,17 +57,17 @@ } /** - * Helper method that returns a Subject object + * Helper method that returns a ObservableSubject object * * @since 1.9 * * @param $data * - * @return Subject + * @return ObservableSubject */ - private function newObserverSubject() { + private function newObservableSubject() { - $subject = $this->getMockBuilder( '\SMW\Subject' ) + $subject = $this->getMockBuilder( '\SMW\ObservableSubject' ) ->setMethods( array( 'lulu' ) ) ->getMock(); @@ -84,7 +84,7 @@ */ public function testConstructor() { $this->assertInstanceOf( '\SMW\Observer', $this->newObserver() ); - $this->assertInstanceOf( '\SMW\Subject', $this->newObserverSubject() ); + $this->assertInstanceOf( '\SMW\ObservableSubject', $this->newObservableSubject() ); } /** @@ -92,7 +92,7 @@ */ public function testInvokeAndDetach() { - $subject = $this->getMockForAbstractClass( '\SMW\Subject' ); + $subject = $this->getMockForAbstractClass( '\SMW\ObservableSubject' ); // Same Observer instance attached twice results in only one registered object $observer = $this->getMockForAbstractClass( '\SMW\Observer', array( $subject ) ); @@ -117,7 +117,7 @@ */ public function testNotifyAndUpdate() { - $subject = $this->newObserverSubject(); + $subject = $this->newObservableSubject(); $subject->attach( $this->newObserver() ); $this->assertNull( $subject->getState() ); diff --git a/tests/phpunit/includes/PropertyChangeNotifierTest.php b/tests/phpunit/includes/PropertyChangeNotifierTest.php index ff3def7..96a3664 100644 --- a/tests/phpunit/includes/PropertyChangeNotifierTest.php +++ b/tests/phpunit/includes/PropertyChangeNotifierTest.php @@ -3,6 +3,7 @@ namespace SMW\Test; use SMW\PropertyChangeNotifier; +use SMW\ObservableSubjectDispatcher; use SMW\DIProperty; use Title; @@ -77,7 +78,7 @@ * * @since 1.9 */ - public function testFindDisparity( $storeValues, $dataValues, $settings, $expected ) { + public function testDetectChanges( $storeValues, $dataValues, $settings, $expected ) { $subject = $this->newSubject( $this->newTitle( SMW_NS_PROPERTY ) ); $this->storeValues = $storeValues; @@ -92,7 +93,9 @@ ); $instance = $this->getInstance( $store, $data, $settings ); - $observer = new MockChangeObserver( $instance ); + $observer = new MockChangeObserver(); + + $instance->setDispatcher( new ObservableSubjectDispatcher( $observer ) ); $this->assertInstanceOf( $this->getClass(), $instance->detectChanges() ); $this->assertEquals( $subject->getTitle(), $instance->getTitle() ); -- To view, visit https://gerrit.wikimedia.org/r/77565 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I64c156006e9340aba57aba6b86d3b3c93a4b5c82 Gerrit-PatchSet: 3 Gerrit-Project: mediawiki/extensions/SemanticMediaWiki Gerrit-Branch: master Gerrit-Owner: Mwjames <[email protected]> Gerrit-Reviewer: Mwjames <[email protected]> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
