Refactored remembering of TestCaseOutcomes. working_v5_0
authorJan Vrany <jan.vrany@fit.cvut.cz>
Mon, 14 Jul 2014 21:58:21 +0100
branchworking_v5_0
changeset 614 3003097506c9
parent 613 5a546630cfcf
child 615 f1b888de7817
Refactored remembering of TestCaseOutcomes. TestCaseOutcomes are no longer remembered in class instance var of the TestCase but rather in one global dictionary on TestCaseOutcome class. The top-level weak dictionary uses test method as a key and second-level dictionary as value. This ensures that when a test method is changed, sooner or later (now obsolete) remebered outcomes are reclamed by the GC. The second-level dictionary uses test case class as a key and outcome as value. This is used to keep outcomes for inherited test cases. This dictionary is also weak, ensuring that when the class is unloaded or changed, outcomes are reclamed. To reduce a number of weak objects a special TestCaseOutcomeWeakIdentityDictionary is used. It optimizes the most common case when there are no inherited testcases.
Make.proto
Make.spec
ResumableTestFailureTestCase.st
SUnitNameResolver.st
TestCase.st
TestCaseOutcome.st
TestCaseOutcomeWeakIdentityDictionary.st
abbrev.stc
bc.mak
extensions.st
libInit.cc
stx_goodies_sunit.st
sunit.rc
--- a/Make.proto	Wed Jul 09 23:00:04 2014 +0100
+++ b/Make.proto	Mon Jul 14 21:58:21 2014 +0100
@@ -34,7 +34,7 @@
 # add the path(es) here:,
 # ********** OPTIONAL: MODIFY the next lines ***
 # LOCALINCLUDES=-Ifoo -Ibar
-LOCALINCLUDES= -I$(INCLUDE_TOP)/stx/libbasic -I$(INCLUDE_TOP)/stx/libbasic2 -I$(INCLUDE_TOP)/stx/libview -I$(INCLUDE_TOP)/stx/libview2
+LOCALINCLUDES= -I$(INCLUDE_TOP)/stx/libbasic -I$(INCLUDE_TOP)/stx/libbasic2 -I$(INCLUDE_TOP)/stx/libbasic3 -I$(INCLUDE_TOP)/stx/libview -I$(INCLUDE_TOP)/stx/libview2
 
 
 # if you need any additional defines for embedded C code,
@@ -125,6 +125,7 @@
 prereq:
 	cd ../../libbasic && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)"
 	cd ../../libbasic2 && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)"
+	cd ../../libbasic3 && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)"
 	cd ../../libview && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)"
 	cd ../../libview2 && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)"
 
@@ -151,6 +152,7 @@
 $(OUTDIR)SUnitNameResolver.$(O) SUnitNameResolver.$(H): SUnitNameResolver.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)TestAsserter.$(O) TestAsserter.$(H): TestAsserter.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)TestCaseOutcome.$(O) TestCaseOutcome.$(H): TestCaseOutcome.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
+$(OUTDIR)TestCaseOutcomeWeakIdentityDictionary.$(O) TestCaseOutcomeWeakIdentityDictionary.$(H): TestCaseOutcomeWeakIdentityDictionary.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)TestCoverageReporter.$(O) TestCoverageReporter.$(H): TestCoverageReporter.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)TestFailure.$(O) TestFailure.$(H): TestFailure.st $(INCLUDE_TOP)/stx/libbasic/Exception.$(H) $(INCLUDE_TOP)/stx/libbasic/GenericException.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)TestResult.$(O) TestResult.$(H): TestResult.st $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
@@ -164,9 +166,8 @@
 $(OUTDIR)TestResource.$(O) TestResource.$(H): TestResource.st $(INCLUDE_TOP)/stx/goodies/sunit/TestAsserter.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)TestResultStX.$(O) TestResultStX.$(H): TestResultStX.st $(INCLUDE_TOP)/stx/goodies/sunit/TestResult.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)TestSkipped.$(O) TestSkipped.$(H): TestSkipped.st $(INCLUDE_TOP)/stx/goodies/sunit/TestFailure.$(H) $(INCLUDE_TOP)/stx/libbasic/Exception.$(H) $(INCLUDE_TOP)/stx/libbasic/GenericException.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
-$(OUTDIR)TestCaseWithArguments.$(O) TestCaseWithArguments.$(H): TestCaseWithArguments.st $(INCLUDE_TOP)/stx/goodies/sunit/TestAsserter.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestCase.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
 $(OUTDIR)TestResultForRunWithDebug.$(O) TestResultForRunWithDebug.$(H): TestResultForRunWithDebug.st $(INCLUDE_TOP)/stx/goodies/sunit/TestResult.$(H) $(INCLUDE_TOP)/stx/goodies/sunit/TestResultStX.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR)
-$(OUTDIR)extensions.$(O): extensions.st $(INCLUDE_TOP)/stx/libbasic/ArrayedCollection.$(H) $(INCLUDE_TOP)/stx/libbasic/Behavior.$(H) $(INCLUDE_TOP)/stx/libbasic/Block.$(H) $(INCLUDE_TOP)/stx/libbasic/CharacterArray.$(H) $(INCLUDE_TOP)/stx/libbasic/Class.$(H) $(INCLUDE_TOP)/stx/libbasic/ClassDescription.$(H) $(INCLUDE_TOP)/stx/libbasic/Collection.$(H) $(INCLUDE_TOP)/stx/libbasic/CompiledCode.$(H) $(INCLUDE_TOP)/stx/libbasic/ExecutableFunction.$(H) $(INCLUDE_TOP)/stx/libbasic/GenericException.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(INCLUDE_TOP)/stx/libbasic/SequenceableCollection.$(H) $(INCLUDE_TOP)/stx/libbasic/String.$(H) $(INCLUDE_TOP)/stx/libbasic/Symbol.$(H) $(INCLUDE_TOP)/stx/libbasic/UninterpretedBytes.$(H) $(STCHDR)
+$(OUTDIR)extensions.$(O): extensions.st $(INCLUDE_TOP)/stx/libbasic/ArrayedCollection.$(H) $(INCLUDE_TOP)/stx/libbasic/Behavior.$(H) $(INCLUDE_TOP)/stx/libbasic/Block.$(H) $(INCLUDE_TOP)/stx/libbasic/CharacterArray.$(H) $(INCLUDE_TOP)/stx/libbasic/Class.$(H) $(INCLUDE_TOP)/stx/libbasic/ClassDescription.$(H) $(INCLUDE_TOP)/stx/libbasic/Collection.$(H) $(INCLUDE_TOP)/stx/libbasic/CompiledCode.$(H) $(INCLUDE_TOP)/stx/libbasic/ExecutableFunction.$(H) $(INCLUDE_TOP)/stx/libbasic/GenericException.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(INCLUDE_TOP)/stx/libbasic/SequenceableCollection.$(H) $(INCLUDE_TOP)/stx/libbasic/String.$(H) $(INCLUDE_TOP)/stx/libbasic/Symbol.$(H) $(INCLUDE_TOP)/stx/libbasic/UninterpretedBytes.$(H) $(INCLUDE_TOP)/stx/libbasic3/Change.$(H) $(INCLUDE_TOP)/stx/libbasic3/ClassChange.$(H) $(INCLUDE_TOP)/stx/libbasic3/MethodChange.$(H) $(STCHDR)
 
 # ENDMAKEDEPEND --- do not remove this line
 
--- a/Make.spec	Wed Jul 09 23:00:04 2014 +0100
+++ b/Make.spec	Mon Jul 14 21:58:21 2014 +0100
@@ -55,6 +55,7 @@
 	SUnitNameResolver \
 	TestAsserter \
 	TestCaseOutcome \
+	TestCaseOutcomeWeakIdentityDictionary \
 	TestCoverageReporter \
 	TestFailure \
 	TestResult \
@@ -68,7 +69,6 @@
 	TestResource \
 	TestResultStX \
 	TestSkipped \
-	TestCaseWithArguments \
 	TestResultForRunWithDebug \
 
 
@@ -80,6 +80,7 @@
     $(OUTDIR_SLASH)SUnitNameResolver.$(O) \
     $(OUTDIR_SLASH)TestAsserter.$(O) \
     $(OUTDIR_SLASH)TestCaseOutcome.$(O) \
+    $(OUTDIR_SLASH)TestCaseOutcomeWeakIdentityDictionary.$(O) \
     $(OUTDIR_SLASH)TestCoverageReporter.$(O) \
     $(OUTDIR_SLASH)TestFailure.$(O) \
     $(OUTDIR_SLASH)TestResult.$(O) \
@@ -93,7 +94,6 @@
     $(OUTDIR_SLASH)TestResource.$(O) \
     $(OUTDIR_SLASH)TestResultStX.$(O) \
     $(OUTDIR_SLASH)TestSkipped.$(O) \
-    $(OUTDIR_SLASH)TestCaseWithArguments.$(O) \
     $(OUTDIR_SLASH)TestResultForRunWithDebug.$(O) \
     $(OUTDIR_SLASH)extensions.$(O) \
 
--- a/ResumableTestFailureTestCase.st	Wed Jul 09 23:00:04 2014 +0100
+++ b/ResumableTestFailureTestCase.st	Mon Jul 14 21:58:21 2014 +0100
@@ -74,6 +74,11 @@
 
 !ResumableTestFailureTestCase class methodsFor:'documentation'!
 
+version_HG
+
+    ^ '$Changeset: <not expanded> $'
+!
+
 version_SVN
     ^ '§Id: ResumableTestFailureTestCase.st 214 2011-03-14 12:22:21Z vranyj1 §'
 ! !
--- a/SUnitNameResolver.st	Wed Jul 09 23:00:04 2014 +0100
+++ b/SUnitNameResolver.st	Mon Jul 14 21:58:21 2014 +0100
@@ -32,6 +32,28 @@
 
 notificationObject
 	^Notification
+!
+
+weakIdentityDictionaryClass
+    "Return an EphemeronDictionary (if available) or Weak(Identity)Dictionary class"
+    
+    #(
+     #EphemeronDictionary       "VW"
+     #WeakIdentityDictionary    "St/X"
+     #WeakDictionary            "VW"
+     )
+            do:[:name | 
+                | class |
+
+                class := self classNamed:name.
+                class notNil ifTrue:[
+                    ^ class.
+                ].
+            ].
+    self error:'No weak-like dictionary class found!!'.
+
+    "Created: / 14-07-2014 / 09:46:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (format): / 14-07-2014 / 21:01:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !SUnitNameResolver class methodsFor:'documentation'!
@@ -43,3 +65,4 @@
 version_SVN
     ^ '§Id: SUnitNameResolver.st 204 2010-09-11 15:21:51Z vranyj1 §'
 ! !
+
--- a/TestCase.st	Wed Jul 09 23:00:04 2014 +0100
+++ b/TestCase.st	Mon Jul 14 21:58:21 2014 +0100
@@ -161,46 +161,22 @@
 !
 
 rememberOutcome: thisOutcome
-    |thisTestCase someOtherOutcome someOtherTestCase|
-
-    thisTestCase := thisOutcome testCase.
-
-    lastOutcomes isNil ifTrue:[
-        lastOutcomes := OrderedCollection new.
-    ].
+    <resource: #obsolete>
 
-    "Not a nice code, but portable (what: doWithIndex: is not portable?)"
-    1 to: lastOutcomes size do:[:i|
-        someOtherOutcome := lastOutcomes at: i.
-        someOtherTestCase := someOtherOutcome testCase.
-        "/ compare by classes name - in case it got redefined
-        (someOtherTestCase selector == thisTestCase selector
-        and: [someOtherTestCase class name = thisTestCase class name]) ifTrue:[
-            "remember; for the timestamp and other info"
-            lastOutcomes at: i put: thisOutcome.
-            someOtherOutcome result ~= thisOutcome result ifTrue:[
-                "but only send out change notification to browser if state has changed"
-                self lastTestRunResultChanged: thisOutcome selector. 
-            ].
-            ^self.                    
-        ].
-    ].
-    lastOutcomes add: thisOutcome.
-    self lastTestRunResultChanged: thisOutcome selector.
-    ^self
+    TestCaseOutcome rememberOutcome: thisOutcome
 
     "Created: / 20-08-2011 / 12:43:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 04-06-2012 / 16:19:07 / cg"
+    "Modified: / 13-07-2014 / 23:28:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (format): / 14-07-2014 / 21:36:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 rememberedOutcomeFor: selector
-
-    lastOutcomes isNil ifTrue:[^nil].
-    ^lastOutcomes 
-        detect: [:outcome| outcome testCase selector == selector]
-        ifNone:[nil].
+    ^ TestCaseOutcome rememberedOutcomeFor: selector in: self.
 
     "Created: / 20-08-2011 / 14:27:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 13-07-2014 / 23:56:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified (comment): / 14-07-2014 / 09:43:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 resources
@@ -222,16 +198,16 @@
 testSelector:selector result: result
     "return true, if the last run of this test had the outcome result"
 
-    lastOutcomes isNil ifTrue:[^false].
-    ^ lastOutcomes 
-        contains:[:any|
-            any testCase class name = self name
-            and:[any testCase selector == selector
-            and:[any result == result]]
-        ]
+    "ST/X Specific"
+
+    | outcome |
+
+    outcome := self rememberedOutcomeFor: selector.
+    ^ outcome notNil and:[ outcome result == result ]
 
     "Created: / 20-08-2011 / 16:15:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
     "Modified: / 04-06-2012 / 16:12:17 / cg"
+    "Modified: / 14-07-2014 / 09:44:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 testSelectorError:selector
--- a/TestCaseOutcome.st	Wed Jul 09 23:00:04 2014 +0100
+++ b/TestCaseOutcome.st	Mon Jul 14 21:58:21 2014 +0100
@@ -2,7 +2,7 @@
 
 Object subclass:#TestCaseOutcome
 	instanceVariableNames:'testCase result properties'
-	classVariableNames:''
+	classVariableNames:'RemeberedOutcomes'
 	poolDictionaries:''
 	category:'SUnit-Base'
 !
@@ -18,6 +18,19 @@
 "
 ! !
 
+!TestCaseOutcome class methodsFor:'initialization'!
+
+initialize
+    "Invoked at system start or when the class is dynamically loaded."
+
+    "/ please change as required (and remove this comment)
+
+
+    RemeberedOutcomes := SUnitNameResolver weakIdentityDictionaryClass new
+
+    "Modified: / 14-07-2014 / 09:59:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !TestCaseOutcome class methodsFor:'instance creation'!
 
 forCase: aTestCase
@@ -27,6 +40,50 @@
     "Created: / 16-08-2011 / 15:24:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
+!TestCaseOutcome class methodsFor:'notifying'!
+
+notifyOutcomeChanged: currentOutcome ifDifferentFrom: previousOutcome
+    "Notifies whoever is interested that the current outcome for a testcase has
+     changed, but only if result of the current (pass, fail or error) is actually 
+     different the result of previous outcome"   
+
+    (previousOutcome isNil or:[ previousOutcome result ~~ currentOutcome result ]) ifTrue:[ 
+        currentOutcome testCase class lastTestRunResultChanged:currentOutcome testCase selector         
+    ].
+
+    "Created: / 14-07-2014 / 21:07:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!TestCaseOutcome class methodsFor:'remembering'!
+
+rememberOutcome: current
+    | method outcomes previous |    
+
+    method := current method.                                    
+    outcomes := RemeberedOutcomes at: method ifAbsent:[ RemeberedOutcomes at: method put: TestCaseOutcomeWeakIdentityDictionary new ]. 
+    previous := outcomes at: current testCase class ifAbsent:[ nil ].
+    outcomes at: current testCase class put: current.
+    self notifyOutcomeChanged: current ifDifferentFrom: previous.
+
+    "Created: / 13-07-2014 / 23:28:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 14-07-2014 / 21:16:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+rememberedOutcomeFor: selector in: class
+    | implementor method outcomes |
+
+    implementor := class.
+    [implementor notNil and:[implementor includesSelector: selector]]
+            whileFalse: [implementor := implementor superclass].
+    implementor isNil ifTrue:[ ^ nil ].
+    method := implementor compiledMethodAt: selector.                   
+    outcomes := RemeberedOutcomes at: method ifAbsent:[ ^ nil ].
+    ^ outcomes at: class ifAbsent: [ nil ]
+
+    "Created: / 13-07-2014 / 23:56:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 14-07-2014 / 21:15:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !TestCaseOutcome methodsFor:'accessing'!
 
 collectedOutput
@@ -91,6 +148,18 @@
     "Modified (format): / 18-08-2011 / 21:02:28 / cg"
 !
 
+method
+    "Return the CompiledMethod corresponding to this test case in as dialect-neutral a way as possible.  We code on the assumption there must be one. If there isn't and we work up to nil superclass then fail, not bothering with implementor isNil ifTrue: [^nil] as we assume the caller would immediately fail in that case."
+
+    | implementor |
+    implementor := testCase class.
+    [implementor includesSelector: testCase selector]
+            whileFalse: [implementor := implementor superclass].
+    ^ implementor compiledMethodAt: testCase selector
+
+    "Created: / 13-07-2014 / 23:31:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 propertyAt: aSymbol
 
     ^ self propertyAt: aSymbol ifAbsent: [nil]
@@ -195,9 +264,10 @@
 
 remember
 
-    ^testCase class rememberOutcome: self.
+    ^TestCaseOutcome rememberOutcome: self.
 
     "Created: / 20-08-2011 / 12:45:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 14-07-2014 / 21:35:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
 !TestCaseOutcome class methodsFor:'documentation'!
@@ -206,3 +276,5 @@
     ^ '$Header: /cvs/stx/stx/goodies/sunit/TestCaseOutcome.st,v 1.6 2014-04-16 22:06:04 cg Exp $'
 ! !
 
+
+TestCaseOutcome initialize!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestCaseOutcomeWeakIdentityDictionary.st	Mon Jul 14 21:58:21 2014 +0100
@@ -0,0 +1,97 @@
+"{ Package: 'stx:goodies/sunit' }"
+
+Object subclass:#TestCaseOutcomeWeakIdentityDictionary
+	instanceVariableNames:'contents'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'SUnit-Private'
+!
+
+!TestCaseOutcomeWeakIdentityDictionary class methodsFor:'documentation'!
+
+documentation
+"
+    TestCaseOutcomeWeakIdentityDictionary is a a weak dictionary-like object to store
+    key-value pairs (where value is either TestCaseOutcome or another
+    Dictionary pointing to TestCaseOutcome). 
+
+    The main difference is that TestCaseOutcomeWeakIdentityDictionary optimizes the case
+    it there's only one key-value pair. In this case, key and value is held
+    strongly.
+
+    This us used to store remembered outcomes while trying to reduce a number
+    of weak objects and thus saving some GC work.
+
+    [author:]
+        Jan Vrany <jan.vrany@fit.cvut.cz>
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!TestCaseOutcomeWeakIdentityDictionary methodsFor:'accessing'!
+
+at: key
+    ^ self at:key ifAbsent:[self errorKeyNotFound:key]
+
+    "Created: / 14-07-2014 / 20:55:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+at: key ifAbsent: block
+    contents isNil ifTrue:[ ^ block value ].
+    contents class == Association ifTrue:[ 
+        contents key == key ifTrue:[ 
+            ^ contents value.
+        ].
+        ^ block value
+    ].
+    ^ contents at: key ifAbsent: block
+
+    "Created: / 14-07-2014 / 20:55:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+at: key ifAbsentPut: block
+    ^ self at: key ifAbsent:[ self at: key put: block value ].
+
+    "Created: / 14-07-2014 / 20:55:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+at: key put: value
+    | newContents |
+
+    contents isNil ifTrue:[ 
+        contents := Association key: key value: value.
+        ^ value.
+    ].
+
+    contents class == Association ifTrue:[ 
+        contents key == key ifTrue:[ 
+            contents value: value.
+            ^ value
+        ] ifFalse:[
+            newContents := self dictionaryClass new.
+            newContents at: contents key put: contents value.
+            contents := newContents.
+        ]
+    ].
+    contents at: key put: value.
+    ^ value
+
+    "Created: / 14-07-2014 / 20:55:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!TestCaseOutcomeWeakIdentityDictionary methodsFor:'private'!
+
+dictionaryClass
+    "raise an error: this method should be implemented (TODO)"
+
+    ^ self shouldImplement
+
+    "Created: / 14-07-2014 / 21:03:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
--- a/abbrev.stc	Wed Jul 09 23:00:04 2014 +0100
+++ b/abbrev.stc	Mon Jul 14 21:58:21 2014 +0100
@@ -1,10 +1,13 @@
 # automagically generated by the project definition
 # this file is needed for stc to be able to compile modules independently.
 # it provides information about a classes filename, category and especially namespace.
-ExampleTestResource ExampleTestResource stx:goodies/sunit 'SUnit-Tests' 1
+MetricsReporter MetricsReporter stx:goodies/sunit 'SUnit-Smalltalk/X-Report' 0
 SUnitDelay SUnitDelay stx:goodies/sunit 'SUnit-Preload' 0
 SUnitNameResolver SUnitNameResolver stx:goodies/sunit 'SUnit-Preload' 0
 TestAsserter TestAsserter stx:goodies/sunit 'SUnit-Base' 0
+TestCaseOutcome TestCaseOutcome stx:goodies/sunit 'SUnit-Base' 0
+TestCaseOutcomeWeakIdentityDictionary TestCaseOutcomeWeakIdentityDictionary stx:goodies/sunit 'SUnit-Private' 0
+TestCoverageReporter TestCoverageReporter stx:goodies/sunit 'SUnit-Smalltalk/X-Report' 0
 TestFailure TestFailure stx:goodies/sunit 'SUnit-Preload' 1
 TestResult TestResult stx:goodies/sunit 'SUnit-Base' 0
 TestResultReporter TestResultReporter stx:goodies/sunit 'SUnit-Smalltalk/X-Report' 0
@@ -14,13 +17,18 @@
 stx_goodies_sunit stx_goodies_sunit stx:goodies/sunit '* Projects & Packages *' 3
 ResumableTestFailure ResumableTestFailure stx:goodies/sunit 'SUnit-Preload' 1
 TestCase TestCase stx:goodies/sunit 'SUnit-Base' 1
-TestCaseWithArguments TestCaseWithArguments stx:goodies/sunit 'SUnit-Base' 1
 TestResource TestResource stx:goodies/sunit 'SUnit-Base' 1
+TestResultStX TestResultStX stx:goodies/sunit 'SUnit-Smalltalk/X' 0
+TestSkipped TestSkipped stx:goodies/sunit 'SUnit-Preload' 1
 ExampleSetTest ExampleSetTest stx:goodies/sunit 'SUnit-Tests' 1
+ExampleTestResource ExampleTestResource stx:goodies/sunit 'SUnit-Tests' 1
 ResumableTestFailureTestCase ResumableTestFailureTestCase stx:goodies/sunit 'SUnit-Tests' 1
 SUnitTest SUnitTest stx:goodies/sunit 'SUnit-Tests' 1
+SUnitTests2 SUnitTests2 stx:goodies/sunit 'SUnit-Smalltalk/X-Tests' 1
 SimpleTestResource SimpleTestResource stx:goodies/sunit 'SUnit-Tests' 2
 SimpleTestResourceTestCase SimpleTestResourceTestCase stx:goodies/sunit 'SUnit-Tests' 1
+TestCaseWithArguments TestCaseWithArguments stx:goodies/sunit 'SUnit-Base' 1
+TestResultForRunWithDebug TestResultForRunWithDebug stx:goodies/sunit 'SUnit-Smalltalk/X' 0
 FailingTestResourceTestCase FailingTestResourceTestCase stx:goodies/sunit 'SUnit-Tests' 1
 ManyTestResourceTestCase ManyTestResourceTestCase stx:goodies/sunit 'SUnit-Tests' 1
 SimpleTestResourceA SimpleTestResourceA stx:goodies/sunit 'SUnit-Tests' 2
@@ -30,14 +38,7 @@
 SimpleTestResourceB1 SimpleTestResourceB1 stx:goodies/sunit 'SUnit-Tests' 2
 SimpleTestResourceCircular SimpleTestResourceCircular stx:goodies/sunit 'SUnit-Tests' 2
 SimpleTestResourceCircular1 SimpleTestResourceCircular1 stx:goodies/sunit 'SUnit-Tests' 2
+TestSuitesHierarchyScriptTest TestSuitesHierarchyScriptTest stx:goodies/sunit 'SUnit-Tests' 1
+TestSuitesScriptTest TestSuitesScriptTest stx:goodies/sunit 'SUnit-Tests' 1
 CircularTestResourceTestCase CircularTestResourceTestCase stx:goodies/sunit 'SUnit-Tests' 1
-TestCaseOutcome TestCaseOutcome stx:goodies/sunit 'SUnit-Base' 0
-TestResultStX TestResultStX stx:goodies/sunit 'SUnit-Smalltalk/X' 0
-TestResultForRunWithDebug TestResultForRunWithDebug stx:goodies/sunit 'SUnit-Smalltalk/X' 0
-SUnitTests2 SUnitTests2 stx:goodies/sunit 'SUnit-Smalltalk/X-Tests' 1
-TestCoverageReporter TestCoverageReporter stx:goodies/sunit 'SUnit-Smalltalk/X-Report' 0
-MetricsReporter MetricsReporter stx:goodies/sunit 'SUnit-Smalltalk/X-Report' 0
-TestSkipped TestSkipped stx:goodies/sunit 'SUnit-Preload' 1
-TestSuitesScriptTest TestSuitesScriptTest stx:goodies/sunit 'SUnit-Tests' 1
-TestSuitesHierarchyScriptTest TestSuitesHierarchyScriptTest stx:goodies/sunit 'SUnit-Tests' 1
 TestSuitesCompoundScriptTest TestSuitesCompoundScriptTest stx:goodies/sunit 'SUnit-Tests' 1
--- a/bc.mak	Wed Jul 09 23:00:04 2014 +0100
+++ b/bc.mak	Mon Jul 14 21:58:21 2014 +0100
@@ -34,7 +34,7 @@
 
 
 
-LOCALINCLUDES= -I$(INCLUDE_TOP)\stx\libbasic -I$(INCLUDE_TOP)\stx\libbasic2 -I$(INCLUDE_TOP)\stx\libview -I$(INCLUDE_TOP)\stx\libview2
+LOCALINCLUDES= -I$(INCLUDE_TOP)\stx\libbasic -I$(INCLUDE_TOP)\stx\libbasic2 -I$(INCLUDE_TOP)\stx\libbasic3 -I$(INCLUDE_TOP)\stx\libview -I$(INCLUDE_TOP)\stx\libview2
 LOCALDEFINES=
 
 STCLOCALOPT=-package=$(PACKAGE) -I. $(LOCALINCLUDES) -headerDir=. $(STCLOCALOPTIMIZATIONS) $(STCWARNINGS) $(LOCALDEFINES)  -varPrefix=$(LIBNAME)
@@ -52,6 +52,7 @@
 prereq:
 	pushd ..\..\libbasic & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) "
 	pushd ..\..\libbasic2 & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) "
+	pushd ..\..\libbasic3 & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) "
 	pushd ..\..\libview & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) "
 	pushd ..\..\libview2 & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) "
 
@@ -75,6 +76,7 @@
 $(OUTDIR)SUnitNameResolver.$(O) SUnitNameResolver.$(H): SUnitNameResolver.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)TestAsserter.$(O) TestAsserter.$(H): TestAsserter.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)TestCaseOutcome.$(O) TestCaseOutcome.$(H): TestCaseOutcome.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
+$(OUTDIR)TestCaseOutcomeWeakIdentityDictionary.$(O) TestCaseOutcomeWeakIdentityDictionary.$(H): TestCaseOutcomeWeakIdentityDictionary.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)TestCoverageReporter.$(O) TestCoverageReporter.$(H): TestCoverageReporter.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)TestFailure.$(O) TestFailure.$(H): TestFailure.st $(INCLUDE_TOP)\stx\libbasic\Exception.$(H) $(INCLUDE_TOP)\stx\libbasic\GenericException.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)TestResult.$(O) TestResult.$(H): TestResult.st $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
@@ -88,9 +90,8 @@
 $(OUTDIR)TestResource.$(O) TestResource.$(H): TestResource.st $(INCLUDE_TOP)\stx\goodies\sunit\TestAsserter.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)TestResultStX.$(O) TestResultStX.$(H): TestResultStX.st $(INCLUDE_TOP)\stx\goodies\sunit\TestResult.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)TestSkipped.$(O) TestSkipped.$(H): TestSkipped.st $(INCLUDE_TOP)\stx\goodies\sunit\TestFailure.$(H) $(INCLUDE_TOP)\stx\libbasic\Exception.$(H) $(INCLUDE_TOP)\stx\libbasic\GenericException.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
-$(OUTDIR)TestCaseWithArguments.$(O) TestCaseWithArguments.$(H): TestCaseWithArguments.st $(INCLUDE_TOP)\stx\goodies\sunit\TestAsserter.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestCase.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
 $(OUTDIR)TestResultForRunWithDebug.$(O) TestResultForRunWithDebug.$(H): TestResultForRunWithDebug.st $(INCLUDE_TOP)\stx\goodies\sunit\TestResult.$(H) $(INCLUDE_TOP)\stx\goodies\sunit\TestResultStX.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR)
-$(OUTDIR)extensions.$(O): extensions.st $(INCLUDE_TOP)\stx\libbasic\ArrayedCollection.$(H) $(INCLUDE_TOP)\stx\libbasic\Behavior.$(H) $(INCLUDE_TOP)\stx\libbasic\Block.$(H) $(INCLUDE_TOP)\stx\libbasic\CharacterArray.$(H) $(INCLUDE_TOP)\stx\libbasic\Class.$(H) $(INCLUDE_TOP)\stx\libbasic\ClassDescription.$(H) $(INCLUDE_TOP)\stx\libbasic\Collection.$(H) $(INCLUDE_TOP)\stx\libbasic\CompiledCode.$(H) $(INCLUDE_TOP)\stx\libbasic\ExecutableFunction.$(H) $(INCLUDE_TOP)\stx\libbasic\GenericException.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(INCLUDE_TOP)\stx\libbasic\SequenceableCollection.$(H) $(INCLUDE_TOP)\stx\libbasic\String.$(H) $(INCLUDE_TOP)\stx\libbasic\Symbol.$(H) $(INCLUDE_TOP)\stx\libbasic\UninterpretedBytes.$(H) $(STCHDR)
+$(OUTDIR)extensions.$(O): extensions.st $(INCLUDE_TOP)\stx\libbasic\ArrayedCollection.$(H) $(INCLUDE_TOP)\stx\libbasic\Behavior.$(H) $(INCLUDE_TOP)\stx\libbasic\Block.$(H) $(INCLUDE_TOP)\stx\libbasic\CharacterArray.$(H) $(INCLUDE_TOP)\stx\libbasic\Class.$(H) $(INCLUDE_TOP)\stx\libbasic\ClassDescription.$(H) $(INCLUDE_TOP)\stx\libbasic\Collection.$(H) $(INCLUDE_TOP)\stx\libbasic\CompiledCode.$(H) $(INCLUDE_TOP)\stx\libbasic\ExecutableFunction.$(H) $(INCLUDE_TOP)\stx\libbasic\GenericException.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(INCLUDE_TOP)\stx\libbasic\SequenceableCollection.$(H) $(INCLUDE_TOP)\stx\libbasic\String.$(H) $(INCLUDE_TOP)\stx\libbasic\Symbol.$(H) $(INCLUDE_TOP)\stx\libbasic\UninterpretedBytes.$(H) $(INCLUDE_TOP)\stx\libbasic3\Change.$(H) $(INCLUDE_TOP)\stx\libbasic3\ClassChange.$(H) $(INCLUDE_TOP)\stx\libbasic3\MethodChange.$(H) $(STCHDR)
 
 # ENDMAKEDEPEND --- do not remove this line
 
--- a/extensions.st	Wed Jul 09 23:00:04 2014 +0100
+++ b/extensions.st	Mon Jul 14 21:58:21 2014 +0100
@@ -57,6 +57,20 @@
     "Modified: / 05-12-2009 / 18:29:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 ! !
 
+!MethodChange methodsFor:'accessing'!
+
+changeMethod
+    |cls|
+
+    selector isNil ifTrue:[ ^ nil ].
+    cls := self changeClass.
+    cls isNil ifTrue:[^ nil].
+    ^ cls compiledMethodAt:selector asSymbol
+
+    "Created: / 07-02-1998 / 19:47:53 / cg"
+    "Modified: / 14-07-2014 / 09:43:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
 !Object methodsFor:'Camp Smalltalk'!
 
 sunitAddDependent: anObject
--- a/libInit.cc	Wed Jul 09 23:00:04 2014 +0100
+++ b/libInit.cc	Mon Jul 14 21:58:21 2014 +0100
@@ -32,6 +32,7 @@
 _SUnitNameResolver_Init(pass,__pRT__,snd);
 _TestAsserter_Init(pass,__pRT__,snd);
 _TestCaseOutcome_Init(pass,__pRT__,snd);
+_TestCaseOutcomeWeakIdentityDictionary_Init(pass,__pRT__,snd);
 _TestCoverageReporter_Init(pass,__pRT__,snd);
 _TestFailure_Init(pass,__pRT__,snd);
 _TestResult_Init(pass,__pRT__,snd);
@@ -45,7 +46,6 @@
 _TestResource_Init(pass,__pRT__,snd);
 _TestResultStX_Init(pass,__pRT__,snd);
 _TestSkipped_Init(pass,__pRT__,snd);
-_TestCaseWithArguments_Init(pass,__pRT__,snd);
 _TestResultForRunWithDebug_Init(pass,__pRT__,snd);
 
 _stx_137goodies_137sunit_extensions_Init(pass,__pRT__,snd);
--- a/stx_goodies_sunit.st	Wed Jul 09 23:00:04 2014 +0100
+++ b/stx_goodies_sunit.st	Mon Jul 14 21:58:21 2014 +0100
@@ -73,32 +73,40 @@
 !
 
 mandatoryPreRequisites
-    "list all required mandatory packages.
-     Packages are mandatory, if they contain superclasses of the package's classes
-     or classes which are extended by this package.
-     This list can be maintained manually or (better) generated and
-     updated by scanning the superclass hierarchies
-     (the browser has a menu function for that)
-     However, often too much is found, and you may want to explicitely
-     exclude individual packages in the #excludedFromPreRequisites method."
+    "list packages which are mandatory as a prerequisite.
+     This are packages containing superclasses of my classes and classes which
+     are extended by myself.
+     They are mandatory, because we need these packages as a prerequisite for loading and compiling.
+     This method is generated automatically,
+     by searching along the inheritance chain of all of my classes."
 
     ^ #(
-        #'stx:libbasic'    "String - extended "
-        #'stx:libview2'    "ApplicationModel - superclass of TestRunner "
+        #'stx:libbasic'    "ArrayedCollection - extended"
+        #'stx:libbasic3'    "Change - extended"
+        #'stx:libview2'    "ApplicationModel - superclass of TestRunner"
     )
 !
 
 referencedPreRequisites
-    "list all packages containing classes referenced by the packages's members.
-     This list can be maintained manually or (better) generated and
-     updated by looking for global variable accesses
-     (the browser has a menu function for that)
-     However, often too much is found, and you may want to explicitely
-     exclude individual packages in the #excludedFromPreRequisites method."
+    "list packages which are a prerequisite, because they contain
+     classes which are referenced by my classes.
+     We do not need these packages as a prerequisite for loading or compiling.
+     This method is generated automatically,
+     by searching all classes (and their packages) which are referenced by my classes."
 
     ^ #(
-        #'stx:libbasic2'    "SplittingWriteStream - referenced by TestResultStX>>performCase: "
-        #'stx:libview'    "Color - referenced by TestRunner>>displayNormalColorInProgress "
+        #'stx:libbasic2'    "LineNumberReadStream - referenced by TestResultStX>>printLineForContextForJavaCompatibleStackTrace:on:"
+        #'stx:libview'    "Color - referenced by TestRunner class>>colorForFailedTests"
+    )
+!
+
+subProjects
+    "list packages which are known as subprojects. 
+     The generated makefile will enter those and make there as well.
+     However: they are not forced to be loaded when a package is loaded; 
+     for those, redefine requiredPrerequisites."
+
+    ^ #(
     )
 ! !
 
@@ -112,10 +120,13 @@
 
     ^ #(
         "<className> or (<className> attributes...) in load order"
-        (ExampleTestResource autoload)
+        MetricsReporter
         SUnitDelay
         SUnitNameResolver
         TestAsserter
+        TestCaseOutcome
+        TestCaseOutcomeWeakIdentityDictionary
+        TestCoverageReporter
         TestFailure
         TestResult
         TestResultReporter
@@ -125,13 +136,18 @@
         #'stx_goodies_sunit'
         ResumableTestFailure
         TestCase
-        TestCaseWithArguments
         TestResource
+        TestResultStX
+        TestSkipped
         (ExampleSetTest autoload)
+        (ExampleTestResource autoload)
         (ResumableTestFailureTestCase autoload)
         (SUnitTest autoload)
+        (SUnitTests2 autoload)
         (SimpleTestResource autoload)
         (SimpleTestResourceTestCase autoload)
+        (TestCaseWithArguments autoload)
+        TestResultForRunWithDebug
         (FailingTestResourceTestCase autoload)
         (ManyTestResourceTestCase autoload)
         (SimpleTestResourceA autoload)
@@ -141,25 +157,16 @@
         (SimpleTestResourceB1 autoload)
         (SimpleTestResourceCircular autoload)
         (SimpleTestResourceCircular1 autoload)
+        (TestSuitesHierarchyScriptTest autoload)
+        (TestSuitesScriptTest autoload)
         (CircularTestResourceTestCase autoload)
-        TestCaseOutcome
-        TestResultStX
-        TestResultForRunWithDebug
-        (SUnitTests2 autoload)
-        TestCoverageReporter
-        MetricsReporter
-        TestSkipped
-        (TestSuitesScriptTest autoload)
-        (TestSuitesHierarchyScriptTest autoload)
-        (TestSuitesCompoundScriptTest autoload)      
+        (TestSuitesCompoundScriptTest autoload)
     )
-
-    "Modified: / 09-07-2014 / 21:32:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 extensionMethodNames
-    "lists the extension methods which are to be included in the project.
-     Entries are 2-element array literals, consisting of class-name and selector."
+    "list class/selector pairs of extensions.
+     A correponding method with real names must be present in my concrete subclasses"
 
     ^ #(
         Block sunitEnsure:
@@ -176,6 +183,7 @@
         'GenericException class' sunitSignalWith:
         Behavior sunitSelectors
         Class sunitName
+        MethodChange changeMethod
     )
 ! !
 
--- a/sunit.rc	Wed Jul 09 23:00:04 2014 +0100
+++ b/sunit.rc	Mon Jul 14 21:58:21 2014 +0100
@@ -25,7 +25,7 @@
       VALUE "LegalCopyright", "Copyright eXept Software AG 1998-2007\0"
       VALUE "ProductName", "Smalltalk/X\0"
       VALUE "ProductVersion", "6.2.4.0\0"
-      VALUE "ProductDate", "Wed, 09 Jul 2014 20:33:11 GMT\0"
+      VALUE "ProductDate", "Mon, 14 Jul 2014 20:40:23 GMT\0"
     END
 
   END