refactoring_custom/SmallSense__CustomMenuBuilderTests.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Mon, 13 Nov 2017 22:26:12 -0300
changeset 1060 af3a048f9618
parent 833 297eb38e4eee
child 1072 a44c741ee5ef
permissions -rw-r--r--
Fixed xompletion of instance variables in inspector

"
A custom code generation and refactoring support for Smalltalk/X
Copyright (C) 2013-2015 Jakub Nesveda
Copyright (C) 2013-now  Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
"{ Package: 'stx:goodies/smallsense/refactoring_custom' }"

"{ NameSpace: SmallSense }"

Smalltalk::TestCase subclass:#CustomMenuBuilderTests
	instanceVariableNames:'builder menu provider manager mock generatorClassMock resources'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-Refactoring-Custom-UI-Tests'
!

!CustomMenuBuilderTests class methodsFor:'documentation'!

copyright
"
A custom code generation and refactoring support for Smalltalk/X
Copyright (C) 2013-2015 Jakub Nesveda
Copyright (C) 2013-now  Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
! !

!CustomMenuBuilderTests methodsFor:'initialization & release'!

setUp
    super setUp.

    menu := Menu labels: 'Label_01
Label_02
Label_03' values: nil.

    mock := CustomMock new.

    provider := mock mockOf: OrderedCollection.
    provider compileMockMethod: 'generatorsAndRefactoringsDo: aBlock
        self do: aBlock'.  

    manager := CustomManager new.
    manager generatorsOrRefactoringsProvider: provider.

    builder := CustomMenuBuilder new.
    builder manager: manager.

    generatorClassMock := mock mockClassOf: Object.
    mock createMockGetters: generatorClassMock forSelectors: {
        'label'. 'group'. 'name'. 'isAbstract'. 'availableInContext:'. 
        'availableInPerspective:'. 'availableForProgrammingLanguagesInContext:'
    }.

    resources := mock mockOf: Object.
    resources compileMockMethod: 'string:aString ^ ''Translated '', aString'.

    "Modified: / 01-02-2015 / 20:00:43 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

tearDown

    mock unmockAll.
    
    super tearDown.

    "Modified: / 28-12-2014 / 22:02:26 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomMenuBuilderTests methodsFor:'private'!

addGenerator: aLabel group: aGroup
    "Creates initialized code generator mock and adds it to managers generators"
    | generator |

    generator := generatorClassMock new
        objectAttributeAt: #isAbstract put: false;
        objectAttributeAt: #label put: aLabel;
        objectAttributeAt: #name put: 'Unknown class name';
        objectAttributeAt: #group put: aGroup;
        objectAttributeAt: #availableInContext: put: true;
        objectAttributeAt: #availableInPerspective: put: true;
        objectAttributeAt: #availableForProgrammingLanguagesInContext: put: true;
        yourself.

    manager generatorsOrRefactoringsProvider add: generator.

    ^ generator

    "Created: / 28-12-2014 / 22:10:09 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 01-02-2015 / 20:01:33 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

menuItemLabels
    "Helper which returns labels from menu item as collection as string.
    We are comparing labels, because menu items are not comparable - 
    MenuItem label: 'Label' not equals MenuItem label: 'Label'"

    ^ (OrderedCollection streamContents: [ :stream |
        menu itemsDo: [ :item |
            stream nextPut: item label.
            item submenuChannel notNil ifTrue: [ 
                stream nextPut: (OrderedCollection streamContents: [ :innerStream |
                    item submenuChannel value itemsDo: [ :innerItem |
                        innerStream nextPut: innerItem label
                    ]
                ]) asArray
            ]
        ]
    ]) asArray

    "Created: / 28-12-2014 / 10:41:29 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 28-12-2014 / 23:17:41 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomMenuBuilderTests methodsFor:'tests'!

test_build_menu_empty
    | expectedMenu actualMenu |

    expectedMenu := {'Label_01'. 'Label_02'. 'Label_03'}.

    builder
        perspective: CustomPerspective classPerspective;
        menu: menu;
        submenuLabel: 'SomeLabel';
        buildMenu.    

    actualMenu := self menuItemLabels.

    self assert: expectedMenu = actualMenu

    "Modified: / 28-12-2014 / 22:41:37 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_build_menu_for_context_filter
    | expectedMenu actualMenu |

    (self
        addGenerator: 'Generator_01' group: #();
        addGenerator: 'Generator_02' group: #(Group_02);
        addGenerator: 'Generator_03' group: #();
        addGenerator: 'Generator_04' group: #(Group_01);
        addGenerator: 'Generator_05' group: #(Group_01 Subgroup_01);
        addGenerator: 'Generator_06' group: #(Group_01);
        addGenerator: 'Generator_07' group: #(Group_01 Subgroup_01))
            objectAttributeAt: #availableInContext: put: false. "To have at least one generator not avilable for context"

    "Not present generators"
    (self addGenerator: 'Generator_08' group: #())
        objectAttributeAt: #availableForProgrammingLanguagesInContext: put: false.
    (self addGenerator: 'Generator_09' group: #())
        objectAttributeAt: #availableInPerspective: put: false.
    self addGenerator: 'Generator_10' group: #().

    menu := builder buildMenuForContext: CustomSubContext new filter: [ :generator |
        generator label ~= 'Generator_10'
    ].

    expectedMenu := {
        'Generator_01'.
        'Generator_03'.
        '-'.
        'Generator_04'.
        'Generator_06'.
        '-'.
        'Generator_02'.
        '-'.
        'Generator_05'.
        'Generator_07'.
    }.

    actualMenu := self menuItemLabels.

    self assert: expectedMenu = actualMenu

    "Modified (comment): / 28-12-2014 / 22:35:04 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_build_menu_two_generators
    | expectedMenu actualMenu navigationState |

    expectedMenu := {
        'Label_01'.
        'Label_02'. 
        'Translated BunchOfGenerators'. 
        {'Translated Generator_01'. 'Translated Generator_03'}.
        'Label_03'.
    }.

    self
        addGenerator: 'Generator_01' group: #();
        addGenerator: 'Generator_02' group: #();
        addGenerator: 'Generator_03' group: #().

    "Create some methods which actually uses context and perspective to be sure that they are correctly created"
    provider last
        compileMockMethod: 'availableInPerspective: perspective ^ perspective isClassPerspective';
        compileMockMethod: 'availableInContext: context ^ context selectedClasses first name == CustomMenuBuilderTests name'.

    navigationState := Tools::NavigationState new.
    navigationState selectedClasses value: {CustomMenuBuilderTests}.

    builder
        perspective: CustomPerspective classPerspective;
        menu: menu;
        submenuLabel: 'BunchOfGenerators';
        afterMenuItemLabelled: 'Label_02';
        generatorOrRefactoringFilter: [ :generatorOrRefactoring | generatorOrRefactoring label ~= 'Generator_02' ];
        navigationState: navigationState;
        resources: resources;
        buildMenu.    

    actualMenu := self menuItemLabels.

    self assert: expectedMenu = actualMenu.

    (menu menuItemAt: 3) submenuChannel value itemsDo: [ :item | 
        self assert: item enabled value
    ].

    "Created: / 28-12-2014 / 22:48:24 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 04-01-2015 / 15:08:14 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 12-06-2015 / 21:09:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_build_menu_two_generators_empty_builder

    self
        addGenerator: 'Generator_01' group: #();
        addGenerator: 'Generator_02' group: #();
        addGenerator: 'Generator_03' group: #().

    "Create some methods which actually uses context and perspective to be sure that they are correctly created"
    provider last
        compileMockMethod: 'availableInPerspective: perspective ^ perspective isClassPerspective';
        compileMockMethod: 'availableInContext: context ^ context selectedClasses first name == #CustomMenuBuilderTests'.

    self should: [
        builder buildMenu
    ] raise: Error suchThat: [ :error |
        (error description) = 'Attributes named menu and perspective are required.'
    ].

    "Created: / 04-01-2015 / 15:31:15 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_build_menu_two_generators_empty_label
    | expectedMenu actualMenu navigationState |

    expectedMenu := {
        'Label_01'.
        'Label_02'. 
        'Label_03'.
        'Unknown menu label'.
        {'Generator_01'. 'Generator_02'. 'Generator_03'}
    }.

    self
        addGenerator: 'Generator_01' group: #();
        addGenerator: 'Generator_02' group: #();
        addGenerator: 'Generator_03' group: #().

    "Create some methods which actually uses context and perspective to be sure that they are correctly created"
    provider last
        compileMockMethod: 'availableInPerspective: perspective ^ perspective isClassPerspective';
        compileMockMethod: 'availableInContext: context ^ context selectedClasses first name == #CustomMenuBuilderTests'.

    navigationState := Tools::NavigationState new.
    navigationState selectedClasses value: {CustomMenuBuilderTests}.

    builder
        perspective: CustomPerspective classPerspective;
        menu: menu;
        buildMenu.    

    actualMenu := self menuItemLabels.

    self assert: expectedMenu = actualMenu

    "Created: / 04-01-2015 / 15:44:43 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_build_menu_two_generators_with_nil_label
    | expectedMenu actualMenu printer expectedError actualError |

    self
        addGenerator: 'Generator_01' group: #();
        addGenerator: 'Generator_02' group: #().

    provider last objectAttributeAt: #label put: nil.  

    printer := mock mockOf: Object.
    printer compileMockMethod: 'showCR: message 
        (self objectAttributeAt: #showCR:) add: message';
        objectAttributeAt: #showCR: put: OrderedCollection new.

    builder
        perspective: CustomPerspective classPerspective;
        menu: menu;
        submenuLabel: 'BunchOfGenerators';
        errorPrinter: printer;
        buildMenu.

    expectedError := OrderedCollection new.

    actualError := printer objectAttributeAt: #showCR:.
    self assert: expectedError = actualError.

    expectedMenu := {
        'Label_01'.
        'Label_02'.
        'Label_03'.
        'BunchOfGenerators'. 
        {'Generator_01'}.
    }.

    actualMenu := self menuItemLabels.
    self assert: expectedMenu = actualMenu.

    "Created: / 01-02-2015 / 20:25:02 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_build_menu_two_generators_with_should_implement_error
    | expectedMenu actualMenu printer expectedError actualError |

    self
        addGenerator: 'Generator_01' group: #();
        addGenerator: 'Generator_02' group: #().

    provider last compileMockMethod: 'availableInPerspective: perspective 
        self label = ''Generator_02'' ifTrue: [
            self shouldImplement
        ].
        ^ true'.  

    printer := mock mockOf: Object.
    printer compileMockMethod: 'showCR: message 
        (self objectAttributeAt: #showCR:) add: message';
        objectAttributeAt: #showCR: put: OrderedCollection new.

    builder
        perspective: CustomPerspective classPerspective;
        menu: menu;
        submenuLabel: 'BunchOfGenerators';
        errorPrinter: printer;
        buildMenu.

    expectedError := OrderedCollection 
        with: 'An error occured when selecting code generators/refactorings.'
        with: 'Class: Unknown class name Error: functionality has to be implemented: a ', provider last className, '>>availableInPerspective:'.

    actualError := printer objectAttributeAt: #showCR:.
    self assert: expectedError = actualError.

    expectedMenu := {
        'Label_01'.
        'Label_02'.
        'Label_03'.
        'BunchOfGenerators'. 
        {'Generator_01'}.
    }.

    actualMenu := self menuItemLabels.
    self assert: expectedMenu = actualMenu.

    "Created: / 01-02-2015 / 20:19:29 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_build_menu_two_generators_with_subclass_responsibility_error
    | expectedMenu actualMenu printer expectedError actualError |

    self
        addGenerator: 'Generator_01' group: #();
        addGenerator: 'Generator_02' group: #().

    provider last compileMockMethod: 'availableInPerspective: perspective 
        self label = ''Generator_02'' ifTrue: [
            self subclassResponsibility
        ].
        ^ true'.  

    printer := mock mockOf: Object.
    printer compileMockMethod: 'showCR: message 
        (self objectAttributeAt: #showCR:) add: message';
        objectAttributeAt: #showCR: put: OrderedCollection new.

    builder
        perspective: CustomPerspective classPerspective;
        menu: menu;
        submenuLabel: 'BunchOfGenerators';
        errorPrinter: printer;
        buildMenu.

    expectedError := OrderedCollection 
        with: 'An error occured when selecting code generators/refactorings.'
        with: 'Class: Unknown class name Error: "availableInPerspective:" method must be reimplemented in subclass'.

    actualError := printer objectAttributeAt: #showCR:.
    self assert: expectedError = actualError.

    expectedMenu := {
        'Label_01'.
        'Label_02'.
        'Label_03'.
        'BunchOfGenerators'. 
        {'Generator_01'}.
    }.

    actualMenu := self menuItemLabels.
    self assert: expectedMenu = actualMenu.

    "Created: / 01-02-2015 / 19:17:25 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 01-02-2015 / 20:17:32 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_build_menu_two_generators_without_filter
    | expectedMenu actualMenu navigationState |

    expectedMenu := {
        'Label_01'.
        'Label_02'. 
        'Translated BunchOfGenerators'. 
        {'Translated Generator_01'. 'Translated Generator_02'. 'Translated Generator_03'}.
        'Label_03'.
    }.

    self
        addGenerator: 'Generator_01' group: #();
        addGenerator: 'Generator_02' group: #();
        addGenerator: 'Generator_03' group: #().

    "Create some methods which actually uses context and perspective to be sure that they are correctly created"
    provider last
        compileMockMethod: 'availableInPerspective: perspective ^ perspective isClassPerspective';
        compileMockMethod: 'availableInContext: context ^ context selectedClasses first name == CustomMenuBuilderTests name'.

    navigationState := Tools::NavigationState new.
    navigationState selectedClasses value: {CustomMenuBuilderTests}.

    builder
        perspective: CustomPerspective classPerspective;
        menu: menu;
        submenuLabel: 'BunchOfGenerators';
        afterMenuItemLabelled: 'Label_02';
        navigationState: navigationState;
        resources: resources;
        buildMenu.    

    actualMenu := self menuItemLabels.

    self assert: expectedMenu = actualMenu.

    (menu menuItemAt: 3) submenuChannel value itemsDo: [ :item | 
        self assert: item enabled value
    ].

    "Created: / 29-12-2014 / 09:33:20 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 04-01-2015 / 15:08:20 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
    "Modified: / 12-06-2015 / 21:09:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_groups_sort_block
    | expectedGroups actualGroups |

    actualGroups := {
        #(Group_09 Subgroup_02 Subsubgroup_02).
        #(Group_09 Subgroup_01 Subsubgroup_02).
        #(Group_09 Subgroup_01 Subsubgroup_01).
        #(Group_01).
        #(Group_09 Subgroup_01).
        #(Group_01 Subgroup_01).
        #(Group_03).
        #(Group_02 Subgroup_02).
        #(Group_02 Subgroup_01).
        #(Group_10).
        #(Group_09 Subgroup_01 Subsubgroup_02 Subsubsubgroup_01).
        #().
    }.

    "Maybe better order?"
    "
    expectedGroups := {
        #().
        #(Group_01).
        #(Group_01 Subgroup_01).
        #(Group_02 Subgroup_01).
        #(Group_02 Subgroup_02).
        #(Group_03).
        #(Group_09 Subgroup_01).
        #(Group_09 Subgroup_01 Subsubgroup_01).
        #(Group_09 Subgroup_01 Subsubgroup_02).
        #(Group_09 Subgroup_01 Subsubgroup_02 Subsubsubgroup_01).
        #(Group_09 Subgroup_02 Subsubgroup_02).
        #(Group_10)
    }. "

    expectedGroups := {
        #().
        #(Group_01).
        #(Group_03).
        #(Group_10).
        #(Group_01 Subgroup_01).
        #(Group_02 Subgroup_01).
        #(Group_02 Subgroup_02).
        #(Group_09 Subgroup_01).
        #(Group_09 Subgroup_01 Subsubgroup_01).
        #(Group_09 Subgroup_01 Subsubgroup_02).
        #(Group_09 Subgroup_02 Subsubgroup_02).
        #(Group_09 Subgroup_01 Subsubgroup_02 Subsubsubgroup_01).
    }.

    actualGroups sort: builder groupsSortBlock.    
    
    self assert: expectedGroups = actualGroups

    "Modified (format): / 28-12-2014 / 21:54:30 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_place_menu_item_after_menu_item_labeled_for_menu_item_empty
    | menuItem expectedMenuItemLabels actualMenuItemLabels |

    menuItem := MenuItem label: 'SomeLabel'.

    expectedMenuItemLabels := {'Label_01'. 'Label_02'. 'Label_03'. 'SomeLabel'}.

    builder placeMenuItem: menuItem afterMenuItemLabeled: nil forMenu: menu.

    actualMenuItemLabels := self menuItemLabels.

    self assert: expectedMenuItemLabels = actualMenuItemLabels

    "Created: / 04-01-2015 / 15:41:45 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_place_menu_item_after_menu_item_labeled_for_menu_item_found
    | menuItem expectedMenuItemLabels actualMenuItemLabels |

    menuItem := MenuItem label: 'SomeLabel'.

    expectedMenuItemLabels := {'Label_01'. 'Label_02'. 'SomeLabel'. 'Label_03'}.

    builder placeMenuItem: menuItem afterMenuItemLabeled: 'Label_02' forMenu: menu.

    actualMenuItemLabels := self menuItemLabels.

    self assert: expectedMenuItemLabels = actualMenuItemLabels

    "Modified: / 28-12-2014 / 10:41:43 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
!

test_place_menu_item_after_menu_item_labeled_for_menu_item_not_found
    | menuItem expectedMenuItemLabels actualMenuItemLabels |

    menuItem := MenuItem label: 'SomeLabel'.

    expectedMenuItemLabels := {'Label_01'. 'Label_02'. 'Label_03'. 'SomeLabel'}.

    builder placeMenuItem: menuItem afterMenuItemLabeled: 'NotExistingLabel' forMenu: menu.

    actualMenuItemLabels := self menuItemLabels.

    self assert: expectedMenuItemLabels = actualMenuItemLabels

    "Created: / 28-12-2014 / 10:45:14 / Jakub Nesveda <nesvejak@fit.cvut.cz>"
! !

!CustomMenuBuilderTests class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
! !