diff --git a/src/Molecule-Tests/MolComponentImplTest.class.st b/src/Molecule-Tests/MolComponentImplTest.class.st index 43af80b..67a6ae0 100644 --- a/src/Molecule-Tests/MolComponentImplTest.class.st +++ b/src/Molecule-Tests/MolComponentImplTest.class.st @@ -234,6 +234,8 @@ MolComponentImplTest >> testForEventsRemoveProducer [ | component | component := MolCompleteComponentImpl start: #myComponentA. + "initial state" + self assert: (component eventsSubscribers at: MolUsedEvents) equals: MolUtils defaultComponentName. component forEvents: MolUsedEvents useAllProducers: #(#producerA #producerB #producerC). @@ -247,7 +249,8 @@ MolComponentImplTest >> testForEventsRemoveProducer [ component forEvents: MolUsedEvents removeProducer: #producerC. self assert: component eventsSubscribers size equals: 1. - self assert: (component eventsSubscribers at: MolUsedEvents) equals: nil. + "back to initial state" + self assert: (component eventsSubscribers at: MolUsedEvents) equals: MolUtils defaultComponentName. ] { #category : #'tests - connecting - events producers' } @@ -673,6 +676,37 @@ MolComponentImplTest >> testStart2 [ self assert: component componentName equals: #compA. ] +{ #category : #'tests - connecting - events producers' } +MolComponentImplTest >> testStartAndStopComponentWithRemoveProducerSeveralTimes [ + "This test reproduce issue #246: Exception after several starts and stops of same component" + + | compA compB | + "start first implemention of a component contract" + compA := MolCompleteComponentImpl start: #compA. + compB := MolCompleteComponentImpl start: #compB. + + "link compB to compA" + compB forServices: MolUsedServices useProvider: #compA. + compB forEvents: MolUsedEvents useProducer: #compA. + compB getMolUsedEventsSubscriber subscribe: compB. + + "call the service of the first component, it answer #service" + self assert: compB getMolUsedServicesProvider service equals: #service. + + "stop and start component several times" + 1 to: 10 do:[ :i | + compB forEvents: MolUsedEvents removeProducer: #compA. + compB class stop: #compB. + compB := MolCompleteComponentImpl start: #compB. + compB forServices: MolUsedServices useProvider: #compA. + compB forEvents: MolUsedEvents useProducer: #compA. + compB getMolUsedEventsSubscriber subscribe: compB. + self assert: compB getMolUsedServicesProvider service equals: #service. + ]. + + +] + { #category : #'tests - component creation' } MolComponentImplTest >> testStartWithGeneratedName [ diff --git a/src/Molecule/MolComponentImpl.trait.st b/src/Molecule/MolComponentImpl.trait.st index fcde883..e52ac50 100644 --- a/src/Molecule/MolComponentImpl.trait.st +++ b/src/Molecule/MolComponentImpl.trait.st @@ -348,7 +348,10 @@ MolComponentImpl >> forEvents: anEventsTrait removeProducer: aComponentName [ producers := self eventsSubscribers at: anEventsTrait. producers ifNil:[ ^self ]. - producers = aComponentName ifTrue:[ self eventsSubscribers at: anEventsTrait put: nil. ^ self ]. + producers = aComponentName ifTrue:[ + "Molecule issue #242: store the default component name when a producer is removed to going back to the initial state" + self eventsSubscribers at: anEventsTrait put: MolUtils defaultComponentName. ^ self + ]. (producers isArray and:[producers includes: aComponentName]) ifTrue: [ | newProducers | newProducers := producers asOrderedCollection copy. newProducers remove: aComponentName. diff --git a/src/Molecule/MolEventSubscriber.class.st b/src/Molecule/MolEventSubscriber.class.st index 84122ad..d9eaa2e 100644 --- a/src/Molecule/MolEventSubscriber.class.st +++ b/src/Molecule/MolEventSubscriber.class.st @@ -61,15 +61,20 @@ MolEventSubscriber >> connectOriginator: componentName to: aComponent [ "Connect a component to event pipeline" | key connect | - key := aComponent eventsSubscribers at: self events ifAbsent: [ nil ]. - connect := key isSymbol ifTrue:[ componentName = key ] ifFalse:[ key includes: componentName ]. - - connect ifTrue: [ - self events allSelectors do: [ :event | - | originator | - originator := self originatorsLinks at: componentName. - originator ifNil: [ ^ self error: 'Component originator is nil' ]. - originator when: event send: event to: aComponent ] ] + key := aComponent eventsSubscribers at: self events ifAbsent: [ MolUtils defaultComponentName ]. + + connect := key isSymbol + ifTrue:[ componentName = key ] + ifFalse:[ key includes: componentName ]. + + "Cannot connect, stop here" + connect ifFalse:[ ^ self ]. + + self events allSelectors do: [ :event | + | originator | + originator := self originatorsLinks at: componentName. + originator ifNil: [ ^ self error: 'Component originator is nil' ]. + originator when: event send: event to: aComponent ] ] { #category : #private }