diff --git a/BaselineOfDebuggingSpy/BaselineOfDebuggingSpy.class.st b/BaselineOfDebuggingSpy/BaselineOfDebuggingSpy.class.st index 7d92234..3f90c67 100644 --- a/BaselineOfDebuggingSpy/BaselineOfDebuggingSpy.class.st +++ b/BaselineOfDebuggingSpy/BaselineOfDebuggingSpy.class.st @@ -9,15 +9,14 @@ Class { BaselineOfDebuggingSpy >> baseline: spec [ - - spec baseline: 'ExperimentModel' with: [ - spec repository: - 'github://Pharo-XP-Tools/ExperimentModel:main' ]. - - spec for: #common do: [ - spec postLoadDoIt: #postloadAction. - spec package: 'DebuggingSpy'. - spec package: 'DebuggingSpy-Tests' ] + spec baseline: 'ExperimentModel' with: [ spec repository: 'github://Pharo-XP-Tools/ExperimentModel:main' ]. + + spec for: #common do: [ + spec postLoadDoIt: #postloadAction. + spec package: 'DebuggingSpy'. + spec package: 'DebuggingSpy-Tests'. + spec package: 'DebuggingSpy-Browser'. + spec package: 'DebuggingSpy-Browser-Tests' ] ] { #category : 'baselines' } diff --git a/DebuggingSpy-Browser-Tests/DSRecordBrowserPresenterTest.class.st b/DebuggingSpy-Browser-Tests/DSRecordBrowserPresenterTest.class.st new file mode 100644 index 0000000..5dc18e3 --- /dev/null +++ b/DebuggingSpy-Browser-Tests/DSRecordBrowserPresenterTest.class.st @@ -0,0 +1,303 @@ +Class { + #name : 'DSRecordBrowserPresenterTest', + #superclass : 'TestCase', + #instVars : [ + 'browser' + ], + #category : 'DebuggingSpy-Browser-Tests', + #package : 'DebuggingSpy-Browser-Tests' +} + +{ #category : 'helpers' } +DSRecordBrowserPresenterTest >> filesPresenter [ + + ^ browser presenterAt: #fileListPresenter +] + +{ #category : 'helpers' } +DSRecordBrowserPresenterTest >> generateRecordsFile [ + "Generates a file of random records and returns its file reference." + + | records recordFileRef writeStream | + records := self getRecordExamples. + + recordFileRef := self temporaryDirectory / ('ds-spy-test-' , UUID new asString). + recordFileRef ensureCreateFile. + writeStream := recordFileRef writeStream. + + writeStream nextPut: $[. + + records doWithIndex: [ :record :index | + writeStream nextPutAll: (STON toString: record). + + index = records size ifFalse: [ + writeStream nextPut: $,. + writeStream crlf ] ]. + + writeStream nextPut: $]. + + writeStream close. + + ^ recordFileRef +] + +{ #category : 'helpers' } +DSRecordBrowserPresenterTest >> getRecordExamples [ + + ^ OrderedCollection new + add: (DSBrowseRecord new + windowId: 1; + dateTime: (DateAndTime fromSeconds: 1); + yourself); + add: (DSMouseEnterWindowRecord new + windowId: 2; + dateTime: (DateAndTime fromSeconds: 2); + yourself); + add: (DSMouseLeaveWindowRecord new + windowId: 3; + dateTime: (DateAndTime fromSeconds: 3); + yourself); + add: (DSInspectItRecord new + windowId: 4; + dateTime: (DateAndTime fromSeconds: 4); + yourself); + yourself +] + +{ #category : 'helpers' } +DSRecordBrowserPresenterTest >> recordsFilterPresenter [ + + ^ browser presenterAt: #recordsFilter +] + +{ #category : 'helpers' } +DSRecordBrowserPresenterTest >> recordsTablePresenter [ + + ^ browser presenterAt: #recordsTablePresenter +] + +{ #category : 'running' } +DSRecordBrowserPresenterTest >> setUp [ + + super setUp. + browser := DSRecordBrowserPresenter new +] + +{ #category : 'running' } +DSRecordBrowserPresenterTest >> tearDown [ + + DSRecordBrowserPresenter resetBrowser. + super tearDown +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testAddFile [ + + | fileRef | + fileRef := self generateRecordsFile. + + browser addFile: fileRef. + self assert: browser files size equals: 1. + self assert: self filesPresenter items size equals: 1. + + self assert: self filesPresenter selectedItem equals: fileRef +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testAddFileWhenAlreadyInList [ + + | fileRef | + fileRef := self generateRecordsFile. + + browser addFile: fileRef. + browser addFile: fileRef. + self assert: browser files size equals: 1. + self assert: self filesPresenter items size equals: 1. + self assert: self filesPresenter selectedItem equals: fileRef +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testAddingMultipleFiles [ + + | fileRef | + browser addFile: self generateRecordsFile. + fileRef := self generateRecordsFile. + + browser addFile: fileRef. + + self assert: browser files size equals: 2. + self assert: self filesPresenter items size equals: 2. + self assert: self filesPresenter selectedItem equals: fileRef +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testBrowserEmpty [ + + self assertEmpty: browser files. + self assert: self filesPresenter items size equals: 0. + self assert: self filesPresenter selectedItem equals: nil. + self assert: self recordsTablePresenter roots size equals: 0 +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testClosingBrowser [ + + DSRecordBrowserPresenter toggleBrowser. + DSRecordBrowserPresenter toggleBrowser. + self deny: DSRecordBrowserPresenter uniqueInstance window isOpen +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testCreatingAndOpeningBrowser [ + + DSRecordBrowserPresenter toggleBrowser. + self assert: DSRecordBrowserPresenter uniqueInstance window isOpen. + DSRecordBrowserPresenter toggleBrowser +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testFilteringAClassOfRecords [ + + | fileRef history | + fileRef := self generateRecordsFile. + history := browser getHistoryFrom: fileRef. + + browser addFile: fileRef. + self assert: self recordsTablePresenter roots size equals: history records size. + + self recordsFilterPresenter sourceList selectItem: DSBrowseRecord. + self recordsFilterPresenter addSelected. + + self deny: self recordsTablePresenter roots first class equals: DSBrowseRecord +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testFilteringAllRecords [ + + | fileRef history | + fileRef := self generateRecordsFile. + history := browser getHistoryFrom: fileRef. + + browser addFile: fileRef. + + self recordsFilterPresenter addAll. + self assert: self recordsTablePresenter roots size equals: 0 +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testGetHistoryFrom [ + + | fileRef | + fileRef := self generateRecordsFile. + self assert: (browser getHistoryFrom: fileRef) class equals: DSRecordHistory +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testGetRecordColorAssociationsFrom [ + + | windows colorAssociations | + windows := { (DSWindowRecord new + toolInfos: { (DSToolInfo new + toolClassName: 'StPlaygroundPresenter'; + yourself) } asOrderedCollection; + events: { + DSWindowOpenedRecord new. + DSDoItRecord new. + DSStepThroughRecord new }) } asOrderedCollection. + + colorAssociations := browser getRecordColorAssociationsFrom: windows. + + self assert: colorAssociations first key class equals: DSWindowOpenedRecord. + self assert: (colorAssociations at: 2) key class equals: DSDoItRecord. + self assert: colorAssociations last key class equals: DSStepThroughRecord. + + colorAssociations do: [ :association | self assert: association value equals: (Color fromHexString: '#70B77E') ] +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testRemoveFile [ + + | fileRef1 fileRef2 | + fileRef1 := self generateRecordsFile. + fileRef2 := self generateRecordsFile. + + browser addFile: fileRef1. + browser addFile: fileRef2. + browser removeFile: fileRef1. + + self assert: browser files size equals: 1. + self assert: self filesPresenter items size equals: 1. + self assert: self filesPresenter selectedItem equals: fileRef2 +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testRemoveLastFile [ + + | fileRef1 | + fileRef1 := self generateRecordsFile. + + browser addFile: fileRef1. + browser removeFile: fileRef1. + + self assert: browser files size equals: 0. + self assert: self filesPresenter items size equals: 0. + self assert: self filesPresenter selectedItem equals: nil +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testStartRecording [ + + self assert: browser timerWindow isNil. + self deny: DSRecordRegistry autoSerialize. + self deny: DSSpy recordingSession. + + browser startRecording. + self assert: DSSpy recordingSession. + self assert: DSRecordRegistry autoSerialize. + self deny: browser timerWindow isNil. + + browser stopRecording +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testStopRecording [ + + | timerWindow | + browser startRecording. + timerWindow := browser timerWindow. + browser stopRecording. + + self deny: (self currentWorld submorphs includes: timerWindow). + self assert: browser timerWindow isNil +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testUpdateRecordsTable [ + + | fileRef presenterMock | + fileRef := self generateRecordsFile. + presenterMock := MockObject new on: #selectedItem respond: fileRef. + browser updateRecordsTable: presenterMock. + + self assert: self recordsTablePresenter roots first key class equals: DSBrowseRecord. + self assert: (self recordsTablePresenter roots at: 2) key class equals: DSMouseEnterWindowRecord. + self assert: (self recordsTablePresenter roots at: 3) key class equals: DSMouseLeaveWindowRecord. + self assert: self recordsTablePresenter roots last key class equals: DSInspectItRecord +] + +{ #category : 'tests' } +DSRecordBrowserPresenterTest >> testUpdateRecordsTableWhenAddingFile [ + + browser addFile: self generateRecordsFile. + + self assert: self recordsTablePresenter roots first key class equals: DSBrowseRecord. + self assert: (self recordsTablePresenter roots at: 2) key class equals: DSMouseEnterWindowRecord. + self assert: (self recordsTablePresenter roots at: 3) key class equals: DSMouseLeaveWindowRecord. + self assert: self recordsTablePresenter roots last key class equals: DSInspectItRecord +] + +{ #category : 'helpers' } +DSRecordBrowserPresenterTest >> timelinePresenter [ + + ^ browser presenterAt: #graphicTimeline +] diff --git a/DebuggingSpy-Browser-Tests/DSTimerWindowTest.class.st b/DebuggingSpy-Browser-Tests/DSTimerWindowTest.class.st new file mode 100644 index 0000000..c4a1038 --- /dev/null +++ b/DebuggingSpy-Browser-Tests/DSTimerWindowTest.class.st @@ -0,0 +1,54 @@ +Class { + #name : 'DSTimerWindowTest', + #superclass : 'TestCase', + #instVars : [ + 'timerWindow' + ], + #category : 'DebuggingSpy-Browser-Tests', + #package : 'DebuggingSpy-Browser-Tests' +} + +{ #category : 'layout' } +DSTimerWindowTest >> currentTimeMorph [ + "Returns the window's timeNowMorph" + + ^ timerWindow readSlot: (DSTimerWindow slotNamed: #currentTimeMorph) +] + +{ #category : 'running' } +DSTimerWindowTest >> setUp [ + super setUp. + + timerWindow := DSTimerWindow new. +] + +{ #category : 'tests' } +DSTimerWindowTest >> testElapsedTime [ + + DSSpy recordingSession: true. + timerWindow startTimer. + + (Delay forMilliseconds: 1000) wait. + + DSSpy recordingSession: false. + self assert: timerWindow elapsedTime equals: 1 +] + +{ #category : 'tests' } +DSTimerWindowTest >> testEmptyTimerMorph [ + + self assert: (Time readFrom: self timerMorph contents readStream) seconds equals: 0 +] + +{ #category : 'tests' } +DSTimerWindowTest >> testTimeNowMorph [ + + self assert: (Time readFrom: self currentTimeMorph contents readStream) asSeconds equals: Time now asSeconds +] + +{ #category : 'layout' } +DSTimerWindowTest >> timerMorph [ + "Returns the window's timerMorph." + + ^ timerWindow readSlot: (DSTimerWindow slotNamed: #timerMorph) +] diff --git a/DebuggingSpy-Browser-Tests/package.st b/DebuggingSpy-Browser-Tests/package.st new file mode 100644 index 0000000..b20e695 --- /dev/null +++ b/DebuggingSpy-Browser-Tests/package.st @@ -0,0 +1 @@ +Package { #name : 'DebuggingSpy-Browser-Tests' } diff --git a/DebuggingSpy-Browser/DSAbstractEventRecord.extension.st b/DebuggingSpy-Browser/DSAbstractEventRecord.extension.st new file mode 100644 index 0000000..5696c56 --- /dev/null +++ b/DebuggingSpy-Browser/DSAbstractEventRecord.extension.st @@ -0,0 +1,17 @@ +Extension { #name : 'DSAbstractEventRecord' } + +{ #category : '*DebuggingSpy-Browser' } +DSAbstractEventRecord class >> getLeafSubClasses [ + "Returns a list of all non-abstract subclasses, representing all record classes." + + | classes | + classes := OrderedCollection new. + self subclasses do: [ :subclass | + subclass subclasses isEmpty + ifTrue: [ classes add: subclass ] + ifFalse: [ + subclass = DSDoItRecord ifTrue: [ classes add: subclass ]. + classes addAll: subclass getLeafSubClasses ] ]. + + ^ classes +] diff --git a/DebuggingSpy-Browser/DSRecordBrowserPresenter.class.st b/DebuggingSpy-Browser/DSRecordBrowserPresenter.class.st new file mode 100644 index 0000000..5c323b1 --- /dev/null +++ b/DebuggingSpy-Browser/DSRecordBrowserPresenter.class.st @@ -0,0 +1,448 @@ +" +Debugging Spy main interface which includes : +- an opening button on the topside bar of the Pharo IDE +- buttons to start/stop the system instrumentation +- a window to visualize data from recording files +" +Class { + #name : 'DSRecordBrowserPresenter', + #superclass : 'SpPresenter', + #instVars : [ + 'files', + 'recordsTablePresenter', + 'timerWindow', + 'graphicTimeline', + 'recordsFilter', + 'toolbarPresenter', + 'fileListPresenter', + 'startRecordButtonPresenter', + 'stopRecordButtonPresenter' + ], + #classInstVars : [ + 'uniqueInstance' + ], + #category : 'DebuggingSpy-Browser', + #package : 'DebuggingSpy-Browser' +} + +{ #category : 'world menu' } +DSRecordBrowserPresenter class >> menuCommandOn: aBuilder [ + "Adds the DSSpy button on topside bar." + + + (aBuilder item: #DSSpy) + order: 100; + help: 'Open the Debugging Spy browser.'; + action: [ self toggleBrowser ] +] + +{ #category : 'initialization' } +DSRecordBrowserPresenter class >> resetBrowser [ + "Removes the actual browser then another one will be created the next time it needs to be opened." + +