Browse Source

Merge pull request #975 from rcsimm/helios-sunit

Helios sunit
Nicolas Petton 11 years ago
parent
commit
4144991af0

+ 284 - 0
src/Helios-Commands-SUnit.js

@@ -3,6 +3,7 @@ smalltalk.addPackage('Helios-Commands-SUnit');
 smalltalk.packages["Helios-Commands-SUnit"].transport = {"type":"amd","amdNamespace":"helios"};
 
 smalltalk.addClass('HLSUnitCommand', globals.HLToolCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitCommand.comment="I group the commands pertaining to Helios-SUnit (`HLSUnitModel`)";
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -24,7 +25,205 @@ referencedClasses: ["HLSUnitModel"]
 globals.HLSUnitCommand.klass);
 
 
+smalltalk.addClass('HLSUnitInvertSelectedCommand', globals.HLSUnitCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitInvertSelectedCommand.comment="I group the commands that invert selections";
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "i";
+},
+args: [],
+source: "key\x0a\x09^ 'i'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Invert selection";
+},
+args: [],
+source: "label\x0a\x09^'Invert selection'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedCommand.klass);
+
+
+smalltalk.addClass('HLSUnitInvertSelectedClassesCommand', globals.HLSUnitInvertSelectedCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitInvertSelectedClassesCommand.comment="Invert the currently selected classes on a `HLSUnitModel`";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "category",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Classes";
+},
+args: [],
+source: "category\x0a\x09^'Classes'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+protocol: 'executing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._invertSelectedClasses();
+return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLSUnitInvertSelectedClassesCommand)})},
+args: [],
+source: "execute\x0a\x09self model invertSelectedClasses",
+messageSends: ["invertSelectedClasses", "model"],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isActive",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(self["@model"])._selectedPackages())._notEmpty();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isActive",{},globals.HLSUnitInvertSelectedClassesCommand)})},
+args: [],
+source: "isActive\x0a\x09^model selectedPackages notEmpty",
+messageSends: ["notEmpty", "selectedPackages"],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "c";
+},
+args: [],
+source: "key\x0a\x09^ 'c'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Invert selected classes";
+},
+args: [],
+source: "label\x0a\x09^ 'Invert selected classes'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand.klass);
+
+
+smalltalk.addClass('HLSUnitInvertSelectedPackagesCommand', globals.HLSUnitInvertSelectedCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitInvertSelectedPackagesCommand.comment="Invert the currently selected packages on a `HLSUnitModel`";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "category",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Packages";
+},
+args: [],
+source: "category\x0a\x09^'Packages'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+protocol: 'executing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._invertSelectedPackages();
+return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLSUnitInvertSelectedPackagesCommand)})},
+args: [],
+source: "execute\x0a\x09self model invertSelectedPackages",
+messageSends: ["invertSelectedPackages", "model"],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isActive",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return true;
+},
+args: [],
+source: "isActive\x0a\x09^true",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "p";
+},
+args: [],
+source: "key\x0a\x09^ 'p'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Invert selected packages";
+},
+args: [],
+source: "label\x0a\x09^ 'Invert selected packages'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand.klass);
+
+
 smalltalk.addClass('HLSUnitRunTests', globals.HLSUnitCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitRunTests.comment="Run the test cases in the currently selected classes on a `HLSUnitModel`";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "execute",
@@ -89,6 +288,7 @@ globals.HLSUnitRunTests.klass);
 
 
 smalltalk.addClass('HLSUnitSelectAllCommand', globals.HLSUnitCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitSelectAllCommand.comment="I group the select all commands";
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -121,7 +321,91 @@ referencedClasses: []
 globals.HLSUnitSelectAllCommand.klass);
 
 
+smalltalk.addClass('HLSUnitSelectAllClassesCommand', globals.HLSUnitSelectAllCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitSelectAllClassesCommand.comment="Select all available test classes based on what packages are selected on a `HLSUnitModel`";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "category",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Classes";
+},
+args: [],
+source: "category\x0a\x09^'Classes'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+protocol: 'executing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._selectAllClasses();
+return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLSUnitSelectAllClassesCommand)})},
+args: [],
+source: "execute\x0a\x09self model selectAllClasses",
+messageSends: ["selectAllClasses", "model"],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isActive",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(self["@model"])._selectedPackages())._notEmpty();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isActive",{},globals.HLSUnitSelectAllClassesCommand)})},
+args: [],
+source: "isActive\x0a\x09^model selectedPackages notEmpty",
+messageSends: ["notEmpty", "selectedPackages"],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "c";
+},
+args: [],
+source: "key\x0a\x09^ 'c'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Select all classes";
+},
+args: [],
+source: "label\x0a\x09^ 'Select all classes'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand.klass);
+
+
 smalltalk.addClass('HLSUnitSelectAllPackagesCommand', globals.HLSUnitSelectAllCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitSelectAllPackagesCommand.comment="Select all packages with test cases on a `HLSUnitModel`";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "category",

+ 126 - 0
src/Helios-Commands-SUnit.st

@@ -2,6 +2,8 @@ Smalltalk createPackage: 'Helios-Commands-SUnit'!
 HLToolCommand subclass: #HLSUnitCommand
 	instanceVariableNames: ''
 	package: 'Helios-Commands-SUnit'!
+!HLSUnitCommand commentStamp!
+I group the commands pertaining to Helios-SUnit (`HLSUnitModel`)!
 
 !HLSUnitCommand class methodsFor: 'testing'!
 
@@ -9,9 +11,95 @@ isValidFor: aModel
 	^ aModel isKindOf: HLSUnitModel
 ! !
 
+HLSUnitCommand subclass: #HLSUnitInvertSelectedCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-SUnit'!
+!HLSUnitInvertSelectedCommand commentStamp!
+I group the commands that invert selections!
+
+!HLSUnitInvertSelectedCommand class methodsFor: 'accessing'!
+
+key
+	^ 'i'
+!
+
+label
+	^'Invert selection'
+! !
+
+HLSUnitInvertSelectedCommand subclass: #HLSUnitInvertSelectedClassesCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-SUnit'!
+!HLSUnitInvertSelectedClassesCommand commentStamp!
+Invert the currently selected classes on a `HLSUnitModel`!
+
+!HLSUnitInvertSelectedClassesCommand methodsFor: 'accessing'!
+
+category
+	^'Classes'
+! !
+
+!HLSUnitInvertSelectedClassesCommand methodsFor: 'executing'!
+
+execute
+	self model invertSelectedClasses
+! !
+
+!HLSUnitInvertSelectedClassesCommand methodsFor: 'testing'!
+
+isActive
+	^model selectedPackages notEmpty
+! !
+
+!HLSUnitInvertSelectedClassesCommand class methodsFor: 'accessing'!
+
+key
+	^ 'c'
+!
+
+label
+	^ 'Invert selected classes'
+! !
+
+HLSUnitInvertSelectedCommand subclass: #HLSUnitInvertSelectedPackagesCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-SUnit'!
+!HLSUnitInvertSelectedPackagesCommand commentStamp!
+Invert the currently selected packages on a `HLSUnitModel`!
+
+!HLSUnitInvertSelectedPackagesCommand methodsFor: 'accessing'!
+
+category
+	^'Packages'
+! !
+
+!HLSUnitInvertSelectedPackagesCommand methodsFor: 'executing'!
+
+execute
+	self model invertSelectedPackages
+! !
+
+!HLSUnitInvertSelectedPackagesCommand methodsFor: 'testing'!
+
+isActive
+	^true
+! !
+
+!HLSUnitInvertSelectedPackagesCommand class methodsFor: 'accessing'!
+
+key
+	^ 'p'
+!
+
+label
+	^ 'Invert selected packages'
+! !
+
 HLSUnitCommand subclass: #HLSUnitRunTests
 	instanceVariableNames: ''
 	package: 'Helios-Commands-SUnit'!
+!HLSUnitRunTests commentStamp!
+Run the test cases in the currently selected classes on a `HLSUnitModel`!
 
 !HLSUnitRunTests methodsFor: 'executing'!
 
@@ -38,6 +126,8 @@ label
 HLSUnitCommand subclass: #HLSUnitSelectAllCommand
 	instanceVariableNames: ''
 	package: 'Helios-Commands-SUnit'!
+!HLSUnitSelectAllCommand commentStamp!
+I group the select all commands!
 
 !HLSUnitSelectAllCommand class methodsFor: 'accessing'!
 
@@ -49,9 +139,45 @@ label
 	^ 'Select all'
 ! !
 
+HLSUnitSelectAllCommand subclass: #HLSUnitSelectAllClassesCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-SUnit'!
+!HLSUnitSelectAllClassesCommand commentStamp!
+Select all available test classes based on what packages are selected on a `HLSUnitModel`!
+
+!HLSUnitSelectAllClassesCommand methodsFor: 'accessing'!
+
+category
+	^'Classes'
+! !
+
+!HLSUnitSelectAllClassesCommand methodsFor: 'executing'!
+
+execute
+	self model selectAllClasses
+! !
+
+!HLSUnitSelectAllClassesCommand methodsFor: 'testing'!
+
+isActive
+	^model selectedPackages notEmpty
+! !
+
+!HLSUnitSelectAllClassesCommand class methodsFor: 'accessing'!
+
+key
+	^ 'c'
+!
+
+label
+	^ 'Select all classes'
+! !
+
 HLSUnitSelectAllCommand subclass: #HLSUnitSelectAllPackagesCommand
 	instanceVariableNames: ''
 	package: 'Helios-Commands-SUnit'!
+!HLSUnitSelectAllPackagesCommand commentStamp!
+Select all packages with test cases on a `HLSUnitModel`!
 
 !HLSUnitSelectAllPackagesCommand methodsFor: 'accessing'!
 

+ 109 - 0
src/Helios-SUnit-Tests.js

@@ -3,6 +3,7 @@ smalltalk.addPackage('Helios-SUnit-Tests');
 smalltalk.packages["Helios-SUnit-Tests"].transport = {"type":"amd","amdNamespace":"helios"};
 
 smalltalk.addClass('HLSUnitModelTest', globals.TestCase, ['model'], 'Helios-SUnit-Tests');
+globals.HLSUnitModelTest.comment="Test cases for the functionality of  `HLSUnitModel`";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "setUp",
@@ -62,6 +63,114 @@ referencedClasses: ["TestResult"]
 }),
 globals.HLSUnitModelTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInvertSelectedClasses",
+protocol: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$4,$3,$6,$5,$8,$7,$10,$9;
+_st(self["@model"])._selectAllPackages();
+_st(self["@model"])._selectAllClasses();
+$1=self["@model"];
+$2=self._class();
+$ctx1.sendIdx["class"]=1;
+_st($1)._unselectClass_($2);
+$4=_st(self["@model"])._selectedClasses();
+$ctx1.sendIdx["selectedClasses"]=1;
+$3=_st($4)._notEmpty();
+self._assert_($3);
+$6=_st(self["@model"])._selectedClasses();
+$ctx1.sendIdx["selectedClasses"]=2;
+$5=_st($6)._size();
+$ctx1.sendIdx["size"]=1;
+$8=_st(_st(self["@model"])._testClasses())._size();
+$ctx1.sendIdx["size"]=2;
+$7=_st($8).__minus((1));
+self._assert_equals_($5,$7);
+$ctx1.sendIdx["assert:equals:"]=1;
+_st(self["@model"])._invertSelectedClasses();
+$10=_st(self["@model"])._selectedClasses();
+$ctx1.sendIdx["selectedClasses"]=3;
+$9=_st($10)._size();
+self._assert_equals_($9,(1));
+$ctx1.sendIdx["assert:equals:"]=2;
+self._assert_equals_(_st(_st(self["@model"])._selectedClasses())._anyOne(),self._class());
+return self}, function($ctx1) {$ctx1.fill(self,"testInvertSelectedClasses",{},globals.HLSUnitModelTest)})},
+args: [],
+source: "testInvertSelectedClasses\x0a\x09model selectAllPackages.\x0a\x09model selectAllClasses.\x0a\x09model unselectClass: self class.\x0a\x09self assert: model selectedClasses notEmpty.\x0a\x09self assert: model selectedClasses size equals: model testClasses size - 1.\x0a\x09model invertSelectedClasses.\x0a\x09self assert: model selectedClasses size equals: 1.\x0a\x09self assert: model selectedClasses anyOne equals: self class.",
+messageSends: ["selectAllPackages", "selectAllClasses", "unselectClass:", "class", "assert:", "notEmpty", "selectedClasses", "assert:equals:", "size", "-", "testClasses", "invertSelectedClasses", "anyOne"],
+referencedClasses: []
+}),
+globals.HLSUnitModelTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInvertSelectedPackages",
+protocol: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$4,$3,$6,$5,$8,$7,$10,$9;
+_st(self["@model"])._selectAllPackages();
+$1=self["@model"];
+$2=self._thisPackage();
+$ctx1.sendIdx["thisPackage"]=1;
+_st($1)._unselectPackage_($2);
+$4=_st(self["@model"])._selectedPackages();
+$ctx1.sendIdx["selectedPackages"]=1;
+$3=_st($4)._notEmpty();
+self._assert_($3);
+$6=_st(self["@model"])._selectedPackages();
+$ctx1.sendIdx["selectedPackages"]=2;
+$5=_st($6)._size();
+$ctx1.sendIdx["size"]=1;
+$8=_st(_st(self["@model"])._testPackages())._size();
+$ctx1.sendIdx["size"]=2;
+$7=_st($8).__minus((1));
+self._assert_equals_($5,$7);
+$ctx1.sendIdx["assert:equals:"]=1;
+_st(self["@model"])._invertSelectedPackages();
+$10=_st(self["@model"])._selectedPackages();
+$ctx1.sendIdx["selectedPackages"]=3;
+$9=_st($10)._size();
+self._assert_equals_($9,(1));
+$ctx1.sendIdx["assert:equals:"]=2;
+self._assert_equals_(_st(_st(self["@model"])._selectedPackages())._anyOne(),self._thisPackage());
+return self}, function($ctx1) {$ctx1.fill(self,"testInvertSelectedPackages",{},globals.HLSUnitModelTest)})},
+args: [],
+source: "testInvertSelectedPackages\x0a\x09model selectAllPackages.\x0a\x09model unselectPackage: self thisPackage.\x0a\x09self assert: model selectedPackages notEmpty.\x0a\x09self assert: model selectedPackages size equals: model testPackages size - 1.\x0a\x09model invertSelectedPackages.\x0a\x09self assert: model selectedPackages size equals: 1.\x0a\x09self assert: model selectedPackages anyOne equals: self thisPackage.",
+messageSends: ["selectAllPackages", "unselectPackage:", "thisPackage", "assert:", "notEmpty", "selectedPackages", "assert:equals:", "size", "-", "testPackages", "invertSelectedPackages", "anyOne"],
+referencedClasses: []
+}),
+globals.HLSUnitModelTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testSelectAllClasses",
+protocol: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$3;
+_st(self["@model"])._selectAllPackages();
+$2=_st(self["@model"])._testClasses();
+$ctx1.sendIdx["testClasses"]=1;
+$1=_st($2)._notEmpty();
+self._assert_($1);
+_st(self["@model"])._selectAllClasses();
+$3=_st(_st(self["@model"])._selectedClasses())._size();
+$ctx1.sendIdx["size"]=1;
+self._assert_equals_($3,_st(_st(self["@model"])._testClasses())._size());
+return self}, function($ctx1) {$ctx1.fill(self,"testSelectAllClasses",{},globals.HLSUnitModelTest)})},
+args: [],
+source: "testSelectAllClasses\x0a\x09model selectAllPackages.\x0a\x09self assert: model testClasses notEmpty.\x0a\x09model selectAllClasses.\x0a\x09self assert: model selectedClasses size equals: model testClasses size",
+messageSends: ["selectAllPackages", "assert:", "notEmpty", "testClasses", "selectAllClasses", "assert:equals:", "size", "selectedClasses"],
+referencedClasses: []
+}),
+globals.HLSUnitModelTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testSelectAllPackages",

+ 30 - 0
src/Helios-SUnit-Tests.st

@@ -2,6 +2,8 @@ Smalltalk createPackage: 'Helios-SUnit-Tests'!
 TestCase subclass: #HLSUnitModelTest
 	instanceVariableNames: 'model'
 	package: 'Helios-SUnit-Tests'!
+!HLSUnitModelTest commentStamp!
+Test cases for the functionality of  `HLSUnitModel`!
 
 !HLSUnitModelTest methodsFor: 'accessing'!
 
@@ -28,6 +30,34 @@ testEmptyTestResults
 	self assert: (model testResult isKindOf: TestResult)
 !
 
+testInvertSelectedClasses
+	model selectAllPackages.
+	model selectAllClasses.
+	model unselectClass: self class.
+	self assert: model selectedClasses notEmpty.
+	self assert: model selectedClasses size equals: model testClasses size - 1.
+	model invertSelectedClasses.
+	self assert: model selectedClasses size equals: 1.
+	self assert: model selectedClasses anyOne equals: self class.
+!
+
+testInvertSelectedPackages
+	model selectAllPackages.
+	model unselectPackage: self thisPackage.
+	self assert: model selectedPackages notEmpty.
+	self assert: model selectedPackages size equals: model testPackages size - 1.
+	model invertSelectedPackages.
+	self assert: model selectedPackages size equals: 1.
+	self assert: model selectedPackages anyOne equals: self thisPackage.
+!
+
+testSelectAllClasses
+	model selectAllPackages.
+	self assert: model testClasses notEmpty.
+	model selectAllClasses.
+	self assert: model selectedClasses size equals: model testClasses size
+!
+
 testSelectAllPackages
 	self assert: model selectedPackages isEmpty.
 	model selectAllPackages.

+ 253 - 59
src/Helios-SUnit.js

@@ -296,24 +296,65 @@ $ctx1.sendIdx["on:send:to:"]=3;
 $2=_st($1)._on_send_to_($HLClassUnselected(),"onClassUnselected:",self);
 return self}, function($ctx1) {$ctx1.fill(self,"observeModel",{},globals.HLSUnitClassesListWidget)})},
 args: [],
-source: "observeModel\x0a    self model announcer \x0a\x09\x09on: HLPackageSelected\x0a\x09\x09send: #onPackageSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLPackageUnselected\x0a\x09\x09send: #onPackageUnselected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLClassSelected\x0a\x09\x09send: #onClassSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLClassUnselected\x0a\x09\x09send: #onClassUnselected:\x0a\x09\x09to: self",
+source: "observeModel\x0a    self model announcer \x0a\x09\x09on: HLPackageSelected\x0a\x09\x09send: #onPackageSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLPackageUnselected\x0a\x09\x09send: #onPackageUnselected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLClassSelected\x0a\x09\x09send: #onClassSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLClassUnselected\x0a\x09\x09send: #onClassUnselected:\x0a\x09\x09to: self.",
 messageSends: ["on:send:to:", "announcer", "model"],
 referencedClasses: ["HLPackageSelected", "HLPackageUnselected", "HLClassSelected", "HLClassUnselected"]
 }),
 globals.HLSUnitClassesListWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "observeSystem",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $ClassAdded(){return globals.ClassAdded||(typeof ClassAdded=="undefined"?nil:ClassAdded)}
+return smalltalk.withContext(function($ctx1) { 
+_st(_st(self._model())._systemAnnouncer())._on_send_to_($ClassAdded(),"onClassAdded:",self);
+return self}, function($ctx1) {$ctx1.fill(self,"observeSystem",{},globals.HLSUnitClassesListWidget)})},
+args: [],
+source: "observeSystem\x0a    self model systemAnnouncer \x0a\x09\x09on: ClassAdded \x0a\x09\x09send: #onClassAdded:\x0a\x09\x09to: self.",
+messageSends: ["on:send:to:", "systemAnnouncer", "model"],
+referencedClasses: ["ClassAdded"]
+}),
+globals.HLSUnitClassesListWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onClassAdded:",
+protocol: 'reactions',
+fn: function (anAnnouncement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st(_st(self._model())._selectedPackages())._includes_(_st(_st(anAnnouncement)._theClass())._package());
+if(smalltalk.assert($1)){
+self._initializeItems();
+$2=self._refresh();
+$2;
+};
+return self}, function($ctx1) {$ctx1.fill(self,"onClassAdded:",{anAnnouncement:anAnnouncement},globals.HLSUnitClassesListWidget)})},
+args: ["anAnnouncement"],
+source: "onClassAdded: anAnnouncement\x09\x0a\x09(self model selectedPackages includes: anAnnouncement theClass package)\x0a\x09\x09ifTrue: [ \x0a\x09\x09\x09self \x0a\x09\x09\x09\x09initializeItems;\x0a\x09\x09\x09\x09refresh ]",
+messageSends: ["ifTrue:", "includes:", "selectedPackages", "model", "package", "theClass", "initializeItems", "refresh"],
+referencedClasses: []
+}),
+globals.HLSUnitClassesListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "onClassSelected:",
 protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
+var listItem;
 return smalltalk.withContext(function($ctx1) { 
-self._refresh();
-return self}, function($ctx1) {$ctx1.fill(self,"onClassSelected:",{anAnnouncement:anAnnouncement},globals.HLSUnitClassesListWidget)})},
+listItem=self._findListItemFor_(_st(anAnnouncement)._item());
+_st(listItem)._addClass_("active");
+return self}, function($ctx1) {$ctx1.fill(self,"onClassSelected:",{anAnnouncement:anAnnouncement,listItem:listItem},globals.HLSUnitClassesListWidget)})},
 args: ["anAnnouncement"],
-source: "onClassSelected: anAnnouncement\x0a\x09self refresh",
-messageSends: ["refresh"],
+source: "onClassSelected: anAnnouncement\x0a\x09| listItem |\x0a\x09listItem := self findListItemFor: anAnnouncement item.\x0a\x09listItem addClass: 'active'.",
+messageSends: ["findListItemFor:", "item", "addClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitClassesListWidget);
@@ -324,12 +365,14 @@ selector: "onClassUnselected:",
 protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
+var listItem;
 return smalltalk.withContext(function($ctx1) { 
-self._refresh();
-return self}, function($ctx1) {$ctx1.fill(self,"onClassUnselected:",{anAnnouncement:anAnnouncement},globals.HLSUnitClassesListWidget)})},
+listItem=self._findListItemFor_(_st(anAnnouncement)._item());
+_st(listItem)._removeClass_("active");
+return self}, function($ctx1) {$ctx1.fill(self,"onClassUnselected:",{anAnnouncement:anAnnouncement,listItem:listItem},globals.HLSUnitClassesListWidget)})},
 args: ["anAnnouncement"],
-source: "onClassUnselected: anAnnouncement\x0a\x09self refresh",
-messageSends: ["refresh"],
+source: "onClassUnselected: anAnnouncement\x0a\x09| listItem |\x0a\x09listItem := self findListItemFor: anAnnouncement item.\x0a\x09listItem removeClass: 'active'.",
+messageSends: ["findListItemFor:", "item", "removeClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitClassesListWidget);
@@ -547,18 +590,69 @@ referencedClasses: ["HLPackageSelected", "HLPackageUnselected"]
 }),
 globals.HLSUnitPackagesListWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "observeSystem",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $ClassAdded(){return globals.ClassAdded||(typeof ClassAdded=="undefined"?nil:ClassAdded)}
+return smalltalk.withContext(function($ctx1) { 
+_st(_st(self._model())._systemAnnouncer())._on_send_to_($ClassAdded(),"onClassAdded:",self);
+return self}, function($ctx1) {$ctx1.fill(self,"observeSystem",{},globals.HLSUnitPackagesListWidget)})},
+args: [],
+source: "observeSystem\x0a    self model systemAnnouncer \x0a\x09\x09on: ClassAdded \x0a\x09\x09send: #onClassAdded:\x0a\x09\x09to: self.",
+messageSends: ["on:send:to:", "systemAnnouncer", "model"],
+referencedClasses: ["ClassAdded"]
+}),
+globals.HLSUnitPackagesListWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onClassAdded:",
+protocol: 'reactions',
+fn: function (anAnnouncement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $4,$6,$5,$3,$2,$1,$7;
+$4=self._items();
+$6=_st(anAnnouncement)._theClass();
+$ctx1.sendIdx["theClass"]=1;
+$5=_st($6)._package();
+$ctx1.sendIdx["package"]=1;
+$3=_st($4)._includes_($5);
+$2=_st($3)._not();
+$1=_st($2)._and_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(_st(anAnnouncement)._theClass())._package())._isTestPackage();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+if(smalltalk.assert($1)){
+self._initializeItems();
+$7=self._refresh();
+$7;
+};
+return self}, function($ctx1) {$ctx1.fill(self,"onClassAdded:",{anAnnouncement:anAnnouncement},globals.HLSUnitPackagesListWidget)})},
+args: ["anAnnouncement"],
+source: "onClassAdded: anAnnouncement\x0a\x09((self items includes: anAnnouncement theClass package) not and: [anAnnouncement theClass package isTestPackage])\x0a\x09\x09ifTrue: [ \x0a\x09\x09\x09self \x0a\x09\x09\x09\x09initializeItems;\x0a\x09\x09\x09\x09refresh ]",
+messageSends: ["ifTrue:", "and:", "not", "includes:", "items", "package", "theClass", "isTestPackage", "initializeItems", "refresh"],
+referencedClasses: []
+}),
+globals.HLSUnitPackagesListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "onPackageSelected:",
 protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
+var listItem;
 return smalltalk.withContext(function($ctx1) { 
-self._refresh();
-return self}, function($ctx1) {$ctx1.fill(self,"onPackageSelected:",{anAnnouncement:anAnnouncement},globals.HLSUnitPackagesListWidget)})},
+listItem=self._findListItemFor_(_st(anAnnouncement)._item());
+_st(listItem)._addClass_("active");
+return self}, function($ctx1) {$ctx1.fill(self,"onPackageSelected:",{anAnnouncement:anAnnouncement,listItem:listItem},globals.HLSUnitPackagesListWidget)})},
 args: ["anAnnouncement"],
-source: "onPackageSelected: anAnnouncement\x0a\x09self refresh",
-messageSends: ["refresh"],
+source: "onPackageSelected: anAnnouncement\x0a\x09| listItem |\x0a\x09listItem := self findListItemFor: anAnnouncement item.\x0a\x09listItem addClass: 'active'.\x0a\x09",
+messageSends: ["findListItemFor:", "item", "addClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitPackagesListWidget);
@@ -569,12 +663,14 @@ selector: "onPackageUnselected:",
 protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
+var listItem;
 return smalltalk.withContext(function($ctx1) { 
-self._refresh();
-return self}, function($ctx1) {$ctx1.fill(self,"onPackageUnselected:",{anAnnouncement:anAnnouncement},globals.HLSUnitPackagesListWidget)})},
+listItem=self._findListItemFor_(_st(anAnnouncement)._item());
+_st(listItem)._removeClass_("active");
+return self}, function($ctx1) {$ctx1.fill(self,"onPackageUnselected:",{anAnnouncement:anAnnouncement,listItem:listItem},globals.HLSUnitPackagesListWidget)})},
 args: ["anAnnouncement"],
-source: "onPackageUnselected: anAnnouncement\x0a\x09self refresh",
-messageSends: ["refresh"],
+source: "onPackageUnselected: anAnnouncement\x0a\x09| listItem |\x0a\x09listItem := self findListItemFor: anAnnouncement item.\x0a\x09listItem removeClass: 'active'.",
+messageSends: ["findListItemFor:", "item", "removeClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitPackagesListWidget);
@@ -804,28 +900,51 @@ selector: "renderContentOn:",
 protocol: 'rendering',
 fn: function (html){
 var self=this;
+var resultSection;
 function $HLContainer(){return globals.HLContainer||(typeof HLContainer=="undefined"?nil:HLContainer)}
 function $HLVerticalSplitter(){return globals.HLVerticalSplitter||(typeof HLVerticalSplitter=="undefined"?nil:HLVerticalSplitter)}
-function $HLHorizontalSplitter(){return globals.HLHorizontalSplitter||(typeof HLHorizontalSplitter=="undefined"?nil:HLHorizontalSplitter)}
 return smalltalk.withContext(function($ctx1) { 
 var $4,$3,$5,$2,$1;
 $4=self._packagesListWidget();
 $ctx1.sendIdx["packagesListWidget"]=1;
 $3=_st($HLVerticalSplitter())._with_with_($4,self._classesListWidget());
-$ctx1.sendIdx["with:with:"]=2;
-$5=_st($HLHorizontalSplitter())._with_with_(self._resultWidget(),_st($HLHorizontalSplitter())._with_with_(self._failuresWidget(),self._errorsWidget()));
-$ctx1.sendIdx["with:with:"]=3;
+resultSection=self._resultSection();
+$5=resultSection;
 $2=_st($HLVerticalSplitter())._with_with_($3,$5);
 $ctx1.sendIdx["with:with:"]=1;
 $1=_st($HLContainer())._with_($2);
 _st(html)._with_($1);
 $ctx1.sendIdx["with:"]=1;
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(resultSection)._resize_((0));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._valueWithTimeout_((100));
 _st(self._packagesListWidget())._focus();
-return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html},globals.HLSUnit)})},
+return self}, function($ctx1) {$ctx1.fill(self,"renderContentOn:",{html:html,resultSection:resultSection},globals.HLSUnit)})},
 args: ["html"],
-source: "renderContentOn: html\x0a\x09html with: (HLContainer with:  (\x0a\x09\x09HLVerticalSplitter \x0a\x09\x09\x09with: (HLVerticalSplitter\x0a\x09\x09\x09\x09with: self packagesListWidget \x0a        \x09\x09with: self classesListWidget)\x0a\x09\x09\x09with: (HLHorizontalSplitter \x0a\x09\x09\x09\x09with: self resultWidget\x0a\x09\x09\x09\x09with: (HLHorizontalSplitter \x0a\x09\x09\x09\x09\x09with: self failuresWidget\x0a\x09\x09\x09\x09\x09with: self errorsWidget)))).\x0a\x09\x0a\x09self packagesListWidget focus",
-messageSends: ["with:", "with:with:", "packagesListWidget", "classesListWidget", "resultWidget", "failuresWidget", "errorsWidget", "focus"],
-referencedClasses: ["HLContainer", "HLVerticalSplitter", "HLHorizontalSplitter"]
+source: "renderContentOn: html\x0a\x09| resultSection |\x0a\x09html with: (HLContainer with:  (\x0a\x09\x09HLVerticalSplitter \x0a\x09\x09\x09with: (HLVerticalSplitter\x0a\x09\x09\x09\x09with: self packagesListWidget \x0a        \x09\x09with: self classesListWidget)\x0a\x09\x09\x09with: (resultSection := self resultSection))).\x0a\x09\x0a\x09[resultSection resize: 0] valueWithTimeout: 100.\x0a\x09\x0a\x09self packagesListWidget focus",
+messageSends: ["with:", "with:with:", "packagesListWidget", "classesListWidget", "resultSection", "valueWithTimeout:", "resize:", "focus"],
+referencedClasses: ["HLContainer", "HLVerticalSplitter"]
+}),
+globals.HLSUnit);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "resultSection",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+function $HLHorizontalSplitter(){return globals.HLHorizontalSplitter||(typeof HLHorizontalSplitter=="undefined"?nil:HLHorizontalSplitter)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($HLHorizontalSplitter())._with_with_(self._resultWidget(),_st($HLHorizontalSplitter())._with_with_(self._failuresWidget(),self._errorsWidget()));
+$ctx1.sendIdx["with:with:"]=1;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"resultSection",{},globals.HLSUnit)})},
+args: [],
+source: "resultSection\x0a\x09^HLHorizontalSplitter \x0a\x09\x09with: self resultWidget\x0a\x09\x09with: (HLHorizontalSplitter \x0a\x09\x09\x09with: self failuresWidget\x0a\x09\x09\x09with: self errorsWidget)",
+messageSends: ["with:with:", "resultWidget", "failuresWidget", "errorsWidget"],
+referencedClasses: ["HLHorizontalSplitter"]
 }),
 globals.HLSUnit);
 
@@ -920,6 +1039,7 @@ globals.HLSUnit.klass);
 
 
 smalltalk.addClass('HLSUnitModel', globals.HLModel, ['selectedPackages', 'selectedClasses', 'testResult', 'currentSuite'], 'Helios-SUnit');
+globals.HLSUnitModel.comment="I am the model for running unit tests in Helios.\x0a\x0aI provide the ability to select set of tests to run per package, and a detailed result log with passed tests, failed tests and errors.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "currentSuite",
@@ -939,42 +1059,67 @@ globals.HLSUnitModel);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "onResultAnnouncement:",
-protocol: 'reacting',
-fn: function (announcement){
+selector: "invertSelectedClasses",
+protocol: 'actions',
+fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._announcer())._announce_(announcement);
-return self}, function($ctx1) {$ctx1.fill(self,"onResultAnnouncement:",{announcement:announcement},globals.HLSUnitModel)})},
-args: ["announcement"],
-source: "onResultAnnouncement: announcement\x0a\x09\x22Propogate announcement\x22\x0a\x09self announcer announce: announcement.",
-messageSends: ["announce:", "announcer"],
+var $1;
+_st(self._testClasses())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(self._unfilteredSelectedClasses())._includes_(each);
+if(smalltalk.assert($1)){
+return self._unselectClass_(each);
+} else {
+return self._selectClass_(each);
+};
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"invertSelectedClasses",{},globals.HLSUnitModel)})},
+args: [],
+source: "invertSelectedClasses\x0a\x09self testClasses do: [:each | \x0a\x09\x09(self unfilteredSelectedClasses includes: each)\x0a\x09\x09\x09ifTrue: [ self unselectClass: each ]\x0a\x09\x09\x09ifFalse: [ self selectClass: each ]].\x0a\x09",
+messageSends: ["do:", "testClasses", "ifTrue:ifFalse:", "includes:", "unfilteredSelectedClasses", "unselectClass:", "selectClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitModel);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "privateSelectedClasses",
-protocol: 'private',
+selector: "invertSelectedPackages",
+protocol: 'actions',
 fn: function (){
 var self=this;
-function $Set(){return globals.Set||(typeof Set=="undefined"?nil:Set)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1,$receiver;
-$2=self["@selectedClasses"];
-if(($receiver = $2) == null || $receiver.isNil){
-self["@selectedClasses"]=_st($Set())._new();
-$1=self["@selectedClasses"];
+var $1;
+_st(self._testPackages())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(self._selectedPackages())._includes_(each);
+if(smalltalk.assert($1)){
+return self._unselectPackage_(each);
 } else {
-$1=$2;
+return self._selectPackage_(each);
 };
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"privateSelectedClasses",{},globals.HLSUnitModel)})},
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"invertSelectedPackages",{},globals.HLSUnitModel)})},
 args: [],
-source: "privateSelectedClasses\x0a\x09^ (selectedClasses ifNil: [ selectedClasses := Set new ])",
-messageSends: ["ifNil:", "new"],
-referencedClasses: ["Set"]
+source: "invertSelectedPackages\x0a\x09self testPackages do: [:each | \x0a\x09\x09(self selectedPackages includes: each)\x0a\x09\x09\x09ifTrue: [ self unselectPackage: each ]\x0a\x09\x09\x09ifFalse: [ self selectPackage: each ]].\x0a\x09",
+messageSends: ["do:", "testPackages", "ifTrue:ifFalse:", "includes:", "selectedPackages", "unselectPackage:", "selectPackage:"],
+referencedClasses: []
+}),
+globals.HLSUnitModel);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onResultAnnouncement:",
+protocol: 'reacting',
+fn: function (announcement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._announcer())._announce_(announcement);
+return self}, function($ctx1) {$ctx1.fill(self,"onResultAnnouncement:",{announcement:announcement},globals.HLSUnitModel)})},
+args: ["announcement"],
+source: "onResultAnnouncement: announcement\x0a\x09\x22Propogate announcement\x22\x0a\x09self announcer announce: announcement.",
+messageSends: ["announce:", "announcer"],
+referencedClasses: []
 }),
 globals.HLSUnitModel);
 
@@ -1002,6 +1147,25 @@ referencedClasses: ["TestSuiteRunner", "HLRunTests"]
 }),
 globals.HLSUnitModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "selectAllClasses",
+protocol: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._testClasses())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return self._selectClass_(each);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"selectAllClasses",{},globals.HLSUnitModel)})},
+args: [],
+source: "selectAllClasses\x0a\x09self testClasses do: [:each | self selectClass: each].\x0a\x09",
+messageSends: ["do:", "testClasses", "selectClass:"],
+referencedClasses: []
+}),
+globals.HLSUnitModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "selectAllPackages",
@@ -1015,7 +1179,7 @@ return self._selectPackage_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectAllPackages",{},globals.HLSUnitModel)})},
 args: [],
-source: "selectAllPackages\x0a\x09self testPackages do: [:each | self selectPackage: each]",
+source: "selectAllPackages\x0a\x09self testPackages do: [:each | self selectPackage: each].",
 messageSends: ["do:", "testPackages", "selectPackage:"],
 referencedClasses: []
 }),
@@ -1029,12 +1193,12 @@ fn: function (aClass){
 var self=this;
 function $HLClassSelected(){return globals.HLClassSelected||(typeof HLClassSelected=="undefined"?nil:HLClassSelected)}
 return smalltalk.withContext(function($ctx1) { 
-_st(self._privateSelectedClasses())._add_(aClass);
+_st(self._unfilteredSelectedClasses())._add_(aClass);
 _st(self._announcer())._announce_(_st($HLClassSelected())._on_(aClass));
 return self}, function($ctx1) {$ctx1.fill(self,"selectClass:",{aClass:aClass},globals.HLSUnitModel)})},
 args: ["aClass"],
-source: "selectClass: aClass\x0a\x09self privateSelectedClasses add: aClass.\x0a\x09self announcer announce: (HLClassSelected on: aClass).",
-messageSends: ["add:", "privateSelectedClasses", "announce:", "announcer", "on:"],
+source: "selectClass: aClass\x0a\x09self unfilteredSelectedClasses add: aClass.\x0a\x09self announcer announce: (HLClassSelected on: aClass).",
+messageSends: ["add:", "unfilteredSelectedClasses", "announce:", "announcer", "on:"],
 referencedClasses: ["HLClassSelected"]
 }),
 globals.HLSUnitModel);
@@ -1065,15 +1229,15 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(self._privateSelectedClasses())._select_((function(each){
+$1=_st(self._unfilteredSelectedClasses())._select_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return _st(self._selectedPackages())._includes_(_st(each)._package());
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"selectedClasses",{},globals.HLSUnitModel)})},
 args: [],
-source: "selectedClasses\x0a\x09^ (self privateSelectedClasses) select: [:each |\x0a\x09\x09self selectedPackages includes: each package]",
-messageSends: ["select:", "privateSelectedClasses", "includes:", "selectedPackages", "package"],
+source: "selectedClasses\x0a\x09^ (self unfilteredSelectedClasses) select: [:each |\x0a\x09\x09self selectedPackages includes: each package]",
+messageSends: ["select:", "unfilteredSelectedClasses", "includes:", "selectedPackages", "package"],
 referencedClasses: []
 }),
 globals.HLSUnitModel);
@@ -1232,6 +1396,31 @@ referencedClasses: ["TestResult"]
 }),
 globals.HLSUnitModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "unfilteredSelectedClasses",
+protocol: 'private',
+fn: function (){
+var self=this;
+function $Set(){return globals.Set||(typeof Set=="undefined"?nil:Set)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$receiver;
+$2=self["@selectedClasses"];
+if(($receiver = $2) == null || $receiver.isNil){
+self["@selectedClasses"]=_st($Set())._new();
+$1=self["@selectedClasses"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"unfilteredSelectedClasses",{},globals.HLSUnitModel)})},
+args: [],
+source: "unfilteredSelectedClasses\x0a\x09^ (selectedClasses ifNil: [ selectedClasses := Set new ])",
+messageSends: ["ifNil:", "new"],
+referencedClasses: ["Set"]
+}),
+globals.HLSUnitModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "unselectClass:",
@@ -1242,7 +1431,7 @@ function $HLClassUnselected(){return globals.HLClassUnselected||(typeof HLClassU
 return smalltalk.withContext(function($ctx1) { 
 var $early={};
 try {
-_st(self._privateSelectedClasses())._remove_ifAbsent_(aClass,(function(){
+_st(self._unfilteredSelectedClasses())._remove_ifAbsent_(aClass,(function(){
 throw $early=[self];
 }));
 _st(self._announcer())._announce_(_st($HLClassUnselected())._on_(aClass));
@@ -1250,8 +1439,8 @@ return self}
 catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"unselectClass:",{aClass:aClass},globals.HLSUnitModel)})},
 args: ["aClass"],
-source: "unselectClass: aClass\x0a\x09self privateSelectedClasses remove: aClass ifAbsent: [^self].\x0a\x09self announcer announce: (HLClassUnselected on: aClass).",
-messageSends: ["remove:ifAbsent:", "privateSelectedClasses", "announce:", "announcer", "on:"],
+source: "unselectClass: aClass\x0a\x09self unfilteredSelectedClasses remove: aClass ifAbsent: [^self].\x0a\x09self announcer announce: (HLClassUnselected on: aClass).",
+messageSends: ["remove:ifAbsent:", "unfilteredSelectedClasses", "announce:", "announcer", "on:"],
 referencedClasses: ["HLClassUnselected"]
 }),
 globals.HLSUnitModel);
@@ -1283,6 +1472,7 @@ globals.HLSUnitModel);
 
 
 smalltalk.addClass('HLSUnitResultListWidget', globals.HLToolListWidget, [], 'Helios-SUnit');
+globals.HLSUnitResultListWidget.comment="I group the lists that display test results";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "observeModel",
@@ -1370,6 +1560,7 @@ globals.HLSUnitResultListWidget);
 
 
 smalltalk.addClass('HLSUnitErrorsListWidget', globals.HLSUnitResultListWidget, [], 'Helios-SUnit');
+globals.HLSUnitErrorsListWidget.comment="I display a list of tests that have errors";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "items",
@@ -1406,10 +1597,11 @@ globals.HLSUnitErrorsListWidget);
 
 
 smalltalk.addClass('HLSUnitFailuresListWidget', globals.HLSUnitResultListWidget, [], 'Helios-SUnit');
+globals.HLSUnitFailuresListWidget.comment="I display a list of tests that have failures";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "items",
-protocol: 'as yet unclassified',
+protocol: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -1442,6 +1634,7 @@ globals.HLSUnitFailuresListWidget);
 
 
 smalltalk.addClass('HLSUnitResultStatus', globals.HLWidget, ['model'], 'Helios-SUnit');
+globals.HLSUnitResultStatus.comment="I display the status of the previous test run\x0a\x0a1. How many tests where run.\x0a* How many tests passed.\x0a* How many tests failed.\x0a* How many tests resulted in an error.\x0a";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "model",
@@ -1487,7 +1680,7 @@ globals.HLSUnitResultStatus);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "observeModel",
-protocol: 'initialization',
+protocol: 'actions',
 fn: function (){
 var self=this;
 function $ResultAnnouncement(){return globals.ResultAnnouncement||(typeof ResultAnnouncement=="undefined"?nil:ResultAnnouncement)}
@@ -1684,6 +1877,7 @@ globals.HLSUnitResultStatus);
 
 
 smalltalk.addClass('HLSUnitResults', globals.HLWidget, ['model', 'progressBarWidget', 'resultStatusWidget'], 'Helios-SUnit');
+globals.HLSUnitResults.comment="I am the widget that displays the test results for a previous test run in Helios.\x0a\x0aI display.\x0a\x0a1. The status of the tests.\x0a* Progress of the currently running test suite.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "model",

+ 107 - 22
src/Helios-SUnit.st

@@ -97,7 +97,14 @@ observeModel
 		
 		on: HLClassUnselected
 		send: #onClassUnselected:
-		to: self
+		to: self.
+!
+
+observeSystem
+    self model systemAnnouncer 
+		on: ClassAdded 
+		send: #onClassAdded:
+		to: self.
 !
 
 select: anObject
@@ -116,12 +123,24 @@ initializeItems
 
 !HLSUnitClassesListWidget methodsFor: 'reactions'!
 
+onClassAdded: anAnnouncement	
+	(self model selectedPackages includes: anAnnouncement theClass package)
+		ifTrue: [ 
+			self 
+				initializeItems;
+				refresh ]
+!
+
 onClassSelected: anAnnouncement
-	self refresh
+	| listItem |
+	listItem := self findListItemFor: anAnnouncement item.
+	listItem addClass: 'active'.
 !
 
 onClassUnselected: anAnnouncement
-	self refresh
+	| listItem |
+	listItem := self findListItemFor: anAnnouncement item.
+	listItem removeClass: 'active'.
 !
 
 onPackageSelected: anAnnouncement
@@ -181,6 +200,13 @@ observeModel
 		to: self
 !
 
+observeSystem
+    self model systemAnnouncer 
+		on: ClassAdded 
+		send: #onClassAdded:
+		to: self.
+!
+
 select: anObject
 	model selectPackage: anObject
 !
@@ -198,12 +224,24 @@ initializeItems
 
 !HLSUnitPackagesListWidget methodsFor: 'reactions'!
 
+onClassAdded: anAnnouncement
+	((self items includes: anAnnouncement theClass package) not and: [anAnnouncement theClass package isTestPackage])
+		ifTrue: [ 
+			self 
+				initializeItems;
+				refresh ]
+!
+
 onPackageSelected: anAnnouncement
-	self refresh
+	| listItem |
+	listItem := self findListItemFor: anAnnouncement item.
+	listItem addClass: 'active'.
 !
 
 onPackageUnselected: anAnnouncement
-	self refresh
+	| listItem |
+	listItem := self findListItemFor: anAnnouncement item.
+	listItem removeClass: 'active'.
 ! !
 
 !HLSUnitPackagesListWidget methodsFor: 'rendering'!
@@ -236,6 +274,14 @@ I provide the ability to select set of tests to run per package, and a detailed
 
 model
 	^ model ifNil: [ model := HLSUnitModel new ]
+!
+
+resultSection
+	^HLHorizontalSplitter 
+		with: self resultWidget
+		with: (HLHorizontalSplitter 
+			with: self failuresWidget
+			with: self errorsWidget)
 ! !
 
 !HLSUnit methodsFor: 'keybindings'!
@@ -249,16 +295,15 @@ registerBindingsOn: aBindingGroup
 !HLSUnit methodsFor: 'rendering'!
 
 renderContentOn: html
+	| resultSection |
 	html with: (HLContainer with:  (
 		HLVerticalSplitter 
 			with: (HLVerticalSplitter
 				with: self packagesListWidget 
         		with: self classesListWidget)
-			with: (HLHorizontalSplitter 
-				with: self resultWidget
-				with: (HLHorizontalSplitter 
-					with: self failuresWidget
-					with: self errorsWidget)))).
+			with: (resultSection := self resultSection))).
+	
+	[resultSection resize: 0] valueWithTimeout: 100.
 	
 	self packagesListWidget focus
 ! !
@@ -317,6 +362,10 @@ canBeOpenAsTab
 HLModel subclass: #HLSUnitModel
 	instanceVariableNames: 'selectedPackages selectedClasses testResult currentSuite'
 	package: 'Helios-SUnit'!
+!HLSUnitModel commentStamp!
+I am the model for running unit tests in Helios.
+
+I provide the ability to select set of tests to run per package, and a detailed result log with passed tests, failed tests and errors.!
 
 !HLSUnitModel methodsFor: 'accessing'!
 
@@ -325,7 +374,7 @@ currentSuite
 !
 
 selectedClasses
-	^ (self privateSelectedClasses) select: [:each |
+	^ (self unfilteredSelectedClasses) select: [:each |
 		self selectedPackages includes: each package]
 !
 
@@ -366,6 +415,20 @@ testResult
 
 !HLSUnitModel methodsFor: 'actions'!
 
+invertSelectedClasses
+	self testClasses do: [:each | 
+		(self unfilteredSelectedClasses includes: each)
+			ifTrue: [ self unselectClass: each ]
+			ifFalse: [ self selectClass: each ]].
+!
+
+invertSelectedPackages
+	self testPackages do: [:each | 
+		(self selectedPackages includes: each)
+			ifTrue: [ self unselectPackage: each ]
+			ifFalse: [ self selectPackage: each ]].
+!
+
 runTests
 	| worker |
 	worker := TestSuiteRunner on: self testCases.
@@ -375,12 +438,16 @@ runTests
 	worker run
 !
 
+selectAllClasses
+	self testClasses do: [:each | self selectClass: each].
+!
+
 selectAllPackages
-	self testPackages do: [:each | self selectPackage: each]
+	self testPackages do: [:each | self selectPackage: each].
 !
 
 selectClass: aClass
-	self privateSelectedClasses add: aClass.
+	self unfilteredSelectedClasses add: aClass.
 	self announcer announce: (HLClassSelected on: aClass).
 !
 
@@ -399,7 +466,7 @@ subscribeToTestSuite: aTestSuiteRunner
 !
 
 unselectClass: aClass
-	self privateSelectedClasses remove: aClass ifAbsent: [^self].
+	self unfilteredSelectedClasses remove: aClass ifAbsent: [^self].
 	self announcer announce: (HLClassUnselected on: aClass).
 !
 
@@ -410,7 +477,7 @@ unselectPackage: aPackage
 
 !HLSUnitModel methodsFor: 'private'!
 
-privateSelectedClasses
+unfilteredSelectedClasses
 	^ (selectedClasses ifNil: [ selectedClasses := Set new ])
 ! !
 
@@ -424,6 +491,8 @@ onResultAnnouncement: announcement
 HLToolListWidget subclass: #HLSUnitResultListWidget
 	instanceVariableNames: ''
 	package: 'Helios-SUnit'!
+!HLSUnitResultListWidget commentStamp!
+I group the lists that display test results!
 
 !HLSUnitResultListWidget methodsFor: 'actions'!
 
@@ -459,6 +528,8 @@ reselectItem: anObject
 HLSUnitResultListWidget subclass: #HLSUnitErrorsListWidget
 	instanceVariableNames: ''
 	package: 'Helios-SUnit'!
+!HLSUnitErrorsListWidget commentStamp!
+I display a list of tests that have errors!
 
 !HLSUnitErrorsListWidget methodsFor: 'accessing'!
 
@@ -473,22 +544,29 @@ label
 HLSUnitResultListWidget subclass: #HLSUnitFailuresListWidget
 	instanceVariableNames: ''
 	package: 'Helios-SUnit'!
+!HLSUnitFailuresListWidget commentStamp!
+I display a list of tests that have failures!
 
 !HLSUnitFailuresListWidget methodsFor: 'accessing'!
 
-label
-	^'Failures'
-! !
-
-!HLSUnitFailuresListWidget methodsFor: 'as yet unclassified'!
-
 items
 	^self model testResult failures
+!
+
+label
+	^'Failures'
 ! !
 
 HLWidget subclass: #HLSUnitResultStatus
 	instanceVariableNames: 'model'
 	package: 'Helios-SUnit'!
+!HLSUnitResultStatus commentStamp!
+I display the status of the previous test run
+
+1. How many tests where run.
+* How many tests passed.
+* How many tests failed.
+* How many tests resulted in an error.!
 
 !HLSUnitResultStatus methodsFor: 'accessing'!
 
@@ -513,7 +591,7 @@ statusInfo
 	^ self printTotal, self printPasses, self printErrors, self printFailures
 ! !
 
-!HLSUnitResultStatus methodsFor: 'initialization'!
+!HLSUnitResultStatus methodsFor: 'actions'!
 
 observeModel
 	self model announcer 
@@ -557,6 +635,13 @@ renderContentOn: html
 HLWidget subclass: #HLSUnitResults
 	instanceVariableNames: 'model progressBarWidget resultStatusWidget'
 	package: 'Helios-SUnit'!
+!HLSUnitResults commentStamp!
+I am the widget that displays the test results for a previous test run in Helios.
+
+I display.
+
+1. The status of the tests.
+* Progress of the currently running test suite.!
 
 !HLSUnitResults methodsFor: 'accessing'!
 

+ 9 - 0
support/helios/helios.css

@@ -305,6 +305,15 @@ body[id="helios"] .welcome button {
   height: auto;
   width: 150px;
 }
+body[id="helios"] .sunit.status.success {
+  background: #43d443;
+}
+body[id="helios"] .sunit.status.failure {
+  background: #ecd443;
+}
+body[id="helios"] .sunit.status.error {
+  background: #e56f3b;
+}
 body[id="helios"] .tool_container {
   position: absolute;
   top: 23px;

+ 16 - 0
support/helios/helios.less

@@ -360,6 +360,22 @@ body[id="helios"] {
 			width: 150px;
 		}
 	}
+	
+	.sunit.status {
+		&.success {
+			background: #43d443;
+		}
+
+
+		&.failure {
+			background: #ecd443;
+		}
+
+
+		&.error {
+			background: #e56f3b;
+		}
+	}
 
 	.tool_container {
 		position: absolute;