diff --git a/src/Refactoring-Core/RBSplitCascadeRefactoring.class.st b/src/Refactoring-Core/RBSplitCascadeRefactoring.class.st index eee97cf44d9..6b905d0d039 100644 --- a/src/Refactoring-Core/RBSplitCascadeRefactoring.class.st +++ b/src/Refactoring-Core/RBSplitCascadeRefactoring.class.st @@ -135,13 +135,31 @@ RBSplitCascadeRefactoring >> split: anInterval from: aSelector in: aClass [ { #category : 'transforming' } RBSplitCascadeRefactoring >> splitCascade [ - ancestorNode parent - addNode: (beforeNodes size > 1 - ifTrue: [ OCCascadeNode messages: beforeNodes ] - ifFalse: [ beforeNodes first ]) - before: ancestorNode. - afterNodes size > 1 - ifTrue: [ cascadeNode messages: afterNodes ] - ifFalse: [ cascadeNode replaceWith: afterNodes first ]. - class compileTree: ancestorNode methodNode + ancestorNode parent + addNode: (beforeNodes size > 1 + ifTrue: [ OCCascadeNode messages: beforeNodes ] + ifFalse: [ beforeNodes first ]) + before: ancestorNode. + ancestorNode isAssignment + ifTrue: [ + "Flatten remaining part for assignment" + | allMessages | + allMessages := cascadeNode messages. + (allMessages copyFrom: beforeNodes size + 1 to: allMessages size - 1) + do: [ :each | + | copy | + copy := each copy. + copy receiver: cascadeNode receiver. + ancestorNode parent + addNode: copy + before: ancestorNode + ]. + cascadeNode replaceWith: allMessages last. + ] + ifFalse: [ + afterNodes size > 1 + ifTrue: [ cascadeNode messages: afterNodes ] + ifFalse: [ cascadeNode replaceWith: afterNodes first ]. + ]. + class compileTree: ancestorNode methodNode ] diff --git a/src/Refactoring-Transformations-Tests/RBCreateCascadeRefactoringTest.class.st b/src/Refactoring-Transformations-Tests/RBCreateCascadeRefactoringTest.class.st new file mode 100644 index 00000000000..e13e8e39900 --- /dev/null +++ b/src/Refactoring-Transformations-Tests/RBCreateCascadeRefactoringTest.class.st @@ -0,0 +1,136 @@ +Class { + #name : 'RBCreateCascadeRefactoringTest', + #superclass : 'RBAbstractTransformationTest', + #instVars : [ + 'class' + ], + #category : 'Refactoring-Transformations-Tests-Test', + #package : 'Refactoring-Transformations-Tests', + #tag : 'Test' +} + +{ #category : 'utilities' } +RBCreateCascadeRefactoringTest >> createCascadeFrom: sourceToCombine in: source [ + + | method start | + method := class compile: source classified: '#test data'. + start := method source findString: sourceToCombine. + ^ RBCreateCascadeRefactoring + model: model + combine: (start to: (start + sourceToCombine size - 1)) + from: #example + in: class +] + +{ #category : 'running' } +RBCreateCascadeRefactoringTest >> setUp [ + + super setUp. + model := RBNamespace new. + model defineClass: [ :aBuilder | + aBuilder + superclass: Object; + name: #TestClass ]. + class := model classNamed: #TestClass. +] + +{ #category : 'tests' } +RBCreateCascadeRefactoringTest >> testAssignmentOnlyLast [ + + | ref | + ref := self + createCascadeFrom: 'obj foo. + x := obj bar.' + in: 'example + obj foo. + x := obj bar.'. + ref generateChanges. + self assert: + (class parseTreeForSelector: #example) + equals: + (self parseMethod: 'example + x := obj + foo; + bar.') +] + +{ #category : 'tests' } +RBCreateCascadeRefactoringTest >> testCascadeFlattening [ + + | ref | + ref := self + createCascadeFrom: 'obj foo; bar. + obj baz.' + in: 'example + obj foo; bar. + obj baz.'. + ref generateChanges. + self assert: + (class parseTreeForSelector: #example) + equals: + (self parseMethod: 'example + obj + foo; + bar; + baz.') +] + +{ #category : 'tests' } +RBCreateCascadeRefactoringTest >> testCreateCascadeBasic [ + + | ref | + ref := self + createCascadeFrom: 'obj foo. + obj bar.' + in: 'example + obj foo. + obj bar.'. + ref generateChanges. + self assert: + (class parseTreeForSelector: #example) + equals: + (self parseMethod: 'example + obj + foo; + bar.') +] + +{ #category : 'failure tests' } +RBCreateCascadeRefactoringTest >> testDifferentReceiversFail [ + + | ref | + ref := self + createCascadeFrom: 'obj1 foo. + obj2 bar.' + in: 'example + obj1 foo. + obj2 bar.'. + self should: [ ref generateChanges ] + raise: RBRefactoringError. +] + +{ #category : 'tests' } +RBCreateCascadeRefactoringTest >> testMultipleAssignmentsFail [ + + | ref | + ref := self + createCascadeFrom: 'x := obj foo. + x := obj bar.' + in: 'example + x := obj foo. + x := obj bar.'. + self should: [ ref generateChanges ] + raise: RBRefactoringError. +] + +{ #category : 'failure tests' } +RBCreateCascadeRefactoringTest >> testSingleStatementFails [ + + | ref | + ref := self + createCascadeFrom: 'obj foo.' + in: 'example + obj foo.'. + self should: [ ref generateChanges ] + raise: RBRefactoringError. +] diff --git a/src/Refactoring-Transformations-Tests/RBSplitCascadeRefactoringTest.class.st b/src/Refactoring-Transformations-Tests/RBSplitCascadeRefactoringTest.class.st new file mode 100644 index 00000000000..83aca2b9b52 --- /dev/null +++ b/src/Refactoring-Transformations-Tests/RBSplitCascadeRefactoringTest.class.st @@ -0,0 +1,193 @@ +Class { + #name : 'RBSplitCascadeRefactoringTest', + #superclass : 'RBAbstractTransformationTest', + #instVars : [ + 'class' + ], + #category : 'Refactoring-Transformations-Tests-Test', + #package : 'Refactoring-Transformations-Tests', + #tag : 'Test' +} + +{ #category : 'utilities' } +RBSplitCascadeRefactoringTest >> createCascadeFrom: sourceToCombine in: source [ + + | method start | + method := class compile: source classified: '#test data'. + start := method source findString: sourceToCombine. + ^ RBCreateCascadeRefactoring + model: model + combine: (start to: (start + sourceToCombine size - 1)) + from: #example + in: class +] + +{ #category : 'running' } +RBSplitCascadeRefactoringTest >> setUp [ + + super setUp. + model := RBNamespace new. + model defineClass: [ :aBuilder | + aBuilder + superclass: Object; + name: #TestClass ]. + class := model classNamed: #TestClass. +] + +{ #category : 'utilities' } +RBSplitCascadeRefactoringTest >> splitCascadeFrom: sourceToSplit in: source [ + + | method start | + method := class compile: source classified: '#test data'. + start := method source findString: sourceToSplit. + ^ RBSplitCascadeRefactoring + model: model + split: (start to: (start + sourceToSplit size - 1)) + from: #example + in: class +] + +{ #category : 'tests' } +RBSplitCascadeRefactoringTest >> testAssignmentSplit [ + +| ref | +ref := self + splitCascadeFrom: ';' + in: 'example + x := obj foo; + bar; + baz'. +ref generateChanges. + +self assert: + (class parseTreeForSelector: #example) + equals: + (self parseMethod: 'example + obj foo. + obj bar. + x := obj baz') +] + +{ #category : 'tests' } +RBSplitCascadeRefactoringTest >> testBasicSplit [ + + | ref | + ref := self + splitCascadeFrom: ';' + in: 'example + obj foo; + bar; + baz'. + ref generateChanges. + self assert: + (class parseTreeForSelector: #example) + equals: + (self parseMethod: 'example + obj foo. + obj + bar; + baz.') +] + +{ #category : 'tests' } +RBSplitCascadeRefactoringTest >> testCreateThenSplitRoundTrip [ + + | createRef splitRef originalMethod | + originalMethod := self parseMethod: 'example + obj foo. + obj bar.'. + createRef := self + createCascadeFrom: 'obj foo. + obj bar.' + in: 'example + obj foo. + obj bar.'. + createRef generateChanges. + splitRef := self + splitCascadeFrom: ';' + in: ((class parseTreeForSelector: #example) source). + splitRef generateChanges. + self assert: + (class parseTreeForSelector: #example) + equals: originalMethod +] + +{ #category : 'tests' } +RBSplitCascadeRefactoringTest >> testInvalidSplitPosition [ + + | ref | + ref := self + splitCascadeFrom: 'foo' + in: 'example + obj foo; + bar; + baz'. + self should: [ ref generateChanges ] + raise: RBRefactoringError. +] + +{ #category : 'tests' } +RBSplitCascadeRefactoringTest >> testNotInCascade [ + + | ref | + ref := self + splitCascadeFrom: 'foo' + in: 'example + obj foo. + obj bar.'. + self should: [ ref generateChanges ] + raise: RBRefactoringError. +] + +{ #category : 'tests' } +RBSplitCascadeRefactoringTest >> testReturnSplit [ + + | ref | + ref := self + splitCascadeFrom: ';' + in: 'example + ^ obj foo; + bar; + baz'. + ref generateChanges. + self assert: + (class parseTreeForSelector: #example) + equals: + (self parseMethod: 'example + obj foo. + ^ obj + bar; + baz.') +] + +{ #category : 'tests' } +RBSplitCascadeRefactoringTest >> testSplitSingleMessage [ + + | ref | + ref := self + splitCascadeFrom: ';' + in: 'example + obj foo; + bar'. + ref generateChanges. + self assert: + (class parseTreeForSelector: #example) + equals: + (self parseMethod: 'example + obj foo. + obj bar.') +] + +{ #category : 'tests' } +RBSplitCascadeRefactoringTest >> testWholeCascadeFail [ + + | ref | + ref := self + splitCascadeFrom: 'foo; bar; baz' + in: 'example + obj foo; + bar; + baz'. + self should: [ ref generateChanges ] + raise: RBRefactoringError. +]